[actor] Add ::queue-redraw signal

Bug 1454 - move queue_redraw virtualization to ClutterActor

The ClutterActor::queue-redraw signal allows parent containers to
track whether their children need a redraw.

Signed-off-by: Emmanuele Bassi <ebassi@linux.intel.com>
This commit is contained in:
Havoc Pennington 2009-02-17 12:22:02 -05:00 committed by Emmanuele Bassi
parent 5706105123
commit 961aac3fb3
4 changed files with 121 additions and 71 deletions

View File

@ -244,6 +244,8 @@ struct _ClutterActorPrivate
/* cached allocation is invalid (request has changed, probably) */ /* cached allocation is invalid (request has changed, probably) */
guint needs_allocation : 1; guint needs_allocation : 1;
guint queued_redraw : 1;
guint show_on_set_parent : 1; guint show_on_set_parent : 1;
guint has_clip : 1; guint has_clip : 1;
guint clip_to_allocation : 1; guint clip_to_allocation : 1;
@ -379,7 +381,7 @@ enum
PICK, PICK,
REALIZE, REALIZE,
UNREALIZE, UNREALIZE,
QUEUE_REDRAW,
EVENT, EVENT,
CAPTURED_EVENT, CAPTURED_EVENT,
BUTTON_PRESS_EVENT, BUTTON_PRESS_EVENT,
@ -881,6 +883,49 @@ clutter_actor_real_allocate (ClutterActor *self,
g_object_thaw_notify (G_OBJECT (self)); g_object_thaw_notify (G_OBJECT (self));
} }
static void
clutter_actor_queue_redraw_with_origin (ClutterActor *self,
ClutterActor *origin)
{
/* short-circuit the trivial case */
if (!CLUTTER_ACTOR_IS_VISIBLE(self))
return;
/* already queued since last paint() */
if (self->priv->queued_redraw)
return;
/* calls klass->queue_redraw in default handler */
g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
}
static void
clutter_actor_real_queue_redraw (ClutterActor *self,
ClutterActor *origin)
{
ClutterActor *parent;
/* short-circuit the trivial case */
if (!CLUTTER_ACTOR_IS_VISIBLE (self))
return;
/* already queued since last paint() */
if (self->priv->queued_redraw)
return;
self->priv->queued_redraw = TRUE;
/* notify parents, if they are all visible eventually we'll
* queue redraw on the stage, which queues the redraw idle.
*/
parent = clutter_actor_get_parent (self);
if (parent != NULL)
{
/* this will go up recursively */
clutter_actor_queue_redraw_with_origin (parent, origin);
}
}
/* like ClutterVertex, but with a w component */ /* like ClutterVertex, but with a w component */
typedef struct { typedef struct {
gfloat x; gfloat x;
@ -1571,6 +1616,7 @@ clutter_actor_paint (ClutterActor *self)
{ {
clutter_actor_shader_pre_paint (self, FALSE); clutter_actor_shader_pre_paint (self, FALSE);
self->priv->queued_redraw = FALSE;
g_signal_emit (self, actor_signals[PAINT], 0); g_signal_emit (self, actor_signals[PAINT], 0);
clutter_actor_shader_post_paint (self); clutter_actor_shader_post_paint (self);
@ -2890,6 +2936,66 @@ clutter_actor_class_init (ClutterActorClass *klass)
G_TYPE_NONE, 1, G_TYPE_NONE, 1,
CLUTTER_TYPE_ACTOR); CLUTTER_TYPE_ACTOR);
/**
* ClutterActor::queue-redraw:
* @actor: the actor we're bubbling the redraw request through
* @origin: the actor which initiated the redraw request
*
* The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
* is called on @origin.
*
* The default implementation for #ClutterActor chains up to the
* parent actor and queues a redraw on the parent, thus "bubbling"
* the redraw queue up through the actor graph. The default
* implementation for #ClutterStage queues a clutter_redraw() in a
* main loop idle handler.
*
* Note that the @origin actor may be the stage, or a container; it
* does not have to be a leaf node in the actor graph.
*
* Toolkits embedding a #ClutterStage which require a redraw and
* relayout cycle can stop the emission of this signal using the
* GSignal API, redraw the UI and then call clutter_redraw()
* themselves, like:
*
* |[
* static void
* on_redraw_complete (void)
* {
* /&ast; execute the Clutter drawing pipeline &ast;/
* clutter_redraw ();
* }
*
* static void
* on_stage_queue_redraw (ClutterStage *stage)
* {
* /&ast; this prevents the default handler to run &ast;/
* g_signal_stop_emission_by_name (stage, "queue-redraw");
*
* /&ast; queue a redraw with the host toolkit and call
* &ast; a function when the redraw has been completed
* &ast;/
* queue_a_redraw (G_CALLBACK (on_redraw_complete));
* }
* ]|
*
* <note><para>This signal is emitted before the Clutter paint
* pipeline is executed. If you want to know when the pipeline has
* been completed you should connect to the ::paint signal on the
* Stage with g_signal_connect_after().</para></note>
*
* Since: 1.0
*/
actor_signals[QUEUE_REDRAW] =
g_signal_new (I_("queue-redraw"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
NULL, NULL,
clutter_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
CLUTTER_TYPE_ACTOR);
/** /**
* ClutterActor::event: * ClutterActor::event:
* @actor: the actor which received the event * @actor: the actor which received the event
@ -3247,6 +3353,7 @@ clutter_actor_class_init (ClutterActorClass *klass)
klass->get_preferred_width = clutter_actor_real_get_preferred_width; klass->get_preferred_width = clutter_actor_real_get_preferred_width;
klass->get_preferred_height = clutter_actor_real_get_preferred_height; klass->get_preferred_height = clutter_actor_real_get_preferred_height;
klass->allocate = clutter_actor_real_allocate; klass->allocate = clutter_actor_real_allocate;
klass->queue_redraw = clutter_actor_real_queue_redraw;
} }
static void static void
@ -3329,22 +3436,9 @@ clutter_actor_destroy (ClutterActor *self)
void void
clutter_actor_queue_redraw (ClutterActor *self) clutter_actor_queue_redraw (ClutterActor *self)
{ {
ClutterActor *stage;
g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_ACTOR (self));
/* short-circuit the trivial case */ clutter_actor_queue_redraw_with_origin (self, self);
if (!CLUTTER_ACTOR_IS_VISIBLE (self))
return;
/* check if any part of the scenegraph we're in
* is not visible
*/
if (!clutter_actor_get_paint_visibility (self))
return;
if ((stage = clutter_actor_get_stage (self)) != NULL)
clutter_stage_queue_redraw (CLUTTER_STAGE (stage));
} }
/** /**

View File

@ -227,6 +227,9 @@ struct _ClutterActorClass
void (* pick) (ClutterActor *actor, void (* pick) (ClutterActor *actor,
const ClutterColor *color); const ClutterColor *color);
void (* queue_redraw) (ClutterActor *actor,
ClutterActor *leaf_that_queued);
/* size negotiation */ /* size negotiation */
void (* get_preferred_width) (ClutterActor *actor, void (* get_preferred_width) (ClutterActor *actor,
ClutterUnit for_height, ClutterUnit for_height,

View File

@ -116,7 +116,6 @@ enum
UNFULLSCREEN, UNFULLSCREEN,
ACTIVATE, ACTIVATE,
DEACTIVATE, DEACTIVATE,
QUEUE_REDRAW,
LAST_SIGNAL LAST_SIGNAL
}; };
@ -376,8 +375,10 @@ redraw_update_idle (gpointer user_data)
} }
static void static void
clutter_stage_real_queue_redraw (ClutterStage *stage) clutter_stage_real_queue_redraw (ClutterActor *actor,
ClutterActor *leaf)
{ {
ClutterStage *stage = CLUTTER_STAGE (actor);
ClutterStagePrivate *priv = stage->priv; ClutterStagePrivate *priv = stage->priv;
if (priv->update_idle == 0) if (priv->update_idle == 0)
@ -585,6 +586,7 @@ clutter_stage_class_init (ClutterStageClass *klass)
actor_class->unrealize = clutter_stage_unrealize; actor_class->unrealize = clutter_stage_unrealize;
actor_class->show = clutter_stage_show; actor_class->show = clutter_stage_show;
actor_class->hide = clutter_stage_hide; actor_class->hide = clutter_stage_hide;
actor_class->queue_redraw = clutter_stage_real_queue_redraw;
/** /**
* ClutterStage:fullscreen: * ClutterStage:fullscreen:
@ -777,58 +779,8 @@ clutter_stage_class_init (ClutterStageClass *klass)
NULL, NULL, NULL, NULL,
clutter_marshal_VOID__VOID, clutter_marshal_VOID__VOID,
G_TYPE_NONE, 0); G_TYPE_NONE, 0);
/**
* ClutterStage::queue-redraw:
* @stage: the stage which was queued for redraw
*
* The ::queue-redraw signal is emitted each time a #ClutterStage
* has been queued for a redraw. You can use this signal to know
* when clutter_stage_queue_redraw() has been called.
*
* Toolkits embedding a #ClutterStage which require a redraw and
* relayout cycle can stop the emission of this signal using the
* GSignal API, redraw the UI and then call clutter_redraw()
* themselves, like:
*
* |[
* static void
* on_redraw_complete (void)
* {
* /&ast; execute the Clutter drawing pipeline &ast;/
* clutter_redraw ();
* }
*
* static void
* on_stage_queue_redraw (ClutterStage *stage)
* {
* /&ast; this prevents the default handler to run &ast;/
* g_signal_stop_emission_by_name (stage, "queue-redraw");
*
* /&ast; queue a redraw with the host toolkit and call
* &ast; a function when the redraw has been completed
* &ast;/
* queue_a_redraw (G_CALLBACK (on_redraw_complete));
* }
* ]|
*
* <note><para>This signal is emitted before the Clutter paint
* pipeline is run. If you want to know when the pipeline has been
* completed you should connect to the ::paint signal on the Stage
* with g_signal_connect_after().</para></note>
*
* Since: 1.0
*/
stage_signals[QUEUE_REDRAW] =
g_signal_new (I_("queue-redraw"),
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterStageClass, queue_redraw),
NULL, NULL,
clutter_marshal_VOID__VOID,
G_TYPE_NONE, 0);
klass->fullscreen = clutter_stage_real_fullscreen; klass->fullscreen = clutter_stage_real_fullscreen;
klass->queue_redraw = clutter_stage_real_queue_redraw;
g_type_class_add_private (gobject_class, sizeof (ClutterStagePrivate)); g_type_class_add_private (gobject_class, sizeof (ClutterStagePrivate));
} }
@ -1793,7 +1745,7 @@ clutter_stage_ensure_viewport (ClutterStage *stage)
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES); CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
clutter_stage_queue_redraw (stage); clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
} }
/** /**
@ -1805,6 +1757,9 @@ clutter_stage_ensure_viewport (ClutterStage *stage)
* <note>Applications should call clutter_actor_queue_redraw() and not * <note>Applications should call clutter_actor_queue_redraw() and not
* this function.</note> * this function.</note>
* *
* <note>This function is just a wrapper for clutter_actor_queue_redraw()
* and should probably go away.</note>
*
* Since: 0.8 * Since: 0.8
*/ */
void void
@ -1812,7 +1767,7 @@ clutter_stage_queue_redraw (ClutterStage *stage)
{ {
g_return_if_fail (CLUTTER_IS_STAGE (stage)); g_return_if_fail (CLUTTER_IS_STAGE (stage));
g_signal_emit (stage, stage_signals[QUEUE_REDRAW], 0); clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
} }
/** /**

View File

@ -106,8 +106,6 @@ struct _ClutterStageClass
void (* activate) (ClutterStage *stage); void (* activate) (ClutterStage *stage);
void (* deactivate) (ClutterStage *stage); void (* deactivate) (ClutterStage *stage);
void (* queue_redraw) (ClutterStage *stage);
/*< private >*/ /*< private >*/
/* padding for future expansion */ /* padding for future expansion */
gpointer _padding_dummy[32]; gpointer _padding_dummy[32];