/* LIBPIKA - The PIKA Library * Copyright (C) 1995-2003 Peter Mattis and Spencer Kimball * * pikaparamspecs.c * * This library is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see * . */ #include "config.h" #include #include "pikabase.h" /* * PIKA_TYPE_PARAM_CHOICE */ static void pika_param_choice_class_init (GParamSpecClass *klass); static void pika_param_choice_init (GParamSpec *pspec); static void pika_param_choice_value_set_default (GParamSpec *pspec, GValue *value); static void pika_param_choice_finalize (GParamSpec *pspec); static gboolean pika_param_choice_validate (GParamSpec *pspec, GValue *value); static gint pika_param_choice_values_cmp (GParamSpec *pspec, const GValue *value1, const GValue *value2); GType pika_param_choice_get_type (void) { static GType type = 0; if (! type) { const GTypeInfo info = { sizeof (GParamSpecClass), NULL, NULL, (GClassInitFunc) pika_param_choice_class_init, NULL, NULL, sizeof (PikaParamSpecChoice), 0, (GInstanceInitFunc) pika_param_choice_init }; type = g_type_register_static (G_TYPE_PARAM_BOXED, "PikaParamChoice", &info, 0); } return type; } static void pika_param_choice_class_init (GParamSpecClass *klass) { klass->value_type = G_TYPE_STRING; klass->value_set_default = pika_param_choice_value_set_default; klass->finalize = pika_param_choice_finalize; klass->value_validate = pika_param_choice_validate; klass->values_cmp = pika_param_choice_values_cmp; } static void pika_param_choice_init (GParamSpec *pspec) { PikaParamSpecChoice *choice = PIKA_PARAM_SPEC_CHOICE (pspec); choice->choice = NULL; choice->default_value = NULL; } static void pika_param_choice_value_set_default (GParamSpec *pspec, GValue *value) { PikaParamSpecChoice *cspec = PIKA_PARAM_SPEC_CHOICE (pspec); g_value_set_string (value, cspec->default_value); } static void pika_param_choice_finalize (GParamSpec *pspec) { PikaParamSpecChoice *spec_choice = PIKA_PARAM_SPEC_CHOICE (pspec); g_free (spec_choice->default_value); g_object_unref (spec_choice->choice); } static gboolean pika_param_choice_validate (GParamSpec *pspec, GValue *value) { PikaParamSpecChoice *spec_choice = PIKA_PARAM_SPEC_CHOICE (pspec); PikaChoice *choice = spec_choice->choice; const gchar *strval = g_value_get_string (value); if (! pika_choice_is_valid (choice, strval)) { if (pika_choice_is_valid (choice, spec_choice->default_value)) { g_value_set_string (value, spec_choice->default_value); } else { /* This might happen if the default value is set insensitive. Then we * should just set any valid random nick. */ GList *nicks; nicks = pika_choice_list_nicks (choice); for (GList *iter = nicks; iter; iter = iter->next) if (pika_choice_is_valid (choice, (gchar *) iter->data)) { g_value_set_string (value, (gchar *) iter->data); break; } } return TRUE; } return FALSE; } static gint pika_param_choice_values_cmp (GParamSpec *pspec, const GValue *value1, const GValue *value2) { const gchar *choice1 = g_value_get_string (value1); const gchar *choice2 = g_value_get_string (value2); return g_strcmp0 (choice1, choice2); } /** * pika_param_spec_choice: * @name: Canonical name of the property specified. * @nick: Nick name of the property specified. * @blurb: Description of the property specified. * @choice: (transfer full): the %PikaChoice describing allowed choices. * @flags: Flags for the property specified. * * Creates a new #PikaParamSpecChoice specifying a * #G_TYPE_STRING property. * This %PikaParamSpecChoice takes ownership of the reference on @choice. * * See g_param_spec_internal() for details on property names. * * Returns: (transfer full): The newly created #PikaParamSpecChoice. * * Since: 3.0 **/ GParamSpec * pika_param_spec_choice (const gchar *name, const gchar *nick, const gchar *blurb, PikaChoice *choice, const gchar *default_value, GParamFlags flags) { PikaParamSpecChoice *choice_spec; choice_spec = g_param_spec_internal (PIKA_TYPE_PARAM_CHOICE, name, nick, blurb, flags); g_return_val_if_fail (choice_spec, NULL); choice_spec->choice = choice; choice_spec->default_value = g_strdup (default_value); return G_PARAM_SPEC (choice_spec); } /* * PIKA_TYPE_ARRAY */ /** * pika_array_new: * @data: (array length=length): * @length: * @static_data: */ PikaArray * pika_array_new (const guint8 *data, gsize length, gboolean static_data) { PikaArray *array; g_return_val_if_fail ((data == NULL && length == 0) || (data != NULL && length > 0), NULL); array = g_slice_new0 (PikaArray); array->data = static_data ? (guint8 *) data : g_memdup2 (data, length); array->length = length; array->static_data = static_data; return array; } PikaArray * pika_array_copy (const PikaArray *array) { if (array) return pika_array_new (array->data, array->length, FALSE); return NULL; } void pika_array_free (PikaArray *array) { if (array) { if (! array->static_data) g_free (array->data); g_slice_free (PikaArray, array); } } G_DEFINE_BOXED_TYPE (PikaArray, pika_array, pika_array_copy, pika_array_free) /* * PIKA_TYPE_PARAM_ARRAY */ static void pika_param_array_class_init (GParamSpecClass *klass); static void pika_param_array_init (GParamSpec *pspec); static gboolean pika_param_array_validate (GParamSpec *pspec, GValue *value); static gint pika_param_array_values_cmp (GParamSpec *pspec, const GValue *value1, const GValue *value2); GType pika_param_array_get_type (void) { static GType type = 0; if (! type) { const GTypeInfo info = { sizeof (GParamSpecClass), NULL, NULL, (GClassInitFunc) pika_param_array_class_init, NULL, NULL, sizeof (PikaParamSpecArray), 0, (GInstanceInitFunc) pika_param_array_init }; type = g_type_register_static (G_TYPE_PARAM_BOXED, "PikaParamArray", &info, 0); } return type; } static void pika_param_array_class_init (GParamSpecClass *klass) { klass->value_type = PIKA_TYPE_ARRAY; klass->value_validate = pika_param_array_validate; klass->values_cmp = pika_param_array_values_cmp; } static void pika_param_array_init (GParamSpec *pspec) { } static gboolean pika_param_array_validate (GParamSpec *pspec, GValue *value) { PikaArray *array = value->data[0].v_pointer; if (array) { if ((array->data == NULL && array->length != 0) || (array->data != NULL && array->length == 0)) { g_value_set_boxed (value, NULL); return TRUE; } } return FALSE; } static gint pika_param_array_values_cmp (GParamSpec *pspec, const GValue *value1, const GValue *value2) { PikaArray *array1 = value1->data[0].v_pointer; PikaArray *array2 = value2->data[0].v_pointer; /* try to return at least *something*, it's useless anyway... */ if (! array1) return array2 != NULL ? -1 : 0; else if (! array2) return array1 != NULL ? 1 : 0; else if (array1->length < array2->length) return -1; else if (array1->length > array2->length) return 1; return 0; } /** * pika_param_spec_array: * @name: Canonical name of the property specified. * @nick: Nick name of the property specified. * @blurb: Description of the property specified. * @flags: Flags for the property specified. * * Creates a new #PikaParamSpecArray specifying a * [type@Array] property. * * See g_param_spec_internal() for details on property names. * * Returns: (transfer full): The newly created #PikaParamSpecArray. * * Since: 3.0 **/ GParamSpec * pika_param_spec_array (const gchar *name, const gchar *nick, const gchar *blurb, GParamFlags flags) { PikaParamSpecArray *array_spec; array_spec = g_param_spec_internal (PIKA_TYPE_PARAM_ARRAY, name, nick, blurb, flags); return G_PARAM_SPEC (array_spec); } static const guint8 * pika_value_get_array (const GValue *value) { PikaArray *array = value->data[0].v_pointer; if (array) return array->data; return NULL; } static guint8 * pika_value_dup_array (const GValue *value) { PikaArray *array = value->data[0].v_pointer; if (array) return g_memdup2 (array->data, array->length); return NULL; } static void pika_value_set_array (GValue *value, const guint8 *data, gsize length) { PikaArray *array = pika_array_new (data, length, FALSE); g_value_take_boxed (value, array); } static void pika_value_set_static_array (GValue *value, const guint8 *data, gsize length) { PikaArray *array = pika_array_new (data, length, TRUE); g_value_take_boxed (value, array); } static void pika_value_take_array (GValue *value, guint8 *data, gsize length) { PikaArray *array = pika_array_new (data, length, TRUE); array->static_data = FALSE; g_value_take_boxed (value, array); } /* * PIKA_TYPE_INT32_ARRAY */ typedef PikaArray PikaInt32Array; G_DEFINE_BOXED_TYPE (PikaInt32Array, pika_int32_array, pika_array_copy, pika_array_free) /* * PIKA_TYPE_PARAM_INT32_ARRAY */ static void pika_param_int32_array_class_init (GParamSpecClass *klass); static void pika_param_int32_array_init (GParamSpec *pspec); GType pika_param_int32_array_get_type (void) { static GType type = 0; if (! type) { const GTypeInfo info = { sizeof (GParamSpecClass), NULL, NULL, (GClassInitFunc) pika_param_int32_array_class_init, NULL, NULL, sizeof (PikaParamSpecInt32Array), 0, (GInstanceInitFunc) pika_param_int32_array_init }; type = g_type_register_static (PIKA_TYPE_PARAM_ARRAY, "PikaParamInt32Array", &info, 0); } return type; } static void pika_param_int32_array_class_init (GParamSpecClass *klass) { klass->value_type = PIKA_TYPE_INT32_ARRAY; } static void pika_param_int32_array_init (GParamSpec *pspec) { } /** * pika_param_spec_int32_array: * @name: Canonical name of the property specified. * @nick: Nick name of the property specified. * @blurb: Description of the property specified. * @flags: Flags for the property specified. * * Creates a new #PikaParamSpecInt32Array specifying a * %PIKA_TYPE_INT32_ARRAY property. * * See g_param_spec_internal() for details on property names. * * Returns: (transfer full): The newly created #PikaParamSpecInt32Array. * * Since: 3.0 **/ GParamSpec * pika_param_spec_int32_array (const gchar *name, const gchar *nick, const gchar *blurb, GParamFlags flags) { PikaParamSpecArray *array_spec; array_spec = g_param_spec_internal (PIKA_TYPE_PARAM_INT32_ARRAY, name, nick, blurb, flags); return G_PARAM_SPEC (array_spec); } /** * pika_value_get_int32_array: * @value: A valid value of type %PIKA_TYPE_INT32_ARRAY * * Gets the contents of a %PIKA_TYPE_INT32_ARRAY #GValue * * Returns: (transfer none) (array): The contents of @value */ const gint32 * pika_value_get_int32_array (const GValue *value) { g_return_val_if_fail (PIKA_VALUE_HOLDS_INT32_ARRAY (value), NULL); return (const gint32 *) pika_value_get_array (value); } /** * pika_value_dup_int32_array: * @value: A valid value of type %PIKA_TYPE_INT32_ARRAY * * Gets the contents of a %PIKA_TYPE_INT32_ARRAY #GValue * * Returns: (transfer full) (array): The contents of @value */ gint32 * pika_value_dup_int32_array (const GValue *value) { g_return_val_if_fail (PIKA_VALUE_HOLDS_INT32_ARRAY (value), NULL); return (gint32 *) pika_value_dup_array (value); } /** * pika_value_set_int32_array: * @value: A valid value of type %PIKA_TYPE_INT32_ARRAY * @data: (array length=length): A #gint32 array * @length: The number of elements in @data * * Sets the contents of @value to @data. */ void pika_value_set_int32_array (GValue *value, const gint32 *data, gsize length) { g_return_if_fail (PIKA_VALUE_HOLDS_INT32_ARRAY (value)); pika_value_set_array (value, (const guint8 *) data, length * sizeof (gint32)); } /** * pika_value_set_static_int32_array: * @value: A valid value of type %PIKA_TYPE_INT32_ARRAY * @data: (array length=length): A #gint32 array * @length: The number of elements in @data * * Sets the contents of @value to @data, without copying the data. */ void pika_value_set_static_int32_array (GValue *value, const gint32 *data, gsize length) { g_return_if_fail (PIKA_VALUE_HOLDS_INT32_ARRAY (value)); pika_value_set_static_array (value, (const guint8 *) data, length * sizeof (gint32)); } /** * pika_value_take_int32_array: * @value: A valid value of type %PIKA_TYPE_int32_ARRAY * @data: (transfer full) (array length=length): A #gint32 array * @length: The number of elements in @data * * Sets the contents of @value to @data, and takes ownership of @data. */ void pika_value_take_int32_array (GValue *value, gint32 *data, gsize length) { g_return_if_fail (PIKA_VALUE_HOLDS_INT32_ARRAY (value)); pika_value_take_array (value, (guint8 *) data, length * sizeof (gint32)); } /* * PIKA_TYPE_FLOAT_ARRAY */ typedef PikaArray PikaFloatArray; G_DEFINE_BOXED_TYPE (PikaFloatArray, pika_float_array, pika_array_copy, pika_array_free) /* * PIKA_TYPE_PARAM_FLOAT_ARRAY */ static void pika_param_float_array_class_init (GParamSpecClass *klass); static void pika_param_float_array_init (GParamSpec *pspec); GType pika_param_float_array_get_type (void) { static GType type = 0; if (! type) { const GTypeInfo info = { sizeof (GParamSpecClass), NULL, NULL, (GClassInitFunc) pika_param_float_array_class_init, NULL, NULL, sizeof (PikaParamSpecFloatArray), 0, (GInstanceInitFunc) pika_param_float_array_init }; type = g_type_register_static (PIKA_TYPE_PARAM_ARRAY, "PikaParamFloatArray", &info, 0); } return type; } static void pika_param_float_array_class_init (GParamSpecClass *klass) { klass->value_type = PIKA_TYPE_FLOAT_ARRAY; } static void pika_param_float_array_init (GParamSpec *pspec) { } /** * pika_param_spec_float_array: * @name: Canonical name of the property specified. * @nick: Nick name of the property specified. * @blurb: Description of the property specified. * @flags: Flags for the property specified. * * Creates a new #PikaParamSpecFloatArray specifying a * %PIKA_TYPE_FLOAT_ARRAY property. * * See g_param_spec_internal() for details on property names. * * Returns: (transfer full): The newly created #PikaParamSpecFloatArray. * * Since: 3.0 **/ GParamSpec * pika_param_spec_float_array (const gchar *name, const gchar *nick, const gchar *blurb, GParamFlags flags) { PikaParamSpecArray *array_spec; array_spec = g_param_spec_internal (PIKA_TYPE_PARAM_FLOAT_ARRAY, name, nick, blurb, flags); return G_PARAM_SPEC (array_spec); } /** * pika_value_get_float_array: * @value: A valid value of type %PIKA_TYPE_FLOAT_ARRAY * * Gets the contents of a %PIKA_TYPE_FLOAT_ARRAY #GValue * * Returns: (transfer none) (array): The contents of @value */ const gdouble * pika_value_get_float_array (const GValue *value) { g_return_val_if_fail (PIKA_VALUE_HOLDS_FLOAT_ARRAY (value), NULL); return (const gdouble *) pika_value_get_array (value); } /** * pika_value_dup_float_array: * @value: A valid value of type %PIKA_TYPE_FLOAT_ARRAY * * Gets the contents of a %PIKA_TYPE_FLOAT_ARRAY #GValue * * Returns: (transfer full) (array): The contents of @value */ gdouble * pika_value_dup_float_array (const GValue *value) { g_return_val_if_fail (PIKA_VALUE_HOLDS_FLOAT_ARRAY (value), NULL); return (gdouble *) pika_value_dup_array (value); } /** * pika_value_set_float_array: * @value: A valid value of type %PIKA_TYPE_FLOAT_ARRAY * @data: (array length=length): A #gfloat array * @length: The number of elements in @data * * Sets the contents of @value to @data. */ void pika_value_set_float_array (GValue *value, const gdouble *data, gsize length) { g_return_if_fail (PIKA_VALUE_HOLDS_FLOAT_ARRAY (value)); pika_value_set_array (value, (const guint8 *) data, length * sizeof (gdouble)); } /** * pika_value_set_static_float_array: * @value: A valid value of type %PIKA_TYPE_FLOAT_ARRAY * @data: (array length=length): A #gfloat array * @length: The number of elements in @data * * Sets the contents of @value to @data, without copying the data. */ void pika_value_set_static_float_array (GValue *value, const gdouble *data, gsize length) { g_return_if_fail (PIKA_VALUE_HOLDS_FLOAT_ARRAY (value)); pika_value_set_static_array (value, (const guint8 *) data, length * sizeof (gdouble)); } /** * pika_value_take_float_array: * @value: A valid value of type %PIKA_TYPE_FLOAT_ARRAY * @data: (transfer full) (array length=length): A #gfloat array * @length: The number of elements in @data * * Sets the contents of @value to @data, and takes ownership of @data. */ void pika_value_take_float_array (GValue *value, gdouble *data, gsize length) { g_return_if_fail (PIKA_VALUE_HOLDS_FLOAT_ARRAY (value)); pika_value_take_array (value, (guint8 *) data, length * sizeof (gdouble)); } /* * PIKA_TYPE_RGB_ARRAY */ typedef PikaArray PikaRGBArray; G_DEFINE_BOXED_TYPE (PikaRGBArray, pika_rgb_array, pika_array_copy, pika_array_free) /* * PIKA_TYPE_PARAM_RGB_ARRAY */ static void pika_param_rgb_array_class_init (GParamSpecClass *klass); static void pika_param_rgb_array_init (GParamSpec *pspec); GType pika_param_rgb_array_get_type (void) { static GType type = 0; if (! type) { const GTypeInfo info = { sizeof (GParamSpecClass), NULL, NULL, (GClassInitFunc) pika_param_rgb_array_class_init, NULL, NULL, sizeof (PikaParamSpecRGBArray), 0, (GInstanceInitFunc) pika_param_rgb_array_init }; type = g_type_register_static (G_TYPE_PARAM_BOXED, "PikaParamRGBArray", &info, 0); } return type; } static void pika_param_rgb_array_class_init (GParamSpecClass *klass) { klass->value_type = PIKA_TYPE_RGB_ARRAY; } static void pika_param_rgb_array_init (GParamSpec *pspec) { } /** * pika_param_spec_rgb_array: * @name: Canonical name of the property specified. * @nick: Nick name of the property specified. * @blurb: Description of the property specified. * @flags: Flags for the property specified. * * Creates a new #PikaParamSpecRGBArray specifying a * %PIKA_TYPE_RGB_ARRAY property. * * See g_param_spec_internal() for details on property names. * * Returns: (transfer full): The newly created #PikaParamSpecRGBArray. * * Since: 3.0 **/ GParamSpec * pika_param_spec_rgb_array (const gchar *name, const gchar *nick, const gchar *blurb, GParamFlags flags) { PikaParamSpecRGBArray *array_spec; array_spec = g_param_spec_internal (PIKA_TYPE_PARAM_RGB_ARRAY, name, nick, blurb, flags); return G_PARAM_SPEC (array_spec); } /** * pika_value_get_rgb_array: * @value: A valid value of type %PIKA_TYPE_RGB_ARRAY * * Gets the contents of a %PIKA_TYPE_RGB_ARRAY #GValue * * Returns: (transfer none) (array): The contents of @value */ const PikaRGB * pika_value_get_rgb_array (const GValue *value) { g_return_val_if_fail (PIKA_VALUE_HOLDS_RGB_ARRAY (value), NULL); return (const PikaRGB *) pika_value_get_array (value); } /** * pika_value_dup_rgb_array: * @value: A valid value of type %PIKA_TYPE_RGB_ARRAY * * Gets the contents of a %PIKA_TYPE_RGB_ARRAY #GValue * * Returns: (transfer full) (array): The contents of @value */ PikaRGB * pika_value_dup_rgb_array (const GValue *value) { g_return_val_if_fail (PIKA_VALUE_HOLDS_RGB_ARRAY (value), NULL); return (PikaRGB *) pika_value_dup_array (value); } /** * pika_value_set_rgb_array: * @value: A valid value of type %PIKA_TYPE_RGB_ARRAY * @data: (array length=length): A #PikaRGB array * @length: The number of elements in @data * * Sets the contents of @value to @data. */ void pika_value_set_rgb_array (GValue *value, const PikaRGB *data, gsize length) { g_return_if_fail (PIKA_VALUE_HOLDS_RGB_ARRAY (value)); pika_value_set_array (value, (const guint8 *) data, length * sizeof (PikaRGB)); } /** * pika_value_set_static_rgb_array: * @value: A valid value of type %PIKA_TYPE_RGB_ARRAY * @data: (array length=length): A #PikaRGB array * @length: The number of elements in @data * * Sets the contents of @value to @data, without copying the data. */ void pika_value_set_static_rgb_array (GValue *value, const PikaRGB *data, gsize length) { g_return_if_fail (PIKA_VALUE_HOLDS_RGB_ARRAY (value)); pika_value_set_static_array (value, (const guint8 *) data, length * sizeof (PikaRGB)); } /** * pika_value_take_rgb_array: * @value: A valid value of type %PIKA_TYPE_RGB_ARRAY * @data: (transfer full) (array length=length): A #PikaRGB array * @length: The number of elements in @data * * Sets the contents of @value to @data, and takes ownership of @data. */ void pika_value_take_rgb_array (GValue *value, PikaRGB *data, gsize length) { g_return_if_fail (PIKA_VALUE_HOLDS_RGB_ARRAY (value)); pika_value_take_array (value, (guint8 *) data, length * sizeof (PikaRGB)); } /* * PIKA_TYPE_OBJECT_ARRAY */ /** * pika_object_array_new: * @data: (array length=length) (transfer none): an array of objects. * @object_type: the array will hold objects of this type * @length: the length of @data. * @static_data: whether the objects in @data are static objects and don't * need to be copied. * * Creates a new #PikaObjectArray containing object pointers, of size @length. * * If @static_data is %TRUE, @data is used as-is. * * If @static_data is %FALSE, the object and array will be re-allocated, * hence you are expected to free your input data after. * * Returns: (transfer full): a new #PikaObjectArray. */ PikaObjectArray * pika_object_array_new (GType object_type, GObject **data, gsize length, gboolean static_data) { PikaObjectArray *array; g_return_val_if_fail (g_type_is_a (object_type, G_TYPE_OBJECT), NULL); g_return_val_if_fail ((data == NULL && length == 0) || (data != NULL && length > 0), NULL); array = g_slice_new0 (PikaObjectArray); array->object_type = object_type; if (! static_data && data) { GObject **tmp = g_new0 (GObject *, length); gsize i; for (i = 0; i < length; i++) tmp[i] = g_object_ref (data[i]); array->data = tmp; } else { array->data = data; } array->length = length; array->static_data = static_data; return array; } /** * pika_object_array_copy: * @array: an original #PikaObjectArray of objects. * * Creates a new #PikaObjectArray containing a deep copy of @array. * * Returns: (transfer full): a new #PikaObjectArray. **/ PikaObjectArray * pika_object_array_copy (const PikaObjectArray *array) { if (array) return pika_object_array_new (array->object_type, array->data, array->length, FALSE); return NULL; } void pika_object_array_free (PikaObjectArray *array) { if (array) { if (! array->static_data) { GObject **tmp = array->data; gsize i; for (i = 0; i < array->length; i++) g_object_unref (tmp[i]); g_free (array->data); } g_slice_free (PikaObjectArray, array); } } G_DEFINE_BOXED_TYPE (PikaObjectArray, pika_object_array, pika_object_array_copy, pika_object_array_free) /* * PIKA_TYPE_PARAM_OBJECT_ARRAY */ static void pika_param_object_array_class_init (GParamSpecClass *klass); static void pika_param_object_array_init (GParamSpec *pspec); static gboolean pika_param_object_array_validate (GParamSpec *pspec, GValue *value); static gint pika_param_object_array_values_cmp (GParamSpec *pspec, const GValue *value1, const GValue *value2); GType pika_param_object_array_get_type (void) { static GType type = 0; if (! type) { const GTypeInfo info = { sizeof (GParamSpecClass), NULL, NULL, (GClassInitFunc) pika_param_object_array_class_init, NULL, NULL, sizeof (PikaParamSpecObjectArray), 0, (GInstanceInitFunc) pika_param_object_array_init }; type = g_type_register_static (G_TYPE_PARAM_BOXED, "PikaParamObjectArray", &info, 0); } return type; } static void pika_param_object_array_class_init (GParamSpecClass *klass) { klass->value_type = PIKA_TYPE_OBJECT_ARRAY; klass->value_validate = pika_param_object_array_validate; klass->values_cmp = pika_param_object_array_values_cmp; } static void pika_param_object_array_init (GParamSpec *pspec) { } static gboolean pika_param_object_array_validate (GParamSpec *pspec, GValue *value) { PikaParamSpecObjectArray *array_spec = PIKA_PARAM_SPEC_OBJECT_ARRAY (pspec); PikaObjectArray *array = value->data[0].v_pointer; if (array) { gsize i; if ((array->data == NULL && array->length != 0) || (array->data != NULL && array->length == 0)) { g_value_set_boxed (value, NULL); return TRUE; } if (! g_type_is_a (array->object_type, array_spec->object_type)) { g_value_set_boxed (value, NULL); return TRUE; } for (i = 0; i < array->length; i++) { if (array->data[i] && ! g_type_is_a (G_OBJECT_TYPE (array->data[i]), array_spec->object_type)) { g_value_set_boxed (value, NULL); return TRUE; } } } return FALSE; } static gint pika_param_object_array_values_cmp (GParamSpec *pspec, const GValue *value1, const GValue *value2) { PikaObjectArray *array1 = value1->data[0].v_pointer; PikaObjectArray *array2 = value2->data[0].v_pointer; /* try to return at least *something*, it's useless anyway... */ if (! array1) return array2 != NULL ? -1 : 0; else if (! array2) return array1 != NULL ? 1 : 0; else if (array1->length < array2->length) return -1; else if (array1->length > array2->length) return 1; return 0; } /** * pika_param_spec_object_array: * @name: Canonical name of the property specified. * @nick: Nick name of the property specified. * @blurb: Description of the property specified. * @object_type: GType of the array's elements. * @flags: Flags for the property specified. * * Creates a new #PikaParamSpecObjectArray specifying a * [type@ObjectArray] property. * * See g_param_spec_internal() for details on property names. * * Returns: (transfer full): The newly created #PikaParamSpecObjectArray. * * Since: 3.0 **/ GParamSpec * pika_param_spec_object_array (const gchar *name, const gchar *nick, const gchar *blurb, GType object_type, GParamFlags flags) { PikaParamSpecObjectArray *array_spec; g_return_val_if_fail (g_type_is_a (object_type, G_TYPE_OBJECT), NULL); array_spec = g_param_spec_internal (PIKA_TYPE_PARAM_OBJECT_ARRAY, name, nick, blurb, flags); g_return_val_if_fail (array_spec, NULL); array_spec->object_type = object_type; return G_PARAM_SPEC (array_spec); } /** * pika_value_get_object_array: * @value: a #GValue holding a object #PikaObjectArray. * * Returns: (transfer none): the internal array of objects. */ GObject ** pika_value_get_object_array (const GValue *value) { PikaObjectArray *array; g_return_val_if_fail (PIKA_VALUE_HOLDS_OBJECT_ARRAY (value), NULL); array = value->data[0].v_pointer; if (array) return array->data; return NULL; } /** * pika_value_dup_object_array: * @value: a #GValue holding a object #PikaObjectArray. * * Returns: (transfer full): a deep copy of the array of objects. */ GObject ** pika_value_dup_object_array (const GValue *value) { PikaObjectArray *array; g_return_val_if_fail (PIKA_VALUE_HOLDS_OBJECT_ARRAY (value), NULL); array = value->data[0].v_pointer; if (array) { GObject **ret = g_memdup2 (array->data, (array->length) * sizeof (GObject *)); gsize i; for (i = 0; i < array->length; i++) g_object_ref (ret[i]); return ret; } return NULL; } /** * pika_value_set_object_array: * @value: A valid value of type %PIKA_TYPE_OBJECT_ARRAY * @object_type: The #GType of the object elements * @data: (array length=length): A #GObject array * @length: The number of elements in @data * * Sets the contents of @value to @data. */ void pika_value_set_object_array (GValue *value, GType object_type, GObject **data, gsize length) { PikaObjectArray *array; g_return_if_fail (PIKA_VALUE_HOLDS_OBJECT_ARRAY (value)); g_return_if_fail (g_type_is_a (object_type, G_TYPE_OBJECT)); array = pika_object_array_new (object_type, data, length, FALSE); g_value_take_boxed (value, array); } /** * pika_value_set_static_object_array: * @value: A valid value of type %PIKA_TYPE_OBJECT_ARRAY * @object_type: The #GType of the object elements * @data: (array length=length): A #GObject array * @length: The number of elements in @data * * Sets the contents of @value to @data, without copying the data. */ void pika_value_set_static_object_array (GValue *value, GType object_type, GObject **data, gsize length) { PikaObjectArray *array; g_return_if_fail (PIKA_VALUE_HOLDS_OBJECT_ARRAY (value)); g_return_if_fail (g_type_is_a (object_type, G_TYPE_OBJECT)); array = pika_object_array_new (object_type, data, length, TRUE); g_value_take_boxed (value, array); } /** * pika_value_take_object_array: * @value: A valid value of type %PIKA_TYPE_OBJECT_ARRAY * @object_type: The #GType of the object elements * @data: (transfer full) (array length=length): A #GObject array * @length: The number of elements in @data * * Sets the contents of @value to @data, and takes ownership of @data. */ void pika_value_take_object_array (GValue *value, GType object_type, GObject **data, gsize length) { PikaObjectArray *array; g_return_if_fail (PIKA_VALUE_HOLDS_OBJECT_ARRAY (value)); g_return_if_fail (g_type_is_a (object_type, G_TYPE_OBJECT)); array = pika_object_array_new (object_type, data, length, TRUE); array->static_data = FALSE; g_value_take_boxed (value, array); }