From 9c6e527d4b7c80dda997aae35a7bdb00e9bd3aed Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Wed, 21 May 2014 09:57:15 -0400 Subject: [PATCH] Add ::first-frame signal to MetaWindowActor This signal is emitted the first time a frame of contents of the window is completed by the application and has been drawn on the screen. This is meant to be used for performance measurement of application startup. https://bugzilla.gnome.org/show_bug.cgi?id=732343 --- src/compositor/meta-window-actor.c | 57 ++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index b743127c5..363c98068 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -36,6 +36,12 @@ #include "wayland/meta-wayland-surface.h" +typedef enum { + INITIALLY_FROZEN, + DRAWING_FIRST_FRAME, + EMITTED_FIRST_FRAME +} FirstFrameState; + struct _MetaWindowActorPrivate { MetaWindow *window; @@ -104,6 +110,7 @@ struct _MetaWindowActorPrivate guint no_shadow : 1; guint updates_frozen : 1; + guint first_frame_state : 2; /* FirstFrameState */ }; typedef struct _FrameData FrameData; @@ -115,6 +122,14 @@ struct _FrameData gint64 frame_drawn_time; }; +enum +{ + FIRST_FRAME, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + enum { PROP_META_WINDOW = 1, @@ -181,6 +196,31 @@ meta_window_actor_class_init (MetaWindowActorClass *klass) actor_class->paint = meta_window_actor_paint; actor_class->get_paint_volume = meta_window_actor_get_paint_volume; + /** + * MetaWindowActor::first-frame: + * @actor: the #MetaWindowActor instance + * + * The ::first-frame signal will be emitted the first time a frame + * of window contents has been drawn by the application and Mutter + * has had the chance to drawn that frame to the screen. If the + * window starts off initially hidden, obscured, or on on a + * different workspace, the ::first-frame signal will be emitted + * even though the user doesn't see the contents. + * + * MetaDisplay::window-created is a good place to connect to this + * signal - at that point, the MetaWindowActor for the window + * exists, but the window has reliably not yet been drawn. + * Connecting to an existing window that has already been drawn to + * the screen is not useful. + */ + signals[FIRST_FRAME] = + g_signal_new ("first-frame", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); + pspec = g_param_spec_object ("meta-window", "MetaWindow", "The displayed MetaWindow", @@ -306,6 +346,9 @@ meta_window_actor_thaw (MetaWindowActor *self) if (priv->freeze_count > 0) return; + if (priv->first_frame_state == INITIALLY_FROZEN) + priv->first_frame_state = DRAWING_FIRST_FRAME; + if (priv->surface) meta_surface_actor_set_frozen (priv->surface, FALSE); @@ -348,6 +391,9 @@ set_surface (MetaWindowActor *self, * frozen as well... */ meta_surface_actor_set_frozen (priv->surface, priv->freeze_count > 0); + if (!is_frozen (self) && priv->first_frame_state == INITIALLY_FROZEN) + priv->first_frame_state = DRAWING_FIRST_FRAME; + meta_window_actor_update_shape (self); } } @@ -1328,6 +1374,11 @@ meta_window_actor_new (MetaWindow *window) meta_window_actor_sync_updates_frozen (self); + if (is_frozen (self)) + priv->first_frame_state = INITIALLY_FROZEN; + else + priv->first_frame_state = DRAWING_FIRST_FRAME; + /* If a window doesn't start off with updates frozen, we should * we should send a _NET_WM_FRAME_DRAWN immediately after the first drawn. */ @@ -1910,6 +1961,12 @@ meta_window_actor_post_paint (MetaWindowActor *self) do_send_frame_drawn (self, priv->frames->data); priv->needs_frame_drawn = FALSE; } + + if (priv->first_frame_state == DRAWING_FIRST_FRAME) + { + priv->first_frame_state = EMITTED_FIRST_FRAME; + g_signal_emit (self, signals[FIRST_FRAME], 0); + } } static void