Bug 1087 - virtualize stage_queue_redraw

Add a ClutterStage::queue-redraw signal.

The purpose of this signal is to allow combining the Clutter redraw
idle with another redraw idle such as gtk's (or any other one really;
this is desirable anytime Clutter is not the only thing drawing to
a toplevel window).

To override the default, you would connect to ::queue-redraw and then
stop the signal emission.
This commit is contained in:
Havoc Pennington 2009-01-12 14:19:48 +00:00 committed by Emmanuele Bassi
parent f09b221ade
commit be462b2ea8
2 changed files with 91 additions and 29 deletions

View File

@ -115,6 +115,8 @@ enum
UNFULLSCREEN, UNFULLSCREEN,
ACTIVATE, ACTIVATE,
DEACTIVATE, DEACTIVATE,
QUEUE_REDRAW,
LAST_SIGNAL LAST_SIGNAL
}; };
@ -335,6 +337,42 @@ clutter_stage_real_fullscreen (ClutterStage *stage)
clutter_actor_allocate (CLUTTER_ACTOR (stage), &box, FALSE); clutter_actor_allocate (CLUTTER_ACTOR (stage), &box, FALSE);
} }
static gboolean
redraw_update_idle (gpointer user_data)
{
ClutterStage *stage = user_data;
ClutterStagePrivate *priv = stage->priv;
if (priv->update_idle)
{
g_source_remove (priv->update_idle);
priv->update_idle = 0;
}
CLUTTER_NOTE (MULTISTAGE, "redrawing via idle for stage:%p", stage);
clutter_redraw (stage);
return FALSE;
}
static void
clutter_stage_real_queue_redraw (ClutterStage *stage)
{
ClutterStagePrivate *priv = stage->priv;
if (priv->update_idle == 0)
{
CLUTTER_TIMESTAMP (SCHEDULER, "Adding idle source for stage: %p", stage);
/* FIXME: weak_ref self in case we dissapear before paint? */
priv->update_idle =
clutter_threads_add_idle_full (CLUTTER_PRIORITY_REDRAW,
redraw_update_idle,
stage,
NULL);
}
}
static void static void
clutter_stage_set_property (GObject *object, clutter_stage_set_property (GObject *object,
guint prop_id, guint prop_id,
@ -687,8 +725,58 @@ 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)
* {
* /* execute the Clutter drawing pipeline */
* clutter_redraw ();
* }
*
* static void
* on_stage_queue_redraw (ClutterStage *stage)
* {
* /* this prevents the default handler to run */
* g_signal_stop_emission_by_name (stage, "queue-redraw");
*
* /* queue a redraw with the host toolkit and call
* * a function when the redraw has been completed
* */
* 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_FIRST,
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));
} }
@ -1826,24 +1914,6 @@ clutter_stage_ensure_viewport (ClutterStage *stage)
clutter_stage_queue_redraw (stage); clutter_stage_queue_redraw (stage);
} }
static gboolean
redraw_update_idle (gpointer user_data)
{
ClutterStage *stage = user_data;
ClutterStagePrivate *priv = stage->priv;
if (priv->update_idle)
{
g_source_remove (priv->update_idle);
priv->update_idle = 0;
}
CLUTTER_NOTE (MULTISTAGE, "redrawing via idle for stage:%p", stage);
clutter_redraw (stage);
return FALSE;
}
/** /**
* clutter_stage_queue_redraw: * clutter_stage_queue_redraw:
* @stage: the #ClutterStage * @stage: the #ClutterStage
@ -1860,17 +1930,7 @@ clutter_stage_queue_redraw (ClutterStage *stage)
{ {
g_return_if_fail (CLUTTER_IS_STAGE (stage)); g_return_if_fail (CLUTTER_IS_STAGE (stage));
if (!stage->priv->update_idle) g_signal_emit (stage, stage_signals[QUEUE_REDRAW], 0);
{
CLUTTER_TIMESTAMP (SCHEDULER, "Adding idle source for stage: %p", stage);
/* FIXME: weak_ref self in case we dissapear before paint? */
stage->priv->update_idle =
clutter_threads_add_idle_full (CLUTTER_PRIORITY_REDRAW,
redraw_update_idle,
stage,
NULL);
}
} }
/** /**

View File

@ -106,6 +106,8 @@ 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];