[clutter/wip/apocalypses/apocalypse-6: 1/17] interval: Add variadic arguments for initial/final setters



commit beb91d76763b3b3aede1be1da8bc3c1f8184ed8a
Author: Emmanuele Bassi <ebassi linux intel com>
Date:   Thu Mar 15 11:02:30 2012 +0000

    interval: Add variadic arguments for initial/final setters
    
    As a convenience for the C API.
    
    Language bindings should already be using the GValue variants.
    
    This commit also moves the custom progress functions out of the
    clutter-interval.c, as they are meant to be generic interpolation
    functions and not ClutterInterval-specific.

 clutter/clutter-interval.c |  277 +++++++++++++++++++++-----------------------
 clutter/clutter-interval.h |   33 +-----
 clutter/clutter-private.h  |    7 +
 clutter/clutter-types.h    |   28 +++++
 clutter/clutter-util.c     |  148 +++++++++++++++++++++++
 5 files changed, 322 insertions(+), 171 deletions(-)
---
diff --git a/clutter/clutter-interval.c b/clutter/clutter-interval.c
index c151231..d0ccec0 100644
--- a/clutter/clutter-interval.c
+++ b/clutter/clutter-interval.c
@@ -63,14 +63,6 @@
 #include "clutter-private.h"
 #include "clutter-units.h"
 
