mirror of
https://github.com/brl/mutter.git
synced 2025-02-22 16:04:09 +00:00
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.
This commit is contained in:
parent
06314e9ed8
commit
beb91d7676
@ -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
|
||||
@ -670,6 +678,33 @@ clutter_interval_set_initial_value (ClutterInterval *interval,
|
||||
clutter_interval_set_value_internal (interval, INITIAL, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -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
|
||||
@ -762,6 +799,32 @@ clutter_interval_get_final_value (ClutterInterval *interval,
|
||||
clutter_interval_get_value_internal (interval, FINAL, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
@ -43,34 +43,6 @@ G_BEGIN_DECLS
|
||||
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:
|
||||
*
|
||||
@ -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,
|
||||
|
@ -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__ */
|
||||
|
@ -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__ */
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user