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
This commit is contained in:
Owen W. Taylor 2014-05-21 09:57:15 -04:00
parent 077606c057
commit 9c6e527d4b

View File

@ -36,6 +36,12 @@
#include "wayland/meta-wayland-surface.h" #include "wayland/meta-wayland-surface.h"
typedef enum {
INITIALLY_FROZEN,
DRAWING_FIRST_FRAME,
EMITTED_FIRST_FRAME
} FirstFrameState;
struct _MetaWindowActorPrivate struct _MetaWindowActorPrivate
{ {
MetaWindow *window; MetaWindow *window;
@ -104,6 +110,7 @@ struct _MetaWindowActorPrivate
guint no_shadow : 1; guint no_shadow : 1;
guint updates_frozen : 1; guint updates_frozen : 1;
guint first_frame_state : 2; /* FirstFrameState */
}; };
typedef struct _FrameData FrameData; typedef struct _FrameData FrameData;
@ -115,6 +122,14 @@ struct _FrameData
gint64 frame_drawn_time; gint64 frame_drawn_time;
}; };
enum
{
FIRST_FRAME,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
enum enum
{ {
PROP_META_WINDOW = 1, PROP_META_WINDOW = 1,
@ -181,6 +196,31 @@ meta_window_actor_class_init (MetaWindowActorClass *klass)
actor_class->paint = meta_window_actor_paint; actor_class->paint = meta_window_actor_paint;
actor_class->get_paint_volume = meta_window_actor_get_paint_volume; 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", pspec = g_param_spec_object ("meta-window",
"MetaWindow", "MetaWindow",
"The displayed MetaWindow", "The displayed MetaWindow",
@ -306,6 +346,9 @@ meta_window_actor_thaw (MetaWindowActor *self)
if (priv->freeze_count > 0) if (priv->freeze_count > 0)
return; return;
if (priv->first_frame_state == INITIALLY_FROZEN)
priv->first_frame_state = DRAWING_FIRST_FRAME;
if (priv->surface) if (priv->surface)
meta_surface_actor_set_frozen (priv->surface, FALSE); meta_surface_actor_set_frozen (priv->surface, FALSE);
@ -348,6 +391,9 @@ set_surface (MetaWindowActor *self,
* frozen as well... */ * frozen as well... */
meta_surface_actor_set_frozen (priv->surface, priv->freeze_count > 0); 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); meta_window_actor_update_shape (self);
} }
} }
@ -1328,6 +1374,11 @@ meta_window_actor_new (MetaWindow *window)
meta_window_actor_sync_updates_frozen (self); 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 /* 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. * 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); do_send_frame_drawn (self, priv->frames->data);
priv->needs_frame_drawn = FALSE; 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 static void