-typedef struct
-{
-  GType value_type;
-  ClutterProgressFunc func;
-} ProgressData;
-
-static GHashTable *progress_funcs = NULL;
-
 enum
 {
   PROP_0,
@@ -195,23 +187,15 @@ clutter_interval_real_compute_value (ClutterInterval *interval,
 
   value_type = clutter_interval_get_value_type (interval);
 
-  if (G_UNLIKELY (progress_funcs != NULL))
+  if (_clutter_has_progress_function (value_type))
     {
-      ProgressData *p_data;
-
-      p_data =
-        g_hash_table_lookup (progress_funcs, GUINT_TO_POINTER (value_type));
-
-      /* if we have a progress function, and that function was
-       * successful in computing the progress, then we bail out
-       * as fast as we can
-       */
-      if (p_data != NULL)
-        {
-          retval = p_data->func (initial, final, factor, value);
-          if (retval)
-            return retval;
-        }
+      retval = _clutter_run_progress_function (value_type,
+                                               initial,
+                                               final,
+                                               factor,
+                                               value);
+      if (retval)
+        return TRUE;
     }
 
   switch (G_TYPE_FUNDAMENTAL (value_type))
@@ -413,16 +397,44 @@ clutter_interval_init (ClutterInterval *self)
   priv->values = g_malloc0 (sizeof (GValue) * N_VALUES);
 }
 
-static void
-clutter_interval_set_interval_valist (ClutterInterval *interval,
-                                      va_list          var_args)
+static inline void
+clutter_interval_set_value_internal (ClutterInterval *interval,
+                                     gint             index_,
+                                     const GValue    *value)
+{
+  ClutterIntervalPrivate *priv = interval->priv;
+
+  g_assert (index_ >= INITIAL && index_ <= RESULT);
+
+  if (G_IS_VALUE (&priv->values[index_]))
+    g_value_unset (&priv->values[index_]);
+
+  g_value_init (&priv->values[index_], priv->value_type);
+  g_value_copy (value, &priv->values[index_]);
+}
+
+static inline void
+clutter_interval_get_value_internal (ClutterInterval *interval,
+                                     gint             index_,
+                                     GValue          *value)
+{
+  ClutterIntervalPrivate *priv = interval->priv;
+
+  g_assert (index_ >= INITIAL && index_ <= RESULT);
+
+  g_value_copy (&priv->values[index_], value);
+}
+
+static gboolean
+clutter_interval_set_initial_internal (ClutterInterval *interval,
+                                       va_list         *args)
 {
   GType gtype = interval->priv->value_type;
   GValue value = { 0, };
   gchar *error;
 
   /* initial value */
-  G_VALUE_COLLECT_INIT (&value, gtype, var_args, 0, &error);
+  G_VALUE_COLLECT_INIT (&value, gtype, *args, 0, &error);
 
   if (error)
     {
@@ -433,26 +445,42 @@ clutter_interval_set_interval_valist (ClutterInterval *interval,
        * undefined behaviour
        */
       g_free (error);
-      return;
+      return FALSE;
     }
 
-  clutter_interval_set_initial_value (interval, &value);
+  clutter_interval_set_value_internal (interval, INITIAL, &value);
   g_value_unset (&value);
 
-  /* final value */
-  G_VALUE_COLLECT_INIT (&value, gtype, var_args, 0, &error);
+  return TRUE;
+}
+
+static gboolean
+clutter_interval_set_final_internal (ClutterInterval *interval,
+                                     va_list         *args)
+{
+  GType gtype = interval->priv->value_type;
+  GValue value = { 0, };
+  gchar *error;
+
+  /* initial value */
+  G_VALUE_COLLECT_INIT (&value, gtype, *args, 0, &error);
 
   if (error)
     {
       g_warning ("%s: %s", G_STRLOC, error);
 
-      /* see above */
+      /* we leak the value here as it might not be in a valid state
+       * given the error and calling g_value_unset() might lead to
+       * undefined behaviour
+       */
       g_free (error);
-      return;
+      return FALSE;
     }
 
-  clutter_interval_set_final_value (interval, &value);
+  clutter_interval_set_value_internal (interval, FINAL, &value);
   g_value_unset (&value);
+
+  return TRUE;
 }
 
 static void
@@ -524,7 +552,13 @@ clutter_interval_new (GType gtype,
   retval = g_object_new (CLUTTER_TYPE_INTERVAL, "value-type", gtype, NULL);
 
   va_start (args, gtype);
-  clutter_interval_set_interval_valist (retval, args);
+
+  if (!clutter_interval_set_initial_internal (retval, &args))
+    goto out;
+
+  clutter_interval_set_final_internal (retval, &args);
+
+out:
   va_end (args);
 
   return retval;
@@ -616,34 +650,6 @@ clutter_interval_get_value_type (ClutterInterval *interval)
   return interval->priv->value_type;
 }
 
-static inline void
-clutter_interval_set_value_internal (ClutterInterval *interval,
-                                     gint             index_,
-                                     const GValue    *value)
-{
-  ClutterIntervalPrivate *priv = interval->priv;
-
-  g_assert (index_ >= INITIAL && index_ <= RESULT);
-
-  if (G_IS_VALUE (&priv->values[index_]))
-    g_value_unset (&priv->values[index_]);
-
-  g_value_init (&priv->values[index_], priv->value_type);
-  g_value_copy (value, &priv->values[index_]);
-}
-
-static inline void
-clutter_interval_get_value_internal (ClutterInterval *interval,
-                                     gint             index_,
-                                     GValue          *value)
-{
-  ClutterIntervalPrivate *priv = interval->priv;
-
-  g_assert (index_ >= INITIAL && index_ <= RESULT);
-
-  g_value_copy (&priv->values[index_], value);
-}
-
 /**
  * clutter_interval_set_initial_value:
  * @interval: a #ClutterInterval
@@ -652,6 +658,8 @@ clutter_interval_get_value_internal (ClutterInterval *interval,
  * Sets the initial value of @interval to @value. The value is copied
  * inside the #ClutterInterval.
  *
+ * Rename to: clutter_interval_set_initial
+ *
  * Since: 1.0
  */
 void
@@ -671,6 +679,33 @@ clutter_interval_set_initial_value (ClutterInterval *interval,
 }
 
 /**
+ * clutter_interval_set_initial: (skip)
+ * @interval: a #ClutterInterval
+ * @...: the initial value of the interval.
+ *
+ * Variadic arguments version of clutter_interval_set_initial_value().
+ *
+ * This function is meant as a convenience for the C API.
+ *
+ * Language bindings should use clutter_interval_set_initial_value()
+ * instead.
+ *
+ * Since: 1.10
+ */
+void
+clutter_interval_set_initial (ClutterInterval *interval,
+                              ...)
+{
+  va_list args;
+
+  g_return_if_fail (CLUTTER_IS_INTERVAL (interval));
+
+  va_start (args, interval);
+  clutter_interval_set_initial_internal (interval, &args);
+  va_end (args);
+}
+
+/**
  * clutter_interval_get_initial_value:
  * @interval: a #ClutterInterval
  * @value: (out caller-allocates): a #GValue
@@ -721,6 +756,8 @@ clutter_interval_peek_initial_value (ClutterInterval *interval)
  * Sets the final value of @interval to @value. The value is
  * copied inside the #ClutterInterval.
  *
+ * Rename to: clutter_interval_set_final
+ *
  * Since: 1.0
  */
 void
@@ -763,6 +800,32 @@ clutter_interval_get_final_value (ClutterInterval *interval,
 }
 
 /**
+ * clutter_interval_set_final: (skip)
+ * @interval: a #ClutterInterval
+ * @...: the final value of the interval
+ *
+ * Variadic arguments version of clutter_interval_set_final_value().
+ *
+ * This function is meant as a convenience for the C API.
+ *
+ * Language bindings should use clutter_interval_set_final_value() instead.
+ *
+ * Since: 1.10
+ */
+void
+clutter_interval_set_final (ClutterInterval *interval,
+                            ...)
+{
+  va_list args;
+
+  g_return_if_fail (CLUTTER_IS_INTERVAL (interval));
+
+  va_start (args, interval);
+  clutter_interval_set_final_internal (interval, &args);
+  va_end (args);
+}
+
+/**
  * clutter_interval_peek_final_value:
  * @interval: a #ClutterInterval
  *
@@ -812,7 +875,13 @@ clutter_interval_set_interval (ClutterInterval *interval,
   g_return_if_fail (interval->priv->value_type != G_TYPE_INVALID);
 
   va_start (args, interval);
-  clutter_interval_set_interval_valist (interval, args);
+
+  if (!clutter_interval_set_initial_internal (interval, &args))
+    goto out;
+
+  clutter_interval_set_final_internal (interval, &args);
+
+out:
   va_end (args);
 }
 
@@ -941,81 +1010,3 @@ clutter_interval_compute (ClutterInterval *interval,
 
   return NULL;
 }
-
-/**
- * clutter_interval_register_progress_func: (skip)
- * @value_type: a #GType
- * @func: a #ClutterProgressFunc, or %NULL to unset a previously
- *   set progress function
- *
- * Sets the progress function for a given @value_type, like:
- *
- * |[
- *   clutter_interval_register_progress_func (MY_TYPE_FOO,
- *                                            my_foo_progress);
- * ]|
- *
- * Whenever a #ClutterInterval instance using the default
- * #ClutterInterval::compute_value implementation is set as an
- * interval between two #GValue of type @value_type, it will call
- * @func to establish the value depending on the given progress,
- * for instance:
- *
- * |[
- *   static gboolean
- *   my_int_progress (const GValue *a,
- *                    const GValue *b,
- *                    gdouble       progress,
- *                    GValue       *retval)
- *   {
- *     gint ia = g_value_get_int (a);
- *     gint ib = g_value_get_int (b);
- *     gint res = factor * (ib - ia) + ia;
- *
- *     g_value_set_int (retval, res);
- *
- *     return TRUE;
- *   }
- *
- *   clutter_interval_register_progress_func (G_TYPE_INT, my_int_progress);
- * ]|
- *
- * To unset a previously set progress function of a #GType, pass %NULL
- * for @func.
- *
- * Since: 1.0
- */
-void
-clutter_interval_register_progress_func (GType               value_type,
-                                         ClutterProgressFunc func)
-{
-  ProgressData *progress_func;
-
-  g_return_if_fail (value_type != G_TYPE_INVALID);
-
-  if (G_UNLIKELY (progress_funcs == NULL))
-    progress_funcs = g_hash_table_new (NULL, NULL);
-
-  progress_func =
-    g_hash_table_lookup (progress_funcs, GUINT_TO_POINTER (value_type));
-  if (G_UNLIKELY (progress_func))
-    {
-      if (func == NULL)
-        {
-          g_hash_table_remove (progress_funcs, GUINT_TO_POINTER (value_type));
-          g_slice_free (ProgressData, progress_func);
-        }
-      else
-        progress_func->func = func;
-    }
-  else
-    {
-      progress_func = g_slice_new (ProgressData);
-      progress_func->value_type = value_type;
-      progress_func->func = func;
-
-      g_hash_table_replace (progress_funcs,
-                            GUINT_TO_POINTER (value_type),
-                            progress_func);
-    }
-}
diff --git a/clutter/clutter-interval.h b/clutter/clutter-interval.h
index 44174f3..f845de9 100644
--- a/clutter/clutter-interval.h
+++ b/clutter/clutter-interval.h
@@ -44,34 +44,6 @@ typedef struct _ClutterIntervalPrivate          ClutterIntervalPrivate;
 typedef struct _ClutterIntervalClass            ClutterIntervalClass;
 
 /**
- * ClutterProgressFunc:
- * @a: the initial value of an interval
- * @b: the final value of an interval
- * @progress: the progress factor, between 0 and 1
- * @retval: the value used to store the progress
- *
- * Prototype of the progress function used to compute the value
- * between the two ends @a and @b of an interval depending on
- * the value of @progress.
- *
- * The #GValue in @retval is already initialized with the same
- * type as @a and @b.
- *
- * This function will be called by #ClutterInterval if the
- * type of the values of the interval was registered using
- * clutter_interval_register_progress_func().
- *
- * Return value: %TRUE if the function successfully computed
- *   the value and stored it inside @retval
- *
- * Since: 1.0
- */
-typedef gboolean (* ClutterProgressFunc) (const GValue *a,
-                                          const GValue *b,
-                                          gdouble       progress,
-                                          GValue       *retval);
-
-/**
  * ClutterInterval:
  *
  * The #ClutterInterval structure contains only private data and should
@@ -131,11 +103,16 @@ ClutterInterval *clutter_interval_new_with_values    (GType            gtype,
 ClutterInterval *clutter_interval_clone              (ClutterInterval *interval);
 
 GType            clutter_interval_get_value_type     (ClutterInterval *interval);
+
+void             clutter_interval_set_initial        (ClutterInterval *interval,
+                                                      ...);
 void             clutter_interval_set_initial_value  (ClutterInterval *interval,
                                                       const GValue    *value);
 void             clutter_interval_get_initial_value  (ClutterInterval *interval,
                                                       GValue          *value);
 GValue *         clutter_interval_peek_initial_value (ClutterInterval *interval);
+void             clutter_interval_set_final          (ClutterInterval *interval,
+                                                      ...);
 void             clutter_interval_set_final_value    (ClutterInterval *interval,
                                                       const GValue    *value);
 void             clutter_interval_get_final_value    (ClutterInterval *interval,
diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h
index 916ee73..bd099e9 100644
--- a/clutter/clutter-private.h
+++ b/clutter/clutter-private.h
@@ -265,6 +265,13 @@ typedef enum _ClutterCullResult
   CLUTTER_CULL_RESULT_PARTIAL
 } ClutterCullResult;
 
+gboolean        _clutter_has_progress_function  (GType gtype);
+gboolean        _clutter_run_progress_function  (GType gtype,
+                                                 const GValue *initial,
+                                                 const GValue *final,
+                                                 gdouble progress,
+                                                 GValue *retval);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_PRIVATE_H__ */
diff --git a/clutter/clutter-types.h b/clutter/clutter-types.h
index d2b5fe2..fdc81fa 100644
--- a/clutter/clutter-types.h
+++ b/clutter/clutter-types.h
@@ -287,6 +287,34 @@ ClutterMargin * clutter_margin_new      (void) G_GNUC_MALLOC;
 ClutterMargin * clutter_margin_copy     (const ClutterMargin *margin_);
 void            clutter_margin_free     (ClutterMargin       *margin_);
 
+/**
+ * ClutterProgressFunc:
+ * @a: the initial value of an interval
+ * @b: the final value of an interval
+ * @progress: the progress factor, between 0 and 1
+ * @retval: the value used to store the progress
+ *
+ * Prototype of the progress function used to compute the value
+ * between the two ends @a and @b of an interval depending on
+ * the value of @progress.
+ *
+ * The #GValue in @retval is already initialized with the same
+ * type as @a and @b.
+ *
+ * This function will be called by #ClutterInterval if the
+ * type of the values of the interval was registered using
+ * clutter_interval_register_progress_func().
+ *
+ * Return value: %TRUE if the function successfully computed
+ *   the value and stored it inside @retval
+ *
+ * Since: 1.0
+ */
+typedef gboolean (* ClutterProgressFunc) (const GValue *a,
+                                          const GValue *b,
+                                          gdouble       progress,
+                                          GValue       *retval);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_TYPES_H__ */
diff --git a/clutter/clutter-util.c b/clutter/clutter-util.c
index eeecb63..b95629c 100644
--- a/clutter/clutter-util.c
+++ b/clutter/clutter-util.c
@@ -37,6 +37,7 @@
 #include <glib/gi18n-lib.h>
 
 #include "clutter-main.h"
+#include "clutter-interval.h"
 #include "clutter-private.h"
 
 #include "deprecated/clutter-util.h"
@@ -180,3 +181,150 @@ _clutter_util_rectangle_union (const cairo_rectangle_int_t *src1,
   dest->x = dest_x;
   dest->y = dest_y;
 }
+
+typedef struct
+{
+  GType value_type;
+  ClutterProgressFunc func;
+} ProgressData;
+
+G_LOCK_DEFINE_STATIC (progress_funcs);
+static GHashTable *progress_funcs = NULL;
+
+gboolean
+_clutter_has_progress_function (GType gtype)
+{
+  const char *type_name = g_type_name (gtype);
+
+  if (progress_funcs == NULL)
+    return FALSE;
+
+  return g_hash_table_lookup (progress_funcs, type_name) != NULL;
+}
+
+gboolean
+_clutter_run_progress_function (GType gtype,
+                                const GValue *initial,
+                                const GValue *final,
+                                gdouble progress,
+                                GValue *retval)
+{
+  ProgressData *pdata;
+  gboolean res;
+
+  G_LOCK (progress_funcs);
+
+  if (G_UNLIKELY (progress_funcs == NULL))
+    {
+      res = FALSE;
+      goto out;
+    }
+
+  pdata = g_hash_table_lookup (progress_funcs, g_type_name (gtype));
+  if (G_UNLIKELY (pdata == NULL))
+    {
+      res = FALSE;
+      goto out;
+    }
+
+  res = pdata->func (initial, final, progress, retval);
+
+out:
+  G_UNLOCK (progress_funcs);
+
+  return res;
+}
+
+static void
+progress_data_destroy (gpointer data_)
+{
+  g_slice_free (ProgressData, data_);
+}
+
+/**
+ * clutter_interval_register_progress_func: (skip)
+ * @value_type: a #GType
+ * @func: a #ClutterProgressFunc, or %NULL to unset a previously
+ *   set progress function
+ *
+ * Sets the progress function for a given @value_type, like:
+ *
+ * |[
+ *   clutter_interval_register_progress_func (MY_TYPE_FOO,
+ *                                            my_foo_progress);
+ * ]|
+ *
+ * Whenever a #ClutterInterval instance using the default
+ * #ClutterInterval::compute_value implementation is set as an
+ * interval between two #GValue of type @value_type, it will call
+ * @func to establish the value depending on the given progress,
+ * for instance:
+ *
+ * |[
+ *   static gboolean
+ *   my_int_progress (const GValue *a,
+ *                    const GValue *b,
+ *                    gdouble       progress,
+ *                    GValue       *retval)
+ *   {
+ *     gint ia = g_value_get_int (a);
+ *     gint ib = g_value_get_int (b);
+ *     gint res = factor * (ib - ia) + ia;
+ *
+ *     g_value_set_int (retval, res);
+ *
+ *     return TRUE;
+ *   }
+ *
+ *   clutter_interval_register_progress_func (G_TYPE_INT, my_int_progress);
+ * ]|
+ *
+ * To unset a previously set progress function of a #GType, pass %NULL
+ * for @func.
+ *
+ * Since: 1.0
+ */
+void
+clutter_interval_register_progress_func (GType               value_type,
+                                         ClutterProgressFunc func)
+{
+  ProgressData *progress_func;
+  const char *type_name;
+
+  g_return_if_fail (value_type != G_TYPE_INVALID);
+
+  type_name = g_type_name (value_type);
+
+  G_LOCK (progress_funcs);
+
+  if (G_UNLIKELY (progress_funcs == NULL))
+    progress_funcs = g_hash_table_new_full (NULL, NULL,
+                                            NULL,
+                                            progress_data_destroy);
+
+  progress_func =
+    g_hash_table_lookup (progress_funcs, type_name);
+
+  if (G_UNLIKELY (progress_func))
+    {
+      if (func == NULL)
+        {
+          g_hash_table_remove (progress_funcs, type_name);
+          g_slice_free (ProgressData, progress_func);
+        }
+      else
+        progress_func->func = func;
+    }
+  else
+    {
+      progress_func = g_slice_new (ProgressData);
+      progress_func->value_type = value_type;
+      progress_func->func = func;
+
+      g_hash_table_replace (progress_funcs,
+                            (gpointer) type_name,
+                            progress_func);
+    }
+
+  G_UNLOCK (progress_funcs);
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]