From be462b2ea8d2ed908520a498908a83c5ba37a3b7 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Mon, 12 Jan 2009 14:19:48 +0000 Subject: [PATCH] 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. --- clutter/clutter-stage.c | 118 ++++++++++++++++++++++++++++++---------- clutter/clutter-stage.h | 2 + 2 files changed, 91 insertions(+), 29 deletions(-) diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index 3b312df2f..6a4e850b8 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -115,6 +115,8 @@ enum UNFULLSCREEN, ACTIVATE, DEACTIVATE, + QUEUE_REDRAW, + LAST_SIGNAL }; @@ -335,6 +337,42 @@ clutter_stage_real_fullscreen (ClutterStage *stage) 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 clutter_stage_set_property (GObject *object, guint prop_id, @@ -687,8 +725,58 @@ clutter_stage_class_init (ClutterStageClass *klass) NULL, NULL, clutter_marshal_VOID__VOID, 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)); + * } + * ]| + * + * 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(). + * + * 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->queue_redraw = clutter_stage_real_queue_redraw; g_type_class_add_private (gobject_class, sizeof (ClutterStagePrivate)); } @@ -1826,24 +1914,6 @@ clutter_stage_ensure_viewport (ClutterStage *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: * @stage: the #ClutterStage @@ -1860,17 +1930,7 @@ clutter_stage_queue_redraw (ClutterStage *stage) { g_return_if_fail (CLUTTER_IS_STAGE (stage)); - if (!stage->priv->update_idle) - { - 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); - } + g_signal_emit (stage, stage_signals[QUEUE_REDRAW], 0); } /** diff --git a/clutter/clutter-stage.h b/clutter/clutter-stage.h index 7b174ee30..9cbbdeb92 100644 --- a/clutter/clutter-stage.h +++ b/clutter/clutter-stage.h @@ -106,6 +106,8 @@ struct _ClutterStageClass void (* activate) (ClutterStage *stage); void (* deactivate) (ClutterStage *stage); + void (* queue_redraw) (ClutterStage *stage); + /*< private >*/ /* padding for future expansion */ gpointer _padding_dummy[32];