[mutter] Fix corner cases where _NET_WM_FRAME_DRAWN might be missed



commit 5876f2e3e5093b5acc25a675afc8b4f0271cf5c1
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Thu Feb 14 13:40:55 2013 -0500

    Fix corner cases where _NET_WM_FRAME_DRAWN might be missed
    
    The WM spec requires _NET_WM_FRAME_DRAWN to *always* be sent when
    there is an appropriate update to the sync counter value. We were
    potentially missing _NET_WM_FRAME_DRAWN when an application did a
    spontaneous update during an interactive resize and during effects.
    Refactor the code to always send _NET_WM_FRAME_DRAWN, even when
    a window is frozen.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=693833

 src/compositor/compositor.c                |   15 +++++++
 src/compositor/meta-window-actor-private.h |    2 +
 src/compositor/meta-window-actor.c         |   62 ++++++++++++++++------------
 src/core/window-private.h                  |    9 ----
 src/core/window.c                          |   14 ++++--
 src/meta/compositor.h                      |    3 +
 6 files changed, 66 insertions(+), 39 deletions(-)
---
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
index 91b0767..cf9e05b 100644
--- a/src/compositor/compositor.c
+++ b/src/compositor/compositor.c
@@ -764,6 +764,21 @@ meta_compositor_set_updates_frozen (MetaCompositor *compositor,
   meta_window_actor_set_updates_frozen (window_actor, updates_frozen);
 }
 
+void
+meta_compositor_queue_frame_drawn (MetaCompositor *compositor,
+                                   MetaWindow     *window,
+                                   gboolean        no_delay_frame)
+{
+  MetaWindowActor *window_actor;
+
+  DEBUG_TRACE ("meta_compositor_queue_frame_drawn\n");
+  window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
+  if (!window_actor)
+    return;
+
+  meta_window_actor_queue_frame_drawn (window_actor, no_delay_frame);
+}
+
 static gboolean
 is_grabbed_event (MetaDisplay *display,
                   XEvent      *event)
diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h
index 5938677..e2eec5c 100644
--- a/src/compositor/meta-window-actor-private.h
+++ b/src/compositor/meta-window-actor-private.h
@@ -51,6 +51,8 @@ void     meta_window_actor_mapped              (MetaWindowActor *self);
 void     meta_window_actor_unmapped            (MetaWindowActor *self);
 void     meta_window_actor_set_updates_frozen  (MetaWindowActor *self,
                                                 gboolean         updates_frozen);
+void     meta_window_actor_queue_frame_drawn   (MetaWindowActor *self,
+                                                gboolean         no_delay_frame);
 
 cairo_region_t *meta_window_actor_get_obscured_region (MetaWindowActor *self);
 
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index 9980fe6..013a8ec 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -107,6 +107,7 @@ struct _MetaWindowActorPrivate
 
   guint                    needs_damage_all       : 1;
   guint                    received_damage        : 1;
+  guint             repaint_scheduled      : 1;
 
   /* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN
    * client message using the most recent frame in ->frames */
@@ -932,6 +933,7 @@ meta_window_actor_damage_all (MetaWindowActor *self)
                                    cogl_texture_get_height (texture));
 
   priv->needs_damage_all = FALSE;
+  priv->repaint_scheduled = TRUE;
 }
 
 static void
@@ -961,17 +963,41 @@ meta_window_actor_thaw (MetaWindowActor *self)
    * don't know what real damage has happened. */
   if (self->priv->needs_damage_all)
     meta_window_actor_damage_all (self);
-  else if (self->priv->needs_frame_drawn != 0)
+}
+
+void
+meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
+                                     gboolean         no_delay_frame)
+{
+  MetaWindowActorPrivate *priv = self->priv;
+  FrameData *frame = g_slice_new0 (FrameData);
+
+  priv->needs_frame_drawn = TRUE;
+
+  frame->sync_request_serial = priv->window->sync_request_serial;
+
+  priv->frames = g_list_prepend (priv->frames, frame);
+
+  if (no_delay_frame)
+    {
+      ClutterActor *stage = clutter_actor_get_stage (CLUTTER_ACTOR (self));
+      clutter_stage_skip_sync_delay (CLUTTER_STAGE (stage));
+    }
+
+  if (!priv->repaint_scheduled)
     {
-      /* A frame was marked by the client without actually doing any damage;
-       * we need to make sure that the pre_paint/post_paint functions
-       * get called, enabling us to send a _NET_WM_FRAME_DRAWN. We do a
-       * 1-pixel redraw to get consistent timing with non-empty frames.
+      /* A frame was marked by the client without actually doing any
+       * damage, or while we had the window frozen (e.g. during an
+       * interactive resize.) We need to make sure that the
+       * pre_paint/post_paint functions get called, enabling us to
+       * send a _NET_WM_FRAME_DRAWN. We do a 1-pixel redraw to get
+       * consistent timing with non-empty frames.
        */
-      if (self->priv->mapped && !self->priv->needs_pixmap)
+      if (priv->mapped && !priv->needs_pixmap)
         {
           const cairo_rectangle_int_t clip = { 0, 0, 1, 1 };
-          clutter_actor_queue_redraw_with_clip (self->priv->actor, &clip);
+          clutter_actor_queue_redraw_with_clip (priv->actor, &clip);
+          priv->repaint_scheduled = TRUE;
         }
     }
 }
