Bug 1087 - virtualize stage_queue_redraw
authorHavoc Pennington <hp@pobox.com>
Mon, 12 Jan 2009 14:19:48 +0000 (14:19 +0000)
committerEmmanuele Bassi <ebassi@linux.intel.com>
Mon, 12 Jan 2009 14:28:39 +0000 (14:28 +0000)
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
clutter/clutter-stage.h

index 3b312df..6a4e850 100644 (file)
@@ -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)
+   *   {
+   *     /&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_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);
 }
 
 /**
index 7b174ee..9cbbdeb 100644 (file)
@@ -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];