@@ -1949,6 +1975,7 @@ meta_window_actor_process_damage (MetaWindowActor    *self,
                                    event->area.y,
                                    event->area.width,
                                    event->area.height);
+  priv->repaint_scheduled = TRUE;
 }
 
 void
@@ -2350,25 +2377,6 @@ meta_window_actor_handle_updates (MetaWindowActor *self)
   check_needs_pixmap (self);
   check_needs_reshape (self);
   check_needs_shadow (self);
-
-  if (priv->window->needs_frame_drawn)
-    {
-      FrameData *frame = g_slice_new0 (FrameData);
-
-      priv->needs_frame_drawn = TRUE;
-
-      frame->sync_request_serial = priv->window->sync_request_serial;
-
-      priv->frames = g_list_prepend (priv->frames, frame);
-
-      priv->window->needs_frame_drawn = FALSE;
-
-      if (priv->window->no_delay_frame)
-        {
-          ClutterActor *stage = clutter_actor_get_stage (CLUTTER_ACTOR (self));
-          clutter_stage_skip_sync_delay (CLUTTER_STAGE (stage));
-        }
-    }
 }
 
 void
@@ -2396,6 +2404,8 @@ meta_window_actor_post_paint (MetaWindowActor *self)
 {
   MetaWindowActorPrivate *priv = self->priv;
 
+  priv->repaint_scheduled = FALSE;
+
   if (priv->needs_frame_drawn)
     {
       MetaScreen  *screen  = priv->screen;
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 676a6ee..04ee110 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -356,15 +356,6 @@ struct _MetaWindow
    * also handles application frames */
   guint extended_sync_request_counter : 1;
 
-  /* if TRUE, we still need to send a _NET_WM_FRAME_DRAWN message for the
-   * last update the sync request counter */
-  guint needs_frame_drawn : 1;
-
-  /* if TRUE, the frame that was just drawn was drawn without any delay
-   * on the client's part and thus is high-priority - if we add delay
-   * we might cause the client to miss it's target frame rate */
-  guint no_delay_frame : 1;
-
   /* Note: can be NULL */
   GSList *struts;
 
diff --git a/src/core/window.c b/src/core/window.c
index ea50d69..e7c42fe 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -9510,11 +9510,13 @@ void
 meta_window_update_sync_request_counter (MetaWindow *window,
                                          gint64      new_counter_value)
 {
-  if (window->extended_sync_request_counter &&
-      new_counter_value % 2 == 0)
+  gboolean needs_frame_drawn = FALSE;
+  gboolean no_delay_frame = FALSE;
+
+  if (window->extended_sync_request_counter && new_counter_value % 2 == 0)
     {
-      window->needs_frame_drawn = TRUE;
-      window->no_delay_frame = new_counter_value == window->sync_request_serial + 1;
+      needs_frame_drawn = TRUE;
+      no_delay_frame = new_counter_value == window->sync_request_serial + 1;
     }
 
   window->sync_request_serial = new_counter_value;
@@ -9547,6 +9549,10 @@ meta_window_update_sync_request_counter (MetaWindow *window,
                      window->display->grab_latest_motion_y,
                      TRUE);
     }
+
+  if (needs_frame_drawn)
+    meta_compositor_queue_frame_drawn (window->display->compositor, window,
+                                       no_delay_frame);
 }
 #endif /* HAVE_XSYNC */
 
diff --git a/src/meta/compositor.h b/src/meta/compositor.h
index e36f30b..d917caf 100644
--- a/src/meta/compositor.h
+++ b/src/meta/compositor.h
@@ -156,6 +156,9 @@ void meta_compositor_sync_window_geometry (MetaCompositor *compositor,
 void meta_compositor_set_updates_frozen   (MetaCompositor *compositor,
                                            MetaWindow     *window,
                                            gboolean        updates_frozen);
+void meta_compositor_queue_frame_drawn    (MetaCompositor *compositor,
+                                           MetaWindow     *window,
+                                           gboolean        no_delay_frame);
 
 void meta_compositor_sync_stack                (MetaCompositor *compositor,
                                                 MetaScreen     *screen,


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