/* gproperty.c: Property definitions for GObject * * Copyright © 2012 Emmanuele Bassi * * 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 2 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, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307, USA. */ /** * SECTION:gproperty * @Title: GProperty * @Short_Desc: Property definitions for GObject * * #GProperty is a type of #GParamSpec for defining properties for #GObject. * * The main difference between #GProperty and #GParamSpec is that #GProperty * enforces a specific set of best practices for accessing values exposed * as #GObject properties. * * #GProperty uses direct access to the fields in the instance private data * structure whenever possible, and allows specifying accessor functions in * cases where it is necessary. For direct access to the private structure * members, #GProperty will assume that the instance structure contains a * pointer to the private data structure as its last member, e.g.: * * |[ * typedef struct _TestObject TestObject; * typedef struct _TestObjectPrivate TestObjectPrivate; * * struct _TestObject * { * GObject parent_instance; * * TestObjectPrivate *priv; * }; * ]| * * #GProperty is strongly typed, both at compilation time and at run time. * * Unlike #GParamSpec, there is a single public #GProperty class with various * constructors; all public #GProperty methods operate depending on the type * handled by the #GProperty. * * The #GParamSpec methods can be used with #GProperty transparently, to * allow backward compatibility with existing code that introspects #GObject * properties through the #GParamSpec API. * * * Using GProperty * A typical example of #GProperty usage is: * * |[ * /* the private data structure */ * struct _TestObjectPrivate * { * int x; * int y; * int width; * int height; * }; * * /* identifiers for each property in the array */ * enum { PROP_0, PROP_X, PROP_Y, PROP_WIDTH, PROP_HEIGHT, LAST_PROP }; * * /* an array of properties */ * static GParamSpec *test_object_properties[LAST_PROP] = { 0, }; * * static void * test_object_class_init (TestObjectClass *klass) * { * g_type_class_add_private (klass, sizeof (TestObjectPrivate)); * * test_object_properties[PROP_X] = * g_int_property_new ("x", G_PROPERTY_READWRITE, * G_STRUCT_OFFSET (TestObjectPrivate, x), * NULL, * NULL); * * test_object_properties[PROP_Y] = * g_int_property_new ("y", G_PROPERTY_READWRITE, * G_STRUCT_OFFSET (TestObjectPrivate, y), * NULL, * NULL); * * test_object_properties[PROP_WIDTH] = * g_int_property_new ("width", G_PROPERTY_READWRITE, * G_STRUCT_OFFSET (TestObjectPrivate, width), * NULL, * NULL); * * test_object_properties[PROP_HEIGHT] = * g_int_property_new ("height", G_PROPERTY_READWRITE, * G_STRUCT_OFFSET (TestObjectPrivate, height), * NULL, * NULL); * * g_object_class_install_properties (G_OBJECT_CLASS (klass), * G_N_ELEMENTS (test_object_properties), * test_object_properties); * } * ]| * The main differences with the #GParamSpec creation and installation * code are: * * * the constructors take the same parameters * there are not #GObject set_property and get_property * virtual function assignments * all properties use direct access of the member in the * instance private data structure * * * * Setting and getting values * Writing accessors for properties defined using #GProperties is * a simple case of calling g_property_set() or g_property_get(), for * instance the code below is the simplest form of setter and getter * pair for the "x" property as defined above: * |[ * void * test_object_set_x (TestObject *self, * int x) * { * g_return_if_fail (TEST_IS_OBJECT (self)); * * g_property_set (G_PROPERTY (test_object_properties[PROP_X]), self, x); * } * * int * test_object_get_x (TestObject *self) * { * int retval; * * g_return_val_if_fail (TEST_IS_OBJECT (self), 0); * * g_property_get (G_PROPERTY (test_object_properties[PROP_X]), * self, * &retval); * * return retval; * } * ]| * Note that calling g_property_set() for a property holding a * complex type (e.g. #GObject or #GBoxed) without a specific setter * function will, by default, result in the pointer to the new value * being copied in the private data structure's field; if you need to * copy a boxed type, or take a reference on an object type, you will * need to set the %G_PROPERTY_COPY_SET flag when creating the * property. * * Calling g_property_get() will return a pointer to the private * data structure's field, unless %G_PROPERTY_COPY_GET is set when * creating the property, in which case the returned value will either * be a copy of the private data structure field if it is a boxed type * or the instance with its reference count increased if it is an object * type. * * * * Ranges and validation * For different property types it is possible to set a range of * valid values; the setter function can then use g_property_validate() * to check whether the new value is valid. * * The range is set using g_property_set_range(): * * |[ * test_object_properties[PROP_WIDTH] = * g_int_property_new ("width", G_PROPERTY_READWRITE, * G_STRUCT_OFFSET (TestObjectPrivate, width), * NULL, NULL); * g_property_set_range (G_PROPERTY (test_object_properties[PROP_WIDTH]), * 0.0, /* minimum value */ * G_MAXINT /* maximum value */) * * test_object_properties[PROP_HEIGHT] = * g_int_property_new ("height", G_PROPERTY_READWRITE, * G_STRUCT_OFFSET (TestObjectPrivate, height), * NULL, NULL); * g_property_set_range (G_PROPERTY (test_object_properties[PROP_HEIGHT]), * 0.0, /* minimum value */ * G_MAXINT /* maximum value */) * ]| * * The example above keeps the "width" and "height" properties as * integers, but limits the range of valid values to [ 0, %G_MAXINT ]. * * Validation is automatically performed when setting a property * through g_property_set(); explicit setter methods can use g_property_validate() * to perform the validation, e.g.: * * |[ * void * test_object_set_width (TestObject *self, * int width) * { * GProperty *property; * * property = G_PROPERTY (test_object_properties[PROP_WIDTH]); * * g_return_if_fail (!g_property_validate (property, width)); * * /* we deliberately do not use g_property_set() here because * * g_property_set() will implicitly call g_property_validate() * * prior to setting the property * */ * if (self->priv->width == width) * return; * * self->priv->width = width; * * g_object_notify_by_pspec (G_OBJECT (self), G_PARAM_SPEC (property)); * * test_object_queue_foo (self); * } * ]| * * * * Default values * Default values are declared using g_property_set_default(), e.g.: * |[ * test_object_properties[PROP_WIDTH] = * g_int_property_new ("width", G_PROPERTY_READWRITE, * G_STRUCT_OFFSET (TestObjectPrivate, width), * NULL, NULL); * g_property_set_range (G_PROPERTY (test_object_properties[PROP_WIDTH]), * 0, /* minimum value */ * G_MAXINT /* maximum value */) * g_property_set_default (G_PROPERTY (test_object_properties[PROP_WIDTH]), * G_OBJECT_CLASS (klass), * 1); * * test_object_properties[PROP_HEIGHT] = * g_int_property_new ("height", G_PROPERTY_READWRITE, * G_STRUCT_OFFSET (TestObjectPrivate, height), * NULL, NULL); * g_property_set_range (G_PROPERTY (test_object_properties[PROP_HEIGHT]), * 0, /* minimum value */ * G_MAXINT /* maximum value */) * g_property_set_default (G_PROPERTY (test_object_properties[PROP_HEIGHT]), * G_OBJECT_CLASS (klass), * 1); * ]| * * Sub-classes can use g_property_override_default() on an existing property * of their parent classes to override the default value: * * |[ * property = g_object_class_find_property (G_OBJECT_CLASS (klass), "width"); * g_property_override_default (G_PROPERTY (property), * G_OBJECT_CLASS (klass), * 200); * ]| * * The default value can be retrieved using g_property_get_default(), * for instance during instance initialization: * * |[ * static void * test_object_init (TestObject *self) * { * self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TEST_TYPE_OBJECT, * TestObjectPrivate); * * g_property_get_default (G_PROPERTY (test_object_properties[PROP_WIDTH]), * self, * &(self->priv->width)); * g_property_get_default (G_PROPERTY (test_object_properties[PROP_HEIGHT]), * self, * &(self->priv->height)); * } * ]| * * or to return the default value when writing a getter: * * |[ * int * test_object_get_width (TestObject *self) * { * GProperty *property; * int retval; * * property = G_PROPERTY (test_object_properties[PROP_WIDTH]); * * /* return the default width if self has not been foobarized */ * if (!self->priv->is_foobarized) * g_property_get_default (property, self, &retval); * else * g_property_get (property, self, &retval); * * return retval; * } * ]| * * The reason why the object instance is necessary when calling * g_property_get_default() is to retrieve the correct default for the * given instance type, in case sub-classes overridden the default value * using g_property_override_default(). * * * * Custom accessors * For cases where the direct access to a structure field does not * match the semantics of the property it is possible to pass a setter * and a getter function when creating a #GProperty: * * |[ * test_object_property[PROP_COMPLEX] = * g_object_property_new ("complex", G_PROPERTY_READWRITE, -1, * test_object_set_complex, * test_object_get_complex); * g_property_set_prerequisite (G_PROPERTY (test_object_property[PROP_COMPLEX]), * TEST_TYPE_COMPLEX); * ]| * * The accessors can be public or private functions. The implementation * of an explicit setter will be called under the #GProperty lock if the * property is declared using the %G_PROPERTY_ATOMIC flag; the setter should * not notify the property on changes, and should return %TRUE if the value * was modified. An example of a setter is: * * |[ * static gboolean * test_object_set_complex (gpointer self_, * gpointer value_) * { * TestObject *self = self_; * TestComplex *value = value_; * * if (self->priv->complex == value) * return FALSE; * * if (self->priv->complex != NULL) * { * test_complex_set_back_pointer (self->priv->complex, NULL); * g_object_unref (self->priv->complex); * } * * self->priv->complex = value; * * if (self->priv->complex != NULL) * { * g_object_ref (self->priv->complex); * test_complex_set_back_pointer (self->priv->complex, self); * } * * test_object_queue_foo (self); * * return TRUE; * } * ]| * * It is also possible to still pass the offset of the structure * field, and provide either the setter or the getter function: * * |[ * test_object_property[PROP_WIDTH] = * g_int_property_new ("width", G_PROPERTY_READWRITE | G_PROPERTY_COPY_SET, * G_STRUCT_OFFSET (TestObjectPrivate, width), * test_object_set_width, /* explicit setter */ * NULL /* implicit getter */); * ]| * * Calling g_property_set() using the "width" property in the example * above will result in calling test_object_set_width(); calling, instead, * g_property_get() using the "width" property will result in accessing * the width structure member. * * You must not call g_property_set() inside the implementation * of test_object_set_width(), in order to avoid loops. * * * * Special flags * #GProperty has its own set of flags to be passed to its * constructor functions. Alongside the usual %G_PROPERTY_READABLE * and %G_PROPERTY_WRITABLE, which control the access policy for * setter and getter functions, there are the following flags: * * * %G_PROPERTY_DEPRECATED, a flag for marking * deprecated properties. If the G_ENABLE_DIAGNOSTIC environment * variable is set, calling g_property_set() and g_property_get() * on the deprecated properties will result in a run time warning * printed on the console. * %G_PROPERTY_ATOMIC, a flag for marking access * to properties a threadsafe operation. It is possible to change * the locking mechanism by using g_property_set_lock_functions() * and replacing both the lock and the unlock function, which can * then be called by g_property_lock() and g_property_unlock() * when needed. * * * * * * * Auto-generating setters and getters * Similarly to the #G_DEFINE_TYPE macro for defining a new * #GObject type, GObject also provides various macros for * auto-generating the accessors pair of functions. * The most simple way to define a setter and getter pair is * to use the #G_DEFINE_PROPERTY_GET_SET macro. This macro generates * a getter and a setter using the type name, the type of the * property and the name of the property, for instance: * * |[ * G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, int, x) * G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, int, y) * G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, int, width) * G_DEFINE_PROPERTY_GET_SET (TestObject, test_object, int, height) * ]| * * The generated accessor pairs will use the #GProperty API * to validate and access the property value. It is also possible * to separate the setter and getter generation by using the * #G_DEFINE_PROPERTY_GET and #G_DEFINE_PROPERTY_SET macros. * * If either the setter or the getter functions require additional * custom code to be added to the auto-generated one, it is possible to * use the #G_DEFINE_PROPERTY_GET_WITH_CODE macro and its sibling, the * #G_DEFINE_PROPERTY_SET_WITH_CODE macro, for instance: * * |[ * G_DEFINE_PROPERTY_GET (TestObject, test_object, int, width) * G_DEFINE_PROPERTY_SET_WITH_CODE (Test_object, test_object, int, width, * test_object_queue_action (self)) * ]| * * The WITH_CODE variant of the setter will define the "self" and * "value" variables for the instance and the new value respectively; the * custom code will be executed only after the value has been set. * For the WITH_CODE variant of the getter, the macro will define the * "self" and "retval" variables for the instance and the returned value * respectively; the custom code will be executed before retrieving the * value of the property to be returned. * * * * Base object class using GProperty * The example below shows how to use #GProperty and the code * generation macros to implement a simple base class called * "TestFile". * * * FIXME: MISSING XINCLUDE CONTENT * * * * * * Derived object class using GProperty * The example below shows how to use #GProperty and the code * generation macros to implement a simple base class called * "TestFile" and a derived class called "TestFileMp3". * * * FIXME: MISSING XINCLUDE CONTENT * * * */ #include "config.h" #include #include "gproperty.h" #include "gvaluecollector.h" #include "gparam.h" #include "gtype.h" #include "gvalue.h" #include "gvaluetypes.h" struct _GProperty { GParamSpec parent_instance; guint flags : 15; guint is_installed : 1; guint16 type_size; guint16 priv_offset; guint16 field_offset; GQuark prop_id; GPropertyLockFunc lock_func; GPropertyUnlockFunc unlock_func; }; /* defines for the integer sub-types we don't have */ #define g_value_get_int8 g_value_get_int #define g_value_get_int16 g_value_get_int #define g_value_get_int32 g_value_get_int #define g_value_get_uint8 g_value_get_uint #define g_value_get_uint16 g_value_get_uint #define g_value_get_uint32 g_value_get_uint #define DEFINE_PROPERTY_INTEGER(G_t, g_t, c_t, G_T, defVal, minVal, maxVal) \ typedef struct { \ GProperty parent; \ \ c_t min_value; \ c_t max_value; \ \ GProperty##G_t##Set setter; \ GProperty##G_t##Get getter; \ } G##G_t##Property; \ \ static gint \ property_##g_t##_values_cmp (GParamSpec *pspec, \ const GValue *value_a, \ const GValue *value_b) \ { \ c_t val_a = g_value_get_##g_t (value_a); \ c_t val_b = g_value_get_##g_t (value_b); \ \ if (val_a < val_b) \ return -1; \ \ if (val_a > val_b) \ return 1; \ \ return 0; \ } \ \ static gboolean \ property_##g_t##_validate (GParamSpec *pspec, \ GValue *value) \ { \ G##G_t##Property *internal = (G##G_t##Property *) pspec; \ c_t oval = g_value_get_##g_t (value); \ c_t nval = oval; \ \ nval = CLAMP (nval, internal->min_value, internal->max_value); \ \ return nval != oval; \ } \ \ static void \ property_##g_t##_class_init (GParamSpecClass *klass) \ { \ klass->value_type = G_T; \ \ klass->value_validate = property_##g_t##_validate; \ klass->values_cmp = property_##g_t##_values_cmp; \ } \ \ static void \ property_##g_t##_init (GParamSpec *pspec) \ { \ G##G_t##Property *property = (G##G_t##Property *) pspec; \ \ property->min_value = minVal; \ property->max_value = maxVal; \ } \ \ GType _g_##g_t##_property_get_type (void); /* forward declaration for -Wmissing-prototypes */ \ \ GType \ _g_##g_t##_property_get_type (void) \ { \ static volatile gsize pspec_type_id__volatile = 0; \ \ if (g_once_init_enter (&pspec_type_id__volatile)) \ { \ const GTypeInfo info = { \ sizeof (GParamSpecClass), \ NULL, NULL, \ (GClassInitFunc) property_##g_t##_class_init, \ NULL, NULL, \ sizeof (G##G_t##Property), \ 0, \ (GInstanceInitFunc) property_##g_t##_init, \ }; \ \ GType pspec_type_id = \ g_type_register_static (G_TYPE_PROPERTY, \ g_intern_static_string ("G" #G_t "Property"), \ &info, 0); \ \ g_once_init_leave (&pspec_type_id__volatile, pspec_type_id); \ } \ \ return pspec_type_id__volatile; \ } \ \ GParamSpec * \ g_##g_t##_property_new (const gchar *name, \ GPropertyFlags flags, \ gssize offset, \ GProperty##G_t##Set setter, \ GProperty##G_t##Get getter) \ { \ GProperty *prop; \ G##G_t##Property *internal; \ \ g_return_val_if_fail (name != NULL, NULL); \ \ if (setter == NULL && getter == NULL) \ g_return_val_if_fail (offset >= 0, NULL); \ if (setter == NULL) \ flags |= G_PROPERTY_DIRECT_SET; \ if (getter == NULL) \ flags |= G_PROPERTY_DIRECT_GET; \ \ prop = g_param_spec_internal (_g_##g_t##_property_get_type (), \ name, NULL, NULL, \ property_flags_to_param_flags (flags)); \ \ prop->flags = flags; \ \ G_PARAM_SPEC (prop)->value_type = G_T; \ \ prop->field_offset = offset; \ \ prop->is_installed = FALSE; \ \ prop->type_size = sizeof (c_t); \ \ internal = (G##G_t##Property *) prop; \ internal->setter = setter; \ internal->getter = getter; \ \ return G_PARAM_SPEC (prop); \ } \ \ static inline void \ g_##g_t##_property_set_range (GProperty *property, \ c_t min_value, \ c_t max_value) \ { \ if (min_value > max_value) \ { \ g_critical (G_STRLOC ": Invalid range for " #g_t " property '%s'", \ G_PARAM_SPEC (property)->name); \ return; \ } \ \ ((G##G_t##Property *) property)->min_value = min_value; \ ((G##G_t##Property *) property)->max_value = max_value; \ } \ \ static inline void \ g_##g_t##_property_get_range (GProperty *property, \ c_t *min_value, \ c_t *max_value) \ { \ *min_value = ((G##G_t##Property *) property)->min_value; \ *max_value = ((G##G_t##Property *) property)->max_value; \ } \ \ static inline gboolean \ g_##g_t##_property_validate (GProperty *property, \ c_t value) \ { \ G##G_t##Property *internal = (G##G_t##Property *) property; \ \ if (value >= internal->min_value && \ value <= internal->max_value) \ return TRUE; \ \ return FALSE; \ } \ \ static inline gboolean \ g_##g_t##_property_set_value (GProperty *property, \ gpointer gobject, \ c_t value) \ { \ gboolean retval; \ \ if ((property->flags & G_PROPERTY_WRITABLE) == 0) \ { \ g_critical ("The property '%s' of object '%s' is not writable", \ G_PARAM_SPEC (property)->name, \ G_OBJECT_TYPE_NAME (gobject)); \ return FALSE; \ } \ \ if (!g_##g_t##_property_validate (property, value)) \ { \ g_warning ("The value for the property '%s' of object '%s' is out of the valid range", \ G_PARAM_SPEC (property)->name, \ G_OBJECT_TYPE_NAME (gobject)); \ return FALSE; \ } \ \ if (((G##G_t##Property *) property)->setter != NULL) \ { \ property_lock_internal (property, gobject); \ \ retval = ((G##G_t##Property *) property)->setter (gobject, value); \ \ property_unlock_internal (property, gobject); \ \ if (retval) \ g_object_notify_by_pspec (gobject, (GParamSpec *) property); \ } \ else if (property->field_offset >= 0) \ { \ gpointer priv_p, field_p; \ \ property_lock_internal (property, gobject); \ \ priv_p = get_private_pointer (gobject, property->priv_offset); \ field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); \ \ if ((* (c_t *) field_p) == value) \ { \ property_unlock_internal (property, gobject); \ return FALSE; \ } \ \ (* (c_t *) field_p) = value; \ \ property_unlock_internal (property, gobject); \ \ g_object_notify_by_pspec (gobject, (GParamSpec *) property); \ \ retval = TRUE; \ } \ else \ { \ g_critical (G_STRLOC ": No setter function or field offset specified " \ "for property '%s'", \ G_PARAM_SPEC (property)->name); \ \ retval = FALSE; \ } \ \ return retval; \ } \ \ static inline c_t \ g_##g_t##_property_get_value (GProperty *property, \ gpointer gobject) \ { \ if ((property->flags & G_PROPERTY_READABLE) == 0) \ { \ g_critical ("The property '%s' of object '%s' is not readable", \ G_PARAM_SPEC (property)->name, \ G_OBJECT_TYPE_NAME (gobject)); \ return FALSE; \ } \ \ if (((G##G_t##Property *) property)->getter != NULL) \ { \ return ((G##G_t##Property *) property)->getter (gobject); \ } \ else if (property->field_offset >= 0) \ { \ gpointer priv_p, field_p; \ \ priv_p = get_private_pointer (gobject, property->priv_offset); \ field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); \ \ return (* (c_t *) field_p); \ } \ else \ { \ g_critical (G_STRLOC ": No setter function or field offset specified " \ "for property '%s'", \ G_PARAM_SPEC (property)->name); \ return defVal; \ } \ } static void g_property_default_lock (GProperty *property, gpointer gobject) { gpointer bit_lock_p; bit_lock_p = g_object_get_qdata (gobject, property->prop_id); if (bit_lock_p == NULL) { bit_lock_p = g_new0 (gint, 1); g_object_set_qdata_full (gobject, property->prop_id, bit_lock_p, g_free); } g_bit_lock (bit_lock_p, 0); } static void g_property_default_unlock (GProperty *property, gpointer gobject) { gpointer bit_lock_p; bit_lock_p = g_object_get_qdata (gobject, property->prop_id); if (bit_lock_p == NULL) return; g_bit_unlock (bit_lock_p, 0); g_object_set_qdata (gobject, property->prop_id, NULL); } static inline void property_lock_internal (GProperty *property, gpointer gobject) { if (G_LIKELY ((property->flags & G_PROPERTY_ATOMIC) == 0)) return; if (property->lock_func != NULL) property->lock_func (property, gobject); else g_property_default_lock (property, gobject); } static inline void property_unlock_internal (GProperty *property, gpointer gobject) { if (G_LIKELY ((property->flags & G_PROPERTY_ATOMIC) == 0)) return; if (property->unlock_func != NULL) property->unlock_func (property, gobject); else g_property_default_unlock (property, gobject); } static inline gpointer get_private_pointer (gpointer instance, gssize offset) { gpointer priv_p; if (offset < 0) priv_p = g_type_instance_get_private (instance, G_OBJECT_TYPE (instance)); else priv_p = G_STRUCT_MEMBER_P (instance, offset); return priv_p; } static GParamFlags property_flags_to_param_flags (GPropertyFlags flags) { GParamFlags retval = 0; if (flags & G_PROPERTY_READABLE) retval |= G_PARAM_READABLE; if (flags & G_PROPERTY_WRITABLE) retval |= G_PARAM_WRITABLE; if (flags & G_PROPERTY_DEPRECATED) retval |= G_PARAM_DEPRECATED; return retval; } gpointer g_property_get_field (GProperty *property, gpointer gobject) { gpointer priv_p; g_return_val_if_fail (G_IS_PROPERTY (property), NULL); g_return_val_if_fail (G_IS_OBJECT (gobject), NULL); g_return_val_if_fail (property->field_offset >= 0, NULL); priv_p = get_private_pointer (gobject, property->priv_offset); if (priv_p == NULL) return NULL; return G_STRUCT_MEMBER_P (priv_p, property->field_offset); } /* forward declaration */ static void property_set_default (GParamSpec *pspec, GValue *value); static const GValue * property_get_default_for_type (GProperty *property, GType gtype) { GParamSpec *pspec = (GParamSpec *) property; if (gtype == G_TYPE_INVALID) { if (G_UNLIKELY (property->prop_id == 0)) { gchar *lock_name = g_strconcat ("__g_property_id_", pspec->name, NULL); property->prop_id = g_quark_from_string (lock_name); g_free (lock_name); } return g_param_spec_get_qdata (pspec, property->prop_id); } else return g_param_spec_get_qdata (pspec, g_type_qname (gtype)); } static void value_unset_and_free (gpointer data) { GValue *value = data; g_value_unset (value); g_free (value); } static inline void property_set_default_for_type (GProperty *property, GType gtype, GValue *value) { GParamSpec *pspec = (GParamSpec *) property; if (gtype == G_TYPE_INVALID) { if (G_UNLIKELY (property->prop_id == 0)) { gchar *lock_name = g_strconcat ("__g_property_id_", pspec->name, NULL); property->prop_id = g_quark_from_string (lock_name); g_free (lock_name); } if (g_param_spec_get_qdata (pspec, property->prop_id) != NULL) { g_critical (G_STRLOC ": The property '%s' already has a default " "value. Use g_property_override_default() instead.", pspec->name); return; } g_param_spec_set_qdata_full (pspec, property->prop_id, value, value_unset_and_free); } else g_param_spec_set_qdata_full (pspec, g_type_qname (gtype), value, value_unset_and_free); } /** * g_boolean_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property * @getter: (allow-none): the getter function for the property * * Creates a new #GProperty mapping to a boolean value. * * Return value: the newly created #GProperty * * Since: 2.36 */ DEFINE_PROPERTY_INTEGER (Boolean, boolean, gboolean, G_TYPE_BOOLEAN, FALSE, FALSE, TRUE) /** * g_int_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property, or %NULL * @getter: (allow-none): the getter function for the property, or %NULL * * Creates a new #GProperty mapping to an integer value. * * The default range of valid values is [ %G_MININT, %G_MAXINT ]. * * If you require a specific integer size, use g_int8_property_new(), * g_int16_property_new(), g_int32_property_new() or g_int64_property_new(). * * Return value: the newly created #GProperty * * Since: 2.36 */ DEFINE_PROPERTY_INTEGER (Int, int, int, G_TYPE_INT, 0, G_MININT, G_MAXINT) /** * g_int8_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property, or %NULL * @getter: (allow-none): the getter function for the property, or %NULL * * Creates a new #GProperty mapping to an 8 bits integer value. * * The default range of valid values is [ %G_MININT8, %G_MAXINT8 ]. * * Return value: the newly created #GProperty * * Since: 2.36 */ DEFINE_PROPERTY_INTEGER (Int8, int8, gint8, G_TYPE_INT, 0, G_MININT8, G_MAXINT8) /** * g_int16_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property, or %NULL * @getter: (allow-none): the getter function for the property, or %NULL * * Creates a new #GProperty mapping to a 16 bits integer value. * * The default range of valid values is [ %G_MININT16, %G_MAXINT16 ]. * * Return value: the newly created #GProperty * * Since: 2.36 */ DEFINE_PROPERTY_INTEGER (Int16, int16, gint16, G_TYPE_INT, 0, G_MININT16, G_MAXINT16) /** * g_int32_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property, or %NULL * @getter: (allow-none): the getter function for the property, or %NULL * * Creates a new #GProperty mapping to a 32 bits integer value. * * The default range of valid values is [ %G_MININT32, %G_MAXINT32 ]. * * Return value: the newly created #GProperty * * Since: 2.36 */ DEFINE_PROPERTY_INTEGER (Int32, int32, gint32, G_TYPE_INT, 0, G_MININT32, G_MAXINT32) /** * g_int64_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property, or %NULL * @getter: (allow-none): the getter function for the property, or %NULL * * Creates a new #GProperty mapping to a 64 bits integer value. * * The default range of valid values is [ %G_MININT64, %G_MAXINT64 ]. * * Return value: the newly created #GProperty * * Since: 2.36 */ DEFINE_PROPERTY_INTEGER (Int64, int64, gint64, G_TYPE_INT64, 0, G_MININT64, G_MAXINT64) /** * g_long_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property, or %NULL * @getter: (allow-none): the getter function for the property, or %NULL * * Creates a new #GProperty mapping to a long integer value. * * The default range of valid values is [ %G_MINLONG, %G_MAXLONG ]. * * Return value: the newly created #GProperty * * Since: 2.36 */ DEFINE_PROPERTY_INTEGER (Long, long, long, G_TYPE_LONG, 0, G_MINLONG, G_MAXLONG) /** * g_uint_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property, or %NULL * @getter: (allow-none): the getter function for the property, or %NULL * * Creates a new #GProperty mapping to an unsigned integer value. * * The default range of valid values is [ 0, %G_MAXUINT ]. * * If you require a specific integer size, use g_uint8_property_new(), * g_uint16_property_new(), g_uint32_property_new() or g_uint64_property_new(). * * Return value: the newly created #GProperty * * Since: 2.36 */ DEFINE_PROPERTY_INTEGER (UInt, uint, guint, G_TYPE_UINT, 0, 0, G_MAXUINT) /** * g_uint8_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property, or %NULL * @getter: (allow-none): the getter function for the property, or %NULL * * Creates a new #GProperty mapping to an unsigned 8 bits integer value. * * The default range of valid values is [ 0, %G_MAXUINT8 ]. * * Return value: the newly created #GProperty * * Since: 2.36 */ DEFINE_PROPERTY_INTEGER (UInt8, uint8, guint8, G_TYPE_UINT, 0, 0, G_MAXUINT8) /** * g_uint16_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property, or %NULL * @getter: (allow-none): the getter function for the property, or %NULL * * Creates a new #GProperty mapping to an unsigned 16 bits integer value. * * The default range of valid values is [ 0, %G_MAXUINT16 ]. * * Return value: the newly created #GProperty * * Since: 2.36 */ DEFINE_PROPERTY_INTEGER (UInt16, uint16, guint16, G_TYPE_UINT, 0, 0, G_MAXUINT16) /** * g_uint32_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property, or %NULL * @getter: (allow-none): the getter function for the property, or %NULL * * Creates a new #GProperty mapping to an unsigned 32 bits integer value. * * The default range of valid values is [ 0, %G_MAXUINT32 ]. * * Return value: the newly created #GProperty * * Since: 2.36 */ DEFINE_PROPERTY_INTEGER (UInt32, uint32, guint32, G_TYPE_UINT, 0, 0, G_MAXUINT32) /** * g_uint64_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property, or %NULL * @getter: (allow-none): the getter function for the property, or %NULL * * Creates a new #GProperty mapping to an unsigned 64 bits integer value. * * The default range of valid values is [ 0, %G_MAXUINT64 ]. * * Return value: the newly created #GProperty * * Since: 2.36 */ DEFINE_PROPERTY_INTEGER (UInt64, uint64, guint64, G_TYPE_UINT64, 0, 0, G_MAXUINT64) /** * g_ulong_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property, or %NULL * @getter: (allow-none): the getter function for the property, or %NULL * * Creates a new #GProperty mapping to an unsigned long integer value. * * The default range of valid values is [ 0, %G_MAXULONG ]. * * Return value: the newly created #GProperty * * Since: 2.36 */ DEFINE_PROPERTY_INTEGER (ULong, ulong, gulong, G_TYPE_ULONG, 0, 0, G_MAXULONG) /* * GEnum */ /* forward declaration for -Wmissing-prototypes */ GType _g_enum_property_get_type (void); typedef struct { GProperty parent; GEnumClass *e_class; GPropertyEnumSet setter; GPropertyEnumGet getter; } GEnumProperty; static gboolean property_enum_validate (GParamSpec *pspec, GValue *value) { GEnumProperty *property = (GEnumProperty *) pspec; glong oval = value->data[0].v_long; if (property->e_class == NULL || g_enum_get_value (property->e_class, value->data[0].v_long) == NULL) property_set_default (pspec, value); return value->data[0].v_long != oval; } static void property_enum_finalize (GParamSpec *pspec) { GEnumProperty *property = (GEnumProperty *) pspec; GParamSpecClass *parent_class = g_type_class_peek (g_type_parent (_g_enum_property_get_type ())); if (property->e_class) { g_type_class_unref (property->e_class); property->e_class = NULL; } parent_class->finalize (pspec); } static void property_enum_class_init (GParamSpecClass *klass) { klass->value_type = G_TYPE_FLAGS; klass->value_validate = property_enum_validate; klass->finalize = property_enum_finalize; } static void property_enum_init (GParamSpec *pspec) { } GType _g_enum_property_get_type (void) { static volatile gsize pspec_type_id__volatile = 0; if (g_once_init_enter (&pspec_type_id__volatile)) { const GTypeInfo info = { sizeof (GParamSpecClass), NULL, NULL, (GClassInitFunc) property_enum_class_init, NULL, NULL, sizeof (GEnumProperty), 0, (GInstanceInitFunc) property_enum_init, }; GType pspec_type_id = g_type_register_static (G_TYPE_PROPERTY, g_intern_static_string ("GEnumProperty"), &info, 0); g_once_init_leave (&pspec_type_id__volatile, pspec_type_id); } return pspec_type_id__volatile; } /** * g_enum_property_new: * @name: canonical name of the property * @enum: enum for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property * @getter: (allow-none): the getter function for the property * * Creates a new #GProperty mapping to a enumeration type registered * as a sub-type of %G_TYPE_ENUM. * * You should use g_property_set_prerequisite() to set the type * of the enumeration for validation; if the pre-requisite is unset, * setting or getting this property will result in a warning. * * Return value: the newly created #GProperty * * Since: 2.36 */ GParamSpec * g_enum_property_new (const gchar *name, GPropertyFlags flags, gssize offset, GPropertyEnumSet setter, GPropertyEnumGet getter) { GProperty *prop; GEnumProperty *internal; if (setter == NULL && getter == NULL) g_return_val_if_fail (offset >= 0, NULL); if (setter == NULL) flags |= G_PROPERTY_DIRECT_SET; if (getter == NULL) flags |= G_PROPERTY_DIRECT_GET; prop = g_param_spec_internal (_g_enum_property_get_type (), name, NULL, NULL, property_flags_to_param_flags (flags)); prop->flags = flags; G_PARAM_SPEC (prop)->value_type = G_TYPE_ENUM; prop->field_offset = offset; prop->is_installed = FALSE; prop->type_size = sizeof (glong); internal = (GEnumProperty *) prop; internal->setter = setter; internal->getter = getter; return G_PARAM_SPEC (prop); } static inline gboolean g_enum_property_validate (GProperty *property, glong value) { GEnumProperty *e_prop = (GEnumProperty *) property; if (e_prop->e_class != NULL) { if (g_enum_get_value (e_prop->e_class, value) != NULL) return TRUE; } return FALSE; } static inline gboolean g_enum_property_set_value (GProperty *property, gpointer gobject, glong value) { gboolean retval = FALSE; if ((property->flags & G_PROPERTY_WRITABLE) == 0) { g_critical ("The property '%s' of object '%s' is not writable", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (!g_enum_property_validate (property, value)) { g_warning ("The value for the property '%s' of object '%s' is out of the valid range", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (((GEnumProperty *) property)->setter != NULL) { property_lock_internal (property, gobject); retval = ((GEnumProperty *) property)->setter (gobject, value); property_unlock_internal (property, gobject); if (retval) g_object_notify_by_pspec (gobject, (GParamSpec *) property); } else if (property->field_offset >= 0) { gpointer priv_p, field_p; property_lock_internal (property, gobject); priv_p = get_private_pointer (gobject, property->priv_offset); field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); if ((* (gulong *) field_p) == value) { property_unlock_internal (property, gobject); return FALSE; } (* (gulong *) field_p) = value; property_unlock_internal (property, gobject); g_object_notify_by_pspec (gobject, (GParamSpec *) property); retval = TRUE; } else g_critical (G_STRLOC ": No setter function or field offset specified " "for property '%s'", G_PARAM_SPEC (property)->name); return retval; } static inline gulong g_enum_property_get_value (GProperty *property, gpointer gobject) { if ((property->flags & G_PROPERTY_READABLE) == 0) { g_critical ("The property '%s' of object '%s' is not readable", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (((GEnumProperty *) property)->getter != NULL) { return ((GEnumProperty *) property)->getter (gobject); } else if (property->field_offset >= 0) { gpointer priv_p, field_p; priv_p = get_private_pointer (gobject, property->priv_offset); field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); return (* (gulong *) field_p); } else { g_critical (G_STRLOC ": No getter function or field offset specified " "for property '%s'", G_PARAM_SPEC (property)->name); return 0.0; } } /* * GFlags */ /* forward declaration for -Wmissing-prototypes */ GType _g_flags_property_get_type (void); typedef struct { GProperty parent; GFlagsClass *f_class; GPropertyFlagsSet setter; GPropertyFlagsGet getter; } GFlagsProperty; static gboolean property_flags_validate (GParamSpec *pspec, GValue *value) { GFlagsProperty *property = (GFlagsProperty *) pspec; gulong oval = value->data[0].v_ulong; if (property->f_class != NULL) value->data[0].v_ulong &= property->f_class->mask; else property_set_default (pspec, value); return value->data[0].v_ulong != oval; } static void property_flags_finalize (GParamSpec *pspec) { GFlagsProperty *property = (GFlagsProperty *) pspec; GParamSpecClass *parent_class = g_type_class_peek (g_type_parent (_g_flags_property_get_type ())); if (property->f_class) { g_type_class_unref (property->f_class); property->f_class = NULL; } parent_class->finalize (pspec); } static void property_flags_class_init (GParamSpecClass *klass) { klass->value_type = G_TYPE_FLAGS; klass->value_validate = property_flags_validate; klass->finalize = property_flags_finalize; } static void property_flags_init (GParamSpec *pspec) { } GType _g_flags_property_get_type (void) { static volatile gsize pspec_type_id__volatile = 0; if (g_once_init_enter (&pspec_type_id__volatile)) { const GTypeInfo info = { sizeof (GParamSpecClass), NULL, NULL, (GClassInitFunc) property_flags_class_init, NULL, NULL, sizeof (GFlagsProperty), 0, (GInstanceInitFunc) property_flags_init, }; GType pspec_type_id = g_type_register_static (G_TYPE_PROPERTY, g_intern_static_string ("GFlagsProperty"), &info, 0); g_once_init_leave (&pspec_type_id__volatile, pspec_type_id); } return pspec_type_id__volatile; } /** * g_flags_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property * @getter: (allow-none): the getter function for the property * * Creates a new #GProperty mapping to a flag type registered * as a sub-type of %G_TYPE_FLAGS. * * You should use g_property_set_prerequisite() to set the type * of the flags for validation; if the pre-requisite is unset, * setting or getting this property will result in a warning. * * Return value: the newly created #GProperty * * Since: 2.36 */ GParamSpec * g_flags_property_new (const gchar *name, GPropertyFlags flags, gssize offset, GPropertyFlagsSet setter, GPropertyFlagsGet getter) { GProperty *prop; GFlagsProperty *internal; if (setter == NULL && getter == NULL) g_return_val_if_fail (offset >= 0, NULL); if (setter == NULL) flags |= G_PROPERTY_DIRECT_SET; if (getter == NULL) flags |= G_PROPERTY_DIRECT_GET; prop = g_param_spec_internal (_g_flags_property_get_type (), name, NULL, NULL, property_flags_to_param_flags (flags)); prop->flags = flags; G_PARAM_SPEC (prop)->value_type = G_TYPE_FLAGS; prop->field_offset = offset; prop->is_installed = FALSE; prop->type_size = sizeof (gulong); internal = (GFlagsProperty *) prop; internal->setter = setter; internal->getter = getter; return G_PARAM_SPEC (prop); } static inline gboolean g_flags_property_validate (GProperty *property, gulong value) { GFlagsProperty *f_prop = (GFlagsProperty *) property; if (f_prop->f_class != NULL) { gulong masked_value = value; masked_value &= f_prop->f_class->mask; return masked_value == value; } return FALSE; } static inline gboolean g_flags_property_set_value (GProperty *property, gpointer gobject, gulong value) { gboolean retval = FALSE; if ((property->flags & G_PROPERTY_WRITABLE) == 0) { g_critical ("The property '%s' of object '%s' is not writable", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (!g_flags_property_validate (property, value)) { g_warning ("The value for the property '%s' of object '%s' is out of the valid range", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (((GFlagsProperty *) property)->setter != NULL) { property_lock_internal (property, gobject); retval = ((GFlagsProperty *) property)->setter (gobject, value); property_unlock_internal (property, gobject); if (retval) g_object_notify_by_pspec (gobject, (GParamSpec *) property); } else if (property->field_offset >= 0) { gpointer priv_p, field_p; property_lock_internal (property, gobject); priv_p = get_private_pointer (gobject, property->priv_offset); field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); if ((* (gulong *) field_p) == value) { property_unlock_internal (property, gobject); return FALSE; } (* (gulong *) field_p) = value; property_unlock_internal (property, gobject); g_object_notify_by_pspec (gobject, (GParamSpec *) property); retval = TRUE; } else g_critical (G_STRLOC ": No setter function or field offset specified " "for property '%s'", G_PARAM_SPEC (property)->name); return retval; } static inline gulong g_flags_property_get_value (GProperty *property, gpointer gobject) { if ((property->flags & G_PROPERTY_READABLE) == 0) { g_critical ("The property '%s' of object '%s' is not readable", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (((GFlagsProperty *) property)->getter != NULL) { return ((GFlagsProperty *) property)->getter (gobject); } else if (property->field_offset >= 0) { gpointer priv_p, field_p; priv_p = get_private_pointer (gobject, property->priv_offset); field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); return (* (gulong *) field_p); } else { g_critical (G_STRLOC ": No getter function or field offset specified " "for property '%s'", G_PARAM_SPEC (property)->name); return 0.0; } } /* * GFloat */ #define G_FLOAT_EPSILON (1e-30) /* forward declaration for -Wmissing-prototypes */ GType _g_float_property_get_type (void); typedef struct { GProperty parent; gfloat min_value; gfloat max_value; gfloat epsilon; GPropertyFloatSet setter; GPropertyFloatGet getter; } GFloatProperty; static gboolean property_float_validate (GParamSpec *pspec, GValue *value) { GFloatProperty *property = (GFloatProperty *) pspec; gfloat oval = value->data[0].v_float; value->data[0].v_float = CLAMP (value->data[0].v_float, property->min_value, property->max_value); return value->data[0].v_float != oval; } static gint property_float_values_cmp (GParamSpec *pspec, const GValue *value1, const GValue *value2) { gfloat epsilon = ((GFloatProperty *) pspec)->epsilon; if (value1->data[0].v_float < value2->data[0].v_float) return - (value2->data[0].v_float - value1->data[0].v_float > epsilon); else return value1->data[0].v_float - value2->data[0].v_float > epsilon; } static void property_float_class_init (GParamSpecClass *klass) { klass->value_type = G_TYPE_FLOAT; klass->value_validate = property_float_validate; klass->values_cmp = property_float_values_cmp; } static void property_float_init (GParamSpec *pspec) { GFloatProperty *property = (GFloatProperty *) pspec; property->min_value = -G_MAXFLOAT; property->max_value = G_MAXFLOAT; property->epsilon = G_FLOAT_EPSILON; } GType _g_float_property_get_type (void) { static volatile gsize pspec_type_id__volatile = 0; if (g_once_init_enter (&pspec_type_id__volatile)) { const GTypeInfo info = { sizeof (GParamSpecClass), NULL, NULL, (GClassInitFunc) property_float_class_init, NULL, NULL, sizeof (GFloatProperty), 0, (GInstanceInitFunc) property_float_init, }; GType pspec_type_id = g_type_register_static (G_TYPE_PROPERTY, g_intern_static_string ("GFloatProperty"), &info, 0); g_once_init_leave (&pspec_type_id__volatile, pspec_type_id); } return pspec_type_id__volatile; } /** * g_float_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property * @getter: (allow-none): the getter function for the property * * Creates a new #GProperty mapping to a single precision floating * point value. * * Return value: the newly created #GProperty * * Since: 2.36 */ GParamSpec * g_float_property_new (const gchar *name, GPropertyFlags flags, gssize offset, GPropertyFloatSet setter, GPropertyFloatGet getter) { GProperty *prop; GFloatProperty *internal; if (setter == NULL && getter == NULL) g_return_val_if_fail (offset >= 0, NULL); if (setter == NULL) flags |= G_PROPERTY_DIRECT_SET; if (getter == NULL) flags |= G_PROPERTY_DIRECT_GET; prop = g_param_spec_internal (_g_float_property_get_type (), name, NULL, NULL, property_flags_to_param_flags (flags)); prop->flags = flags; G_PARAM_SPEC (prop)->value_type = G_TYPE_FLOAT; prop->field_offset = offset; prop->is_installed = FALSE; prop->type_size = sizeof (gfloat); internal = (GFloatProperty *) prop; internal->setter = setter; internal->getter = getter; return G_PARAM_SPEC (prop); } static inline void g_float_property_set_range (GProperty *property, gfloat min_value, gfloat max_value) { if (min_value > max_value) { g_critical (G_STRLOC ": Invalid range for the property '%s'", G_PARAM_SPEC (property)->name); return; } ((GFloatProperty *) property)->min_value = min_value; ((GFloatProperty *) property)->max_value = max_value; } static inline void g_float_property_get_range (GProperty *property, gfloat *min_value, gfloat *max_value) { *min_value = ((GFloatProperty *) property)->min_value; *max_value = ((GFloatProperty *) property)->max_value; } static inline gboolean g_float_property_validate (GProperty *property, gfloat value) { GFloatProperty *internal = (GFloatProperty *) property; if (value >= internal->min_value && value <= internal->max_value) return TRUE; return FALSE; } static inline gboolean g_float_property_set_value (GProperty *property, gpointer gobject, gfloat value) { gboolean retval = FALSE; if ((property->flags & G_PROPERTY_WRITABLE) == 0) { g_critical ("The property '%s' of object '%s' is not writable", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (!g_float_property_validate (property, value)) { g_warning ("The value for the property '%s' of object '%s' is out of the valid range", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (((GFloatProperty *) property)->setter != NULL) { property_lock_internal (property, gobject); retval = ((GFloatProperty *) property)->setter (gobject, value); property_unlock_internal (property, gobject); if (retval) g_object_notify_by_pspec (gobject, (GParamSpec *) property); } else if (property->field_offset >= 0) { gpointer priv_p, field_p; property_lock_internal (property, gobject); priv_p = get_private_pointer (gobject, property->priv_offset); field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); if ((* (gfloat *) field_p) == value) { property_unlock_internal (property, gobject); return FALSE; } (* (gfloat *) field_p) = value; property_unlock_internal (property, gobject); g_object_notify_by_pspec (gobject, (GParamSpec *) property); retval = TRUE; } else g_critical (G_STRLOC ": No setter function or field offset specified " "for property '%s'", G_PARAM_SPEC (property)->name); return retval; } static inline gfloat g_float_property_get_value (GProperty *property, gpointer gobject) { if ((property->flags & G_PROPERTY_READABLE) == 0) { g_critical ("The property '%s' of object '%s' is not readable", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (((GFloatProperty *) property)->getter != NULL) { return ((GFloatProperty *) property)->getter (gobject); } else if (property->field_offset >= 0) { gpointer priv_p, field_p; priv_p = get_private_pointer (gobject, property->priv_offset); field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); return (* (gfloat *) field_p); } else { g_critical (G_STRLOC ": No getter function or field offset specified " "for property '%s'", G_PARAM_SPEC (property)->name); return 0.0; } } /* * GDouble */ #define G_DOUBLE_EPSILON (1e-90) /* forward declaration for -Wmissing-prototypes */ GType _g_double_property_get_type (void); typedef struct { GProperty parent; gdouble min_value; gdouble max_value; gdouble epsilon; GPropertyDoubleSet setter; GPropertyDoubleGet getter; } GDoubleProperty; static gboolean property_double_validate (GParamSpec *pspec, GValue *value) { GDoubleProperty *property = (GDoubleProperty *) pspec; gdouble oval = value->data[0].v_double; value->data[0].v_double = CLAMP (value->data[0].v_double, property->min_value, property->max_value); return value->data[0].v_double != oval; } static gint property_double_values_cmp (GParamSpec *pspec, const GValue *value1, const GValue *value2) { gdouble epsilon = ((GDoubleProperty *) pspec)->epsilon; if (value1->data[0].v_double < value2->data[0].v_double) return - (value2->data[0].v_double - value1->data[0].v_double > epsilon); else return value1->data[0].v_double - value2->data[0].v_double > epsilon; } static void property_double_class_init (GParamSpecClass *klass) { klass->value_type = G_TYPE_DOUBLE; klass->value_validate = property_double_validate; klass->values_cmp = property_double_values_cmp; } static void property_double_init (GParamSpec *pspec) { GDoubleProperty *property = (GDoubleProperty *) pspec; property->min_value = -G_MAXDOUBLE; property->max_value = G_MAXDOUBLE; property->epsilon = G_DOUBLE_EPSILON; } GType _g_double_property_get_type (void) { static volatile gsize pspec_type_id__volatile = 0; if (g_once_init_enter (&pspec_type_id__volatile)) { const GTypeInfo info = { sizeof (GParamSpecClass), NULL, NULL, (GClassInitFunc) property_double_class_init, NULL, NULL, sizeof (GDoubleProperty), 0, (GInstanceInitFunc) property_double_init, }; GType pspec_type_id = g_type_register_static (G_TYPE_PROPERTY, g_intern_static_string ("GDoubleProperty"), &info, 0); g_once_init_leave (&pspec_type_id__volatile, pspec_type_id); } return pspec_type_id__volatile; } /** * g_double_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property * @getter: (allow-none): the getter function for the property * * Creates a new #GProperty mapping to a double precision floating * point value. * * Return value: the newly created #GProperty * * Since: 2.36 */ GParamSpec * g_double_property_new (const gchar *name, GPropertyFlags flags, gssize offset, GPropertyDoubleSet setter, GPropertyDoubleGet getter) { GProperty *prop; GDoubleProperty *internal; if (setter == NULL && getter == NULL) g_return_val_if_fail (offset >= 0, NULL); if (setter == NULL) flags |= G_PROPERTY_DIRECT_SET; if (getter == NULL) flags |= G_PROPERTY_DIRECT_GET; prop = g_param_spec_internal (_g_double_property_get_type (), name, NULL, NULL, property_flags_to_param_flags (flags)); prop->flags = flags; G_PARAM_SPEC (prop)->value_type = G_TYPE_DOUBLE; prop->field_offset = offset; prop->is_installed = FALSE; prop->type_size = sizeof (gdouble); internal = (GDoubleProperty *) prop; internal->setter = setter; internal->getter = getter; return G_PARAM_SPEC (prop); } static inline void g_double_property_set_range (GProperty *property, gdouble min_value, gdouble max_value) { if (min_value > max_value) { g_critical (G_STRLOC ": Invalid range for property '%s'", G_PARAM_SPEC (property)->name); return; } ((GDoubleProperty *) property)->min_value = min_value; ((GDoubleProperty *) property)->max_value = max_value; } static inline void g_double_property_get_range (GProperty *property, gdouble *min_value, gdouble *max_value) { *min_value = ((GDoubleProperty *) property)->min_value; *max_value = ((GDoubleProperty *) property)->max_value; } static inline gboolean g_double_property_validate (GProperty *property, gdouble value) { GDoubleProperty *internal = (GDoubleProperty *) property; if (value >= internal->min_value && value <= internal->max_value) return TRUE; return FALSE; } static inline gboolean g_double_property_set_value (GProperty *property, gpointer gobject, gdouble value) { gboolean retval = FALSE; if ((property->flags & G_PROPERTY_WRITABLE) == 0) { g_critical ("The property '%s' of object '%s' is not writable", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (!g_double_property_validate (property, value)) { g_warning ("The value for the property '%s' of object '%s' is out of the valid range", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (((GDoubleProperty *) property)->setter != NULL) { property_lock_internal (property, gobject); retval = ((GDoubleProperty *) property)->setter (gobject, value); property_unlock_internal (property, gobject); if (retval) g_object_notify_by_pspec (gobject, (GParamSpec *) property); } else if (property->field_offset >= 0) { gpointer priv_p, field_p; property_lock_internal (property, gobject); priv_p = get_private_pointer (gobject, property->priv_offset); field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); if ((* (gdouble *) field_p) == value) { property_unlock_internal (property, gobject); return FALSE; } (* (gdouble *) field_p) = value; property_unlock_internal (property, gobject); g_object_notify_by_pspec (gobject, (GParamSpec *) property); retval = TRUE; } else g_critical (G_STRLOC ": No setter function or field offset specified " "for property '%s'", G_PARAM_SPEC (property)->name); return retval; } static inline gdouble g_double_property_get_value (GProperty *property, gpointer gobject) { if ((property->flags & G_PROPERTY_READABLE) == 0) { g_critical ("The property '%s' of object '%s' is not readable", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (((GDoubleProperty *) property)->getter != NULL) { return ((GDoubleProperty *) property)->getter (gobject); } else if (property->field_offset >= 0) { gpointer priv_p, field_p; priv_p = get_private_pointer (gobject, property->priv_offset); field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); return (* (gdouble *) field_p); } else { g_critical (G_STRLOC ": No getter function or field offset specified " "for property '%s'", G_PARAM_SPEC (property)->name); return 0.0; } } /* * GString */ /* forward declaration for -Wmissing-prototypes */ GType _g_string_property_get_type (void); typedef struct { GProperty parent; GPropertyStringSet setter; GPropertyStringGet getter; } GStringProperty; static void property_string_class_init (GParamSpecClass *klass) { klass->value_type = G_TYPE_STRING; } static void property_string_init (GParamSpec *pspec) { } GType _g_string_property_get_type (void) { static volatile gsize pspec_type_id__volatile = 0; if (g_once_init_enter (&pspec_type_id__volatile)) { const GTypeInfo info = { sizeof (GParamSpecClass), NULL, NULL, (GClassInitFunc) property_string_class_init, NULL, NULL, sizeof (GStringProperty), 0, (GInstanceInitFunc) property_string_init, }; GType pspec_type_id = g_type_register_static (G_TYPE_PROPERTY, g_intern_static_string ("GStringProperty"), &info, 0); g_once_init_leave (&pspec_type_id__volatile, pspec_type_id); } return pspec_type_id__volatile; } /** * g_string_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property * @getter: (allow-none): the getter function for the property * * Creates a new #GProperty mapping to a string value. * * Return value: the newly created #GProperty * * Since: 2.36 */ GParamSpec * g_string_property_new (const gchar *name, GPropertyFlags flags, gssize offset, GPropertyStringSet setter, GPropertyStringGet getter) { GProperty *prop; GStringProperty *internal; if (setter == NULL && getter == NULL) g_return_val_if_fail (offset >= 0, NULL); if (setter == NULL) flags |= G_PROPERTY_DIRECT_SET; if (getter == NULL) flags |= G_PROPERTY_DIRECT_GET; prop = g_param_spec_internal (_g_string_property_get_type (), name, NULL, NULL, property_flags_to_param_flags (flags)); prop->flags = flags; G_PARAM_SPEC (prop)->value_type = G_TYPE_STRING; prop->field_offset = offset; prop->is_installed = FALSE; prop->type_size = sizeof (gchar*); internal = (GStringProperty *) prop; internal->setter = setter; internal->getter = getter; return G_PARAM_SPEC (prop); } static inline gboolean g_string_property_validate (GProperty *property, const gchar *value) { return TRUE; } static inline gboolean g_string_property_set_value (GProperty *property, gpointer gobject, const gchar *value) { gboolean retval = FALSE; if ((property->flags & G_PROPERTY_WRITABLE) == 0) { g_critical ("The property '%s' of object '%s' is not writable", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (!g_string_property_validate (property, value)) { g_warning ("The value for the property '%s' of object '%s' is out of the valid range", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (((GStringProperty *) property)->setter != NULL) { property_lock_internal (property, gobject); retval = ((GStringProperty *) property)->setter (gobject, value); property_unlock_internal (property, gobject); if (retval) g_object_notify_by_pspec (gobject, (GParamSpec *) property); } else if (property->field_offset >= 0) { gpointer priv_p, field_p; gchar *str; property_lock_internal (property, gobject); priv_p = get_private_pointer (gobject, property->priv_offset); field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); str = (* (gpointer *) field_p); if (g_strcmp0 (str, value) == 0) { property_unlock_internal (property, gobject); return FALSE; } if (property->flags & G_PROPERTY_COPY_SET) { g_free (str); (* (gpointer *) field_p) = g_strdup (value); } else (* (gpointer *) field_p) = (gpointer) value; property_unlock_internal (property, gobject); g_object_notify_by_pspec (gobject, (GParamSpec *) property); retval = TRUE; } else g_critical (G_STRLOC ": No setter function or field offset specified " "for property '%s'", G_PARAM_SPEC (property)->name); return retval; } static inline const gchar * g_string_property_get_value (GProperty *property, gpointer gobject) { if ((property->flags & G_PROPERTY_READABLE) == 0) { g_critical ("The property '%s' of object '%s' is not readable", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (((GStringProperty *) property)->getter != NULL) { return ((GStringProperty *) property)->getter (gobject); } else if (property->field_offset >= 0) { gpointer priv_p, field_p; gchar *retval; priv_p = get_private_pointer (gobject, property->priv_offset); field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); if (property->flags & G_PROPERTY_COPY_GET) retval = g_strdup ((* (gpointer *) field_p)); else retval = (* (gpointer *) field_p); return retval; } else { g_critical (G_STRLOC ": No getter function or field offset specified " "for property '%s'", G_PARAM_SPEC (property)->name); return NULL; } } /* * GBoxed */ /* forward declaration for -Wmissing-prototypes */ GType _g_boxed_property_get_type (void); typedef struct { GProperty parent; GPropertyBoxedSet setter; GPropertyBoxedGet getter; } GBoxedProperty; static void property_boxed_class_init (GParamSpecClass *klass) { klass->value_type = G_TYPE_BOXED; } static void property_boxed_init (GParamSpec *pspec) { } GType _g_boxed_property_get_type (void) { static volatile gsize pspec_type_id__volatile = 0; if (g_once_init_enter (&pspec_type_id__volatile)) { const GTypeInfo info = { sizeof (GParamSpecClass), NULL, NULL, (GClassInitFunc) property_boxed_class_init, NULL, NULL, sizeof (GBoxedProperty), 0, (GInstanceInitFunc) property_boxed_init, }; GType pspec_type_id = g_type_register_static (G_TYPE_PROPERTY, g_intern_static_string ("GBoxedProperty"), &info, 0); g_once_init_leave (&pspec_type_id__volatile, pspec_type_id); } return pspec_type_id__volatile; } /** * g_boxed_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property * @getter: (allow-none): the getter function for the property * * Creates a new #GProperty mapping to a boxed value. * * You can use g_property_set_prerequisite() to specify the #GType * of the boxed value. * * Return value: the newly created #GProperty * * Since: 2.36 */ GParamSpec * g_boxed_property_new (const gchar *name, GPropertyFlags flags, gssize offset, GPropertyBoxedSet setter, GPropertyBoxedGet getter) { GProperty *prop; GBoxedProperty *internal; if (setter == NULL && getter == NULL) g_return_val_if_fail (offset >= 0, NULL); if (setter == NULL) flags |= G_PROPERTY_DIRECT_SET; if (getter == NULL) flags |= G_PROPERTY_DIRECT_GET; prop = g_param_spec_internal (_g_boxed_property_get_type (), name, NULL, NULL, property_flags_to_param_flags (flags)); prop->flags = flags; G_PARAM_SPEC (prop)->value_type = G_TYPE_BOXED; prop->field_offset = offset; prop->is_installed = FALSE; prop->type_size = sizeof (gpointer); internal = (GBoxedProperty *) prop; internal->setter = setter; internal->getter = getter; return G_PARAM_SPEC (prop); } static inline gboolean g_boxed_property_validate (GProperty *property, gconstpointer value) { return TRUE; } static inline gboolean g_boxed_property_set_value (GProperty *property, gpointer gobject, gpointer value) { gboolean retval = FALSE; if ((property->flags & G_PROPERTY_WRITABLE) == 0) { g_critical ("The property '%s' of object '%s' is not writable", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (!g_boxed_property_validate (property, value)) { g_warning ("The value for the property '%s' of object '%s' is out of the valid range", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (((GBoxedProperty *) property)->setter != NULL) { property_lock_internal (property, gobject); retval = ((GBoxedProperty *) property)->setter (gobject, value); property_unlock_internal (property, gobject); if (retval) g_object_notify_by_pspec (gobject, (GParamSpec *) property); } else if (property->field_offset >= 0) { gpointer priv_p, field_p; gpointer old_value; property_lock_internal (property, gobject); priv_p = get_private_pointer (gobject, property->priv_offset); field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); if (property->flags & G_PROPERTY_COPY_SET) { old_value = (* (gpointer *) field_p); if (value != NULL) (* (gpointer *) field_p) = g_boxed_copy (((GParamSpec *) property)->value_type, value); else (* (gpointer *) field_p) = NULL; if (old_value != NULL) g_boxed_free (((GParamSpec *) property)->value_type, old_value); } else (* (gpointer *) field_p) = value; property_unlock_internal (property, gobject); g_object_notify_by_pspec (gobject, (GParamSpec *) property); retval = TRUE; } else g_critical (G_STRLOC ": No setter function or field offset specified " "for property '%s'", G_PARAM_SPEC (property)->name); return retval; } static inline gpointer g_boxed_property_get_value (GProperty *property, gpointer gobject) { if ((property->flags & G_PROPERTY_READABLE) == 0) { g_critical ("The property '%s' of object '%s' is not readable", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (((GBoxedProperty *) property)->getter != NULL) { return ((GBoxedProperty *) property)->getter (gobject); } else if (property->field_offset >= 0) { gpointer priv_p, field_p; gpointer value; priv_p = get_private_pointer (gobject, property->priv_offset); field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); if (property->flags & G_PROPERTY_COPY_GET) value = g_boxed_copy (((GParamSpec *) property)->value_type, (* (gpointer *) field_p)); else value = (* (gpointer *) field_p); return value; } else { g_critical (G_STRLOC ": No getter function or field offset specified " "for property '%s'", G_PARAM_SPEC (property)->name); return NULL; } } /* * GObject */ /* forward declaration for -Wmissing-prototypes */ GType _g_object_property_get_type (void); typedef struct { GProperty parent; GPropertyObjectSet setter; GPropertyObjectGet getter; } GObjectProperty; static void property_object_class_init (GParamSpecClass *klass) { klass->value_type = G_TYPE_OBJECT; } static void property_object_init (GParamSpec *pspec) { } GType _g_object_property_get_type (void) { static volatile gsize pspec_type_id__volatile = 0; if (g_once_init_enter (&pspec_type_id__volatile)) { const GTypeInfo info = { sizeof (GParamSpecClass), NULL, NULL, (GClassInitFunc) property_object_class_init, NULL, NULL, sizeof (GObjectProperty), 0, (GInstanceInitFunc) property_object_init, }; GType pspec_type_id = g_type_register_static (G_TYPE_PROPERTY, g_intern_static_string ("GObjectProperty"), &info, 0); g_once_init_leave (&pspec_type_id__volatile, pspec_type_id); } return pspec_type_id__volatile; } /** * g_object_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property * @getter: (allow-none): the getter function for the property * * Creates a new #GProperty mapping to an object value. * * You can use g_property_set_prerequisite() to specify the #GType * of the object value. * * Return value: the newly created #GProperty * * Since: 2.36 */ GParamSpec * g_object_property_new (const gchar *name, GPropertyFlags flags, gssize offset, GPropertyObjectSet setter, GPropertyObjectGet getter) { GProperty *prop; GObjectProperty *internal; if (setter == NULL && getter == NULL) g_return_val_if_fail (offset >= 0, NULL); if (setter == NULL) flags |= G_PROPERTY_DIRECT_SET; if (getter == NULL) flags |= G_PROPERTY_DIRECT_GET; prop = g_param_spec_internal (_g_object_property_get_type (), name, NULL, NULL, property_flags_to_param_flags (flags)); prop->flags = flags; G_PARAM_SPEC (prop)->value_type = G_TYPE_OBJECT; prop->field_offset = offset; prop->is_installed = FALSE; prop->type_size = sizeof (gpointer); internal = (GObjectProperty *) prop; internal->setter = setter; internal->getter = getter; return G_PARAM_SPEC (prop); } static inline gboolean g_object_property_validate (GProperty *property, gconstpointer value) { if (value == NULL) return FALSE; return g_type_is_a (G_OBJECT_TYPE (value), G_PARAM_SPEC (property)->value_type); } static inline gboolean g_object_property_set_value (GProperty *property, gpointer gobject, gpointer value) { gboolean retval = FALSE; if ((property->flags & G_PROPERTY_WRITABLE) == 0) { g_critical ("The property '%s' of object '%s' is not writable", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (!g_object_property_validate (property, value)) { g_warning ("The value for the property '%s' of object '%s' is out of the valid range", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (((GObjectProperty *) property)->setter != NULL) { property_lock_internal (property, gobject); retval = ((GObjectProperty *) property)->setter (gobject, value); property_unlock_internal (property, gobject); if (retval) g_object_notify_by_pspec (gobject, (GParamSpec *) property); } else if (property->field_offset >= 0) { gpointer priv_p, field_p; gpointer obj; g_return_val_if_fail (value == NULL || G_IS_OBJECT (value), FALSE); property_lock_internal (property, gobject); priv_p = get_private_pointer (gobject, property->priv_offset); field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); if ((* (gpointer *) field_p) == value) { property_unlock_internal (property, gobject); return FALSE; } if (property->flags & G_PROPERTY_COPY_SET) { obj = (* (gpointer *) field_p); if (obj != NULL) g_object_unref (obj); (* (gpointer *) field_p) = obj = value; if (obj != NULL) { if (G_IS_INITIALLY_UNOWNED (obj)) g_object_ref_sink (obj); else g_object_ref (obj); } } else (* (gpointer *) field_p) = value; property_unlock_internal (property, gobject); g_object_notify_by_pspec (gobject, (GParamSpec *) property); retval = TRUE; } else g_critical (G_STRLOC ": No setter function or field offset specified " "for property '%s'", G_PARAM_SPEC (property)->name); return retval; } static inline gpointer g_object_property_get_value (GProperty *property, gpointer gobject) { if ((property->flags & G_PROPERTY_READABLE) == 0) { g_critical ("The property '%s' of object '%s' is not readable", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (((GObjectProperty *) property)->getter != NULL) { return ((GObjectProperty *) property)->getter (gobject); } else if (property->field_offset >= 0) { gpointer priv_p, field_p; priv_p = g_type_instance_get_private (gobject, G_OBJECT_TYPE (gobject)); field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); if (property->flags & G_PROPERTY_COPY_GET) { gpointer value = (* (gpointer *) field_p); if (value != NULL) return g_object_ref (value); else return NULL; } else return (* (gpointer *) field_p); } else { g_critical (G_STRLOC ": No getter function or field offset specified " "for property '%s'", G_PARAM_SPEC (property)->name); return NULL; } } /* * gpointer */ /* forward declaration for -Wmissing-prototypes */ GType _g_pointer_property_get_type (void); typedef struct { GProperty parent; GPropertyPointerSet setter; GPropertyPointerGet getter; } GPointerProperty; static void property_pointer_class_init (GParamSpecClass *klass) { klass->value_type = G_TYPE_POINTER; } static void property_pointer_init (GParamSpec *pspec) { } GType _g_pointer_property_get_type (void) { static volatile gsize pspec_type_id__volatile = 0; if (g_once_init_enter (&pspec_type_id__volatile)) { const GTypeInfo info = { sizeof (GParamSpecClass), NULL, NULL, (GClassInitFunc) property_pointer_class_init, NULL, NULL, sizeof (GPointerProperty), 0, (GInstanceInitFunc) property_pointer_init, }; GType pspec_type_id = g_type_register_static (G_TYPE_PROPERTY, g_intern_static_string ("GPointerProperty"), &info, 0); g_once_init_leave (&pspec_type_id__volatile, pspec_type_id); } return pspec_type_id__volatile; } /** * g_pointer_property_new: * @name: canonical name of the property * @flags: flags for the property * @offset: the offset in the private structure of the field * that stores the property, or -1 * @setter: (allow-none): the setter function for the property * @getter: (allow-none): the getter function for the property * * Creates a new #GProperty mapping to an untyped pointer. * * Return value: the newly created #GProperty * * Since: 2.36 */ GParamSpec * g_pointer_property_new (const gchar *name, GPropertyFlags flags, gssize offset, GPropertyObjectSet setter, GPropertyObjectGet getter) { GProperty *prop; GPointerProperty *internal; if (setter == NULL && getter == NULL) g_return_val_if_fail (offset >= 0, NULL); if (setter == NULL) flags |= G_PROPERTY_DIRECT_SET; if (getter == NULL) flags |= G_PROPERTY_DIRECT_GET; prop = g_param_spec_internal (_g_pointer_property_get_type (), name, NULL, NULL, property_flags_to_param_flags (flags)); prop->flags = flags; G_PARAM_SPEC (prop)->value_type = G_TYPE_POINTER; prop->field_offset = offset; prop->is_installed = FALSE; prop->type_size = sizeof (gpointer); internal = (GPointerProperty *) prop; internal->setter = setter; internal->getter = getter; return G_PARAM_SPEC (prop); } static inline gboolean g_pointer_property_validate (GProperty *property, gconstpointer value) { return TRUE; } static inline gboolean g_pointer_property_set_value (GProperty *property, gpointer gobject, gpointer value) { gboolean retval = FALSE; if ((property->flags & G_PROPERTY_WRITABLE) == 0) { g_critical ("The property '%s' of object '%s' is not writable", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (!g_pointer_property_validate (property, value)) { g_warning ("The value for the property '%s' of object '%s' is out of the valid range", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (((GPointerProperty *) property)->setter != NULL) { property_lock_internal (property, gobject); retval = ((GPointerProperty *) property)->setter (gobject, value); property_unlock_internal (property, gobject); if (retval) g_object_notify_by_pspec (gobject, (GParamSpec *) property); } else if (property->field_offset >= 0) { gpointer priv_p, field_p; property_lock_internal (property, gobject); priv_p = get_private_pointer (gobject, property->priv_offset); field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); if ((* (gpointer *) field_p) == value) { property_unlock_internal (property, gobject); return FALSE; } (* (gpointer *) field_p) = value; property_unlock_internal (property, gobject); g_object_notify_by_pspec (gobject, (GParamSpec *) property); retval = TRUE; } else g_critical (G_STRLOC ": No setter function or field offset specified " "for property '%s'", G_PARAM_SPEC (property)->name); return retval; } static inline gpointer g_pointer_property_get_value (GProperty *property, gpointer gobject) { if ((property->flags & G_PROPERTY_READABLE) == 0) { g_critical ("The property '%s' of object '%s' is not readable", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); return FALSE; } if (((GPointerProperty *) property)->getter != NULL) { return ((GPointerProperty *) property)->getter (gobject); } else if (property->field_offset >= 0) { gpointer priv_p, field_p; priv_p = g_type_instance_get_private (gobject, G_OBJECT_TYPE (gobject)); field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset); return (* (gpointer *) field_p); } else { g_critical (G_STRLOC ": No getter function or field offset specified " "for property '%s'", G_PARAM_SPEC (property)->name); return NULL; } } /* * GProperty common API */ /*< private > * g_property_set_installed: * @property: a #GProperty * @class_gtype: the #GType of the class that installed @property * * Performs additional work once a type class has been associated to * the property. */ void _g_property_set_installed (GProperty *property, gpointer g_class, GType class_gtype) { if (property->field_offset >= 0) { gboolean is_interface = G_TYPE_IS_INTERFACE (class_gtype); if (is_interface) { g_critical (G_STRLOC ": The property '%s' has a field offset value " "but it is being installed on an interface of type '%s'. " "Properties installed on interfaces cannot have direct " "access to a structure field.", G_PARAM_SPEC (property)->name, g_type_name (class_gtype)); property->priv_offset = -1; } property->priv_offset = g_type_class_get_instance_private_offset (g_class, class_gtype); } else property->priv_offset = -1; /* if the property is using the default locking, pre-compute the * quark for the lock */ if ((property->flags & G_PROPERTY_ATOMIC) != 0 && property->prop_id == 0 && property->lock_func == NULL) { gchar *lock_n = g_strconcat ("-g-property-id-", G_PARAM_SPEC (property)->name, NULL); property->prop_id = g_quark_from_string (lock_n); g_free (lock_n); } property->is_installed = TRUE; } static gboolean is_canonical (const gchar *key) { const gchar *p; for (p = key; *p != 0; p++) { gchar c = *p; if (c != '-' && (c < '0' || c > '9') && (c < 'A' || c > 'Z') && (c < 'a' || c > 'z')) return FALSE; } return TRUE; } static void canonicalize_name (gchar *key) { gchar *p; for (p = key; *p != 0; p++) { gchar c = *p; if (c != '-' && (c < '0' || c > '9') && (c < 'A' || c > 'Z') && (c < 'a' || c > 'z')) *p = '-'; } } /** * g_property_canonicalize_name: * @name: a string * * Canonicalizes a string into a property name. * * Return value: (transfer full): a newly allocated string with * the canonical version of @name * * Since: 2.36 */ gchar * g_property_canonicalize_name (const gchar *name) { gchar *retval; g_return_val_if_fail (name != NULL, NULL); if (is_canonical (name)) return g_strdup (g_intern_string (name)); retval = g_strdup (name); canonicalize_name (retval); g_intern_string (retval); return retval; } /** * g_property_describe: * @property: a #GProperty * @nick: a static string with the user-readable name * of the property * @blurb: a static string with the user-readable description * of the property * * Sets the user-readable, and optionally translatable, name and * description of the property. * * This function cannot be called more than once. * * This function is a convenience wrapper around g_param_spec_set_static_nick() * and g_param_spec_set_static_blurb(). * * Since: 2.36 */ void g_property_describe (GProperty *property, const char *nick, const char *blurb) { GParamSpec *pspec; g_return_if_fail (G_IS_PROPERTY (property)); g_return_if_fail (nick != NULL); g_return_if_fail (blurb != NULL); pspec = G_PARAM_SPEC (property); g_param_spec_set_static_nick (pspec, nick); g_param_spec_set_static_blurb (pspec, blurb); } /** * g_property_set_prerequisite: * @property: a #GProperty * @gtype: the prerequisite type * * Sets the prerequisite type for the @property. * * The prerequisite type must have the @property GType as a super-type, * and will be used to make the type checking stricter. * * Since: 2.36 */ void g_property_set_prerequisite (GProperty *property, GType gtype) { g_return_if_fail (G_IS_PROPERTY (property)); g_return_if_fail (gtype != G_TYPE_INVALID); g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID); g_return_if_fail (g_type_is_a (gtype, G_PARAM_SPEC (property)->value_type)); switch (G_PARAM_SPEC (property)->value_type) { case G_TYPE_BOXED: case G_TYPE_OBJECT: G_PARAM_SPEC (property)->value_type = gtype; break; case G_TYPE_ENUM: G_PARAM_SPEC (property)->value_type = gtype; ((GEnumProperty *) property)->e_class = g_type_class_ref (gtype); break; case G_TYPE_FLAGS: G_PARAM_SPEC (property)->value_type = gtype; ((GFlagsProperty *) property)->f_class = g_type_class_ref (gtype); break; default: break; } } /** * g_property_set_range_values: * @property: a #GProperty * @min_value: a #GValue with the minimum value of the range * @max_value: a #GValue with the maximum value of the range * * Sets the valid range of @property, using #GValues. * * This function is intended for language bindings. * * Since: 2.36 */ void g_property_set_range_values (GProperty *property, const GValue *min_value, const GValue *max_value) { GType gtype; g_return_if_fail (G_IS_PROPERTY (property)); g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID); g_return_if_fail (!property->is_installed); g_return_if_fail (min_value != NULL && max_value != NULL); gtype = G_PARAM_SPEC (property)->value_type; g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (min_value), gtype)); g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (max_value), gtype)); switch (gtype) { case G_TYPE_BOOLEAN: g_boolean_property_set_range (property, g_value_get_boolean (min_value), g_value_get_boolean (max_value)); break; case G_TYPE_INT: { gint min_v = g_value_get_int (min_value); gint max_v = g_value_get_int (max_value); switch (property->type_size) { case 1: g_int8_property_set_range (property, min_v, max_v); break; case 2: g_int16_property_set_range (property, min_v, max_v); break; case 4: g_int32_property_set_range (property, min_v, max_v); break; default: g_int_property_set_range (property, min_v, max_v); break; } } break; case G_TYPE_INT64: g_int64_property_set_range (property, g_value_get_int64 (min_value), g_value_get_int64 (max_value)); break; case G_TYPE_LONG: g_long_property_set_range (property, g_value_get_long (min_value), g_value_get_long (max_value)); break; case G_TYPE_UINT: { guint min_v = g_value_get_uint (min_value); guint max_v = g_value_get_uint (max_value); switch (property->type_size) { case 1: g_uint8_property_set_range (property, min_v, max_v); break; case 2: g_uint16_property_set_range (property, min_v, max_v); break; case 4: g_uint32_property_set_range (property, min_v, max_v); break; default: g_uint_property_set_range (property, min_v, max_v); break; } } break; case G_TYPE_UINT64: g_uint64_property_set_range (property, g_value_get_uint64 (min_value), g_value_get_uint64 (max_value)); break; case G_TYPE_ULONG: g_ulong_property_set_range (property, g_value_get_ulong (min_value), g_value_get_ulong (max_value)); break; case G_TYPE_FLOAT: g_float_property_set_range (property, g_value_get_float (min_value), g_value_get_float (max_value)); break; case G_TYPE_DOUBLE: g_double_property_set_range (property, g_value_get_double (min_value), g_value_get_double (max_value)); break; default: break; } } /** * g_property_get_range_values: * @property: a #GProperty * @min_value: a valid #GValue, initialized to the type of @property * @max_value: a valid #GValue, initialized to the type of @property * * Retrieves the bounds of the range of valid values for @property * and stores them into @min_value and @max_value. * * Return value: %TRUE if successful, and %FALSE otherwise * * Since: 2.36 */ gboolean g_property_get_range_values (GProperty *property, GValue *min_value, GValue *max_value) { gboolean retval; GType gtype; g_return_val_if_fail (G_IS_PROPERTY (property), FALSE); g_return_val_if_fail (min_value != NULL, FALSE); g_return_val_if_fail (max_value != NULL, FALSE); gtype = G_PARAM_SPEC (property)->value_type; g_return_val_if_fail (g_value_type_compatible (gtype, G_VALUE_TYPE (min_value)), FALSE); g_return_val_if_fail (g_value_type_compatible (gtype, G_VALUE_TYPE (max_value)), FALSE); switch (gtype) { case G_TYPE_BOOLEAN: { gboolean min_v, max_v; g_boolean_property_get_range (property, &min_v, &max_v); g_value_set_boolean (min_value, min_v); g_value_set_boolean (max_value, max_v); } retval = TRUE; break; case G_TYPE_INT: { gint min_v, max_v; switch (property->type_size) { case 1: g_int8_property_get_range (property, (gint8 *) &min_v, (gint8 *) &max_v); break; case 2: g_int16_property_get_range (property, (gint16 *) &min_v, (gint16 *) &max_v); break; case 4: g_int32_property_get_range (property, (gint32 *) &min_v, (gint32 *) &max_v); break; default: g_int_property_get_range (property, &min_v, &max_v); break; } g_value_set_int (min_value, min_v); g_value_set_int (max_value, max_v); } retval = TRUE; break; case G_TYPE_INT64: { gint64 min_v, max_v; g_int64_property_get_range (property, &min_v, &max_v); g_value_set_int64 (min_value, min_v); g_value_set_int64 (max_value, max_v); } retval = TRUE; break; case G_TYPE_LONG: { glong min_v, max_v; g_long_property_get_range (property, &min_v, &max_v); g_value_set_long (min_value, min_v); g_value_set_long (max_value, max_v); } retval = TRUE; break; case G_TYPE_UINT: { guint min_v, max_v; switch (property->type_size) { case 1: g_uint8_property_get_range (property, (guint8 *) &min_v, (guint8 *) &max_v); break; case 2: g_uint16_property_get_range (property, (guint16 *) &min_v, (guint16 *) &max_v); break; case 4: g_uint32_property_get_range (property, (guint32 *) &min_v, (guint32 *) &max_v); break; default: g_uint_property_get_range (property, &min_v, &max_v); break; } g_value_set_uint (min_value, min_v); g_value_set_uint (max_value, max_v); } retval = TRUE; break; case G_TYPE_UINT64: { guint64 min_v, max_v; g_uint64_property_get_range (property, &min_v, &max_v); g_value_set_uint64 (min_value, min_v); g_value_set_uint64 (max_value, max_v); } retval = TRUE; break; case G_TYPE_ULONG: { gulong min_v, max_v; g_ulong_property_get_range (property, &min_v, &max_v); g_value_set_ulong (min_value, min_v); g_value_set_ulong (max_value, max_v); } retval = TRUE; break; case G_TYPE_FLOAT: { gfloat min_v, max_v; g_float_property_get_range (property, &min_v, &max_v); g_value_set_float (min_value, min_v); g_value_set_float (max_value, max_v); } retval = TRUE; break; case G_TYPE_DOUBLE: { gdouble min_v, max_v; g_double_property_get_range (property, &min_v, &max_v); g_value_set_double (min_value, min_v); g_value_set_double (max_value, max_v); } retval = TRUE; break; default: g_critical (G_STRLOC ": Invalid type '%s'", g_type_name (gtype)); retval = FALSE; break; } return retval; } /** * g_property_set_range: * @property: a #GProperty * @...: the minimum and maximum values of the range * * Sets the range of valid values for @property. * * Since: 2.36 */ void g_property_set_range (GProperty *property, ...) { GType gtype; va_list args; g_return_if_fail (G_IS_PROPERTY (property)); g_return_if_fail (!property->is_installed); gtype = G_PARAM_SPEC (property)->value_type; g_return_if_fail (gtype != G_TYPE_INVALID); va_start (args, property); switch (G_TYPE_FUNDAMENTAL (gtype)) { case G_TYPE_BOOLEAN: { gboolean min_v = va_arg (args, gboolean); gboolean max_v = va_arg (args, gboolean); g_boolean_property_set_range (property, min_v, max_v); } break; case G_TYPE_INT: { gint min_v = va_arg (args, gint); gint max_v = va_arg (args, gint); switch (property->type_size) { case 1: g_int8_property_set_range (property, min_v, max_v); break; case 2: g_int16_property_set_range (property, min_v, max_v); break; case 4: g_int32_property_set_range (property, min_v, max_v); break; default: g_int_property_set_range (property, min_v, max_v); break; } } break; case G_TYPE_INT64: { gint64 min_v = va_arg (args, gint64); gint64 max_v = va_arg (args, gint64); g_int64_property_set_range (property, min_v, max_v); } break; case G_TYPE_LONG: { glong min_v = va_arg (args, glong); glong max_v = va_arg (args, glong); g_long_property_set_range (property, min_v, max_v); } break; case G_TYPE_UINT: { guint min_v = va_arg (args, guint); guint max_v = va_arg (args, guint); switch (property->type_size) { case 1: g_uint8_property_set_range (property, min_v, max_v); break; case 2: g_uint16_property_set_range (property, min_v, max_v); break; case 4: g_uint32_property_set_range (property, min_v, max_v); break; default: g_uint_property_set_range (property, min_v, max_v); break; } } break; case G_TYPE_UINT64: { guint64 min_v = va_arg (args, guint64); guint64 max_v = va_arg (args, guint64); g_uint64_property_set_range (property, min_v, max_v); } break; case G_TYPE_ULONG: { gulong min_v = va_arg (args, gulong); gulong max_v = va_arg (args, gulong); g_ulong_property_set_range (property, min_v, max_v); } break; case G_TYPE_FLOAT: { gfloat min_v = va_arg (args, gdouble); gfloat max_v = va_arg (args, gdouble); g_float_property_set_range (property, min_v, max_v); } break; case G_TYPE_DOUBLE: { gdouble min_v = va_arg (args, gdouble); gdouble max_v = va_arg (args, gdouble); g_double_property_set_range (property, min_v, max_v); } break; default: g_critical (G_STRLOC ": Invalid type %s", g_type_name (gtype)); } va_end (args); } /** * g_property_get_range: * @property: a #GProperty * @...: the return locations for the minimum and maximum values * of the range * * Retrieves the bounds of the range of valid values for @property. * * Return value: %TRUE on success, and %FALSE otherwise * * Since: 2.36 */ gboolean g_property_get_range (GProperty *property, ...) { va_list var_args; GType gtype; gboolean retval; gpointer min_p, max_p; g_return_val_if_fail (G_IS_PROPERTY (property), FALSE); g_return_val_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID, FALSE); gtype = G_PARAM_SPEC (property)->value_type; va_start (var_args, property); min_p = va_arg (var_args, gpointer); max_p = va_arg (var_args, gpointer); switch (G_TYPE_FUNDAMENTAL (gtype)) { case G_TYPE_BOOLEAN: g_boolean_property_get_range (property, (gboolean *) min_p, (gboolean *) max_p); retval = TRUE; break; case G_TYPE_INT: switch (property->type_size) { case 1: g_int8_property_get_range (property, (gint8 *) min_p, (gint8 *) max_p); retval = TRUE; break; case 2: g_int16_property_get_range (property, (gint16 *) min_p, (gint16 *) max_p); retval = TRUE; break; case 4: g_int32_property_get_range (property, (gint32 *) min_p, (gint32 *) max_p); retval = TRUE; break; default: g_int_property_get_range (property, (gint *) min_p, (gint *) max_p); retval = TRUE; break; } break; case G_TYPE_INT64: g_int64_property_get_range (property, (gint64 *) min_p, (gint64 *) max_p); retval = TRUE; break; case G_TYPE_LONG: g_long_property_get_range (property, (glong *) min_p, (glong *) max_p); retval = TRUE; break; case G_TYPE_UINT: switch (property->type_size) { case 1: g_uint8_property_get_range (property, (guint8 *) min_p, (guint8 *) max_p); retval = TRUE; break; case 2: g_uint16_property_get_range (property, (guint16 *) min_p, (guint16 *) max_p); retval = TRUE; break; case 4: g_uint32_property_get_range (property, (guint32 *) min_p, (guint32 *) max_p); retval = TRUE; break; default: g_uint_property_get_range (property, (guint *) min_p, (guint *) max_p); retval = TRUE; break; } break; case G_TYPE_UINT64: g_uint64_property_get_range (property, (guint64 *) min_p, (guint64 *) max_p); retval = TRUE; break; case G_TYPE_ULONG: g_ulong_property_get_range (property, (gulong *) min_p, (gulong *) max_p); retval = TRUE; break; case G_TYPE_FLOAT: g_float_property_get_range (property, (gfloat *) min_p, (gfloat *) max_p); retval = TRUE; break; case G_TYPE_DOUBLE: g_double_property_get_range (property, (gdouble *) min_p, (gdouble *) max_p); retval = TRUE; break; default: g_critical (G_STRLOC ": Invalid type %s", g_type_name (gtype)); retval = FALSE; } va_end (var_args); return retval; } /** * g_property_set_default_value: * @property: a #GProperty * @gobject_class: a #GObject class pointer * @default_value: a #GValue, initialized to the property type * containing the default value for the given class * * Sets the default value of @property for the given class. * * This function is a #GValue variant of g_property_set_default(), and * it is meant to be used by language bindings. * * Since: 2.36 */ void g_property_set_default_value (GProperty *property, const GValue *default_value) { GValue *value; GType gtype; g_return_if_fail (G_IS_PROPERTY (property)); g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID); g_return_if_fail (default_value != NULL); gtype = G_PARAM_SPEC (property)->value_type; g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (default_value), gtype)); value = g_new0 (GValue, 1); g_value_init (value, gtype); if (!g_value_transform (default_value, value)) { g_critical (G_STRLOC ": unable to set the default value for " "property '%s': the type %s of the value is not " "compatible with the type of the %s property", G_PARAM_SPEC (property)->name, g_type_name (G_VALUE_TYPE (default_value)), g_type_name (gtype)); g_value_unset (value); g_free (value); return; } property_set_default_for_type (property, G_TYPE_INVALID, value); } /** * g_property_override_default_value: * @property: a #GProperty * @class_gtype: the type of the class overriding the value * @default_value: a #GValue containing a value with the type of the * property or a transformable type * * Overrides the default value of a @property for the given class * type. * * This function should only be called by language bindings. * * Since: 2.36 */ void g_property_override_default_value (GProperty *property, GType class_gtype, const GValue *default_value) { GValue *value; GType gtype; g_return_if_fail (G_IS_PROPERTY (property)); g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID); g_return_if_fail (g_type_name (class_gtype) != 0); g_return_if_fail (default_value != NULL); gtype = G_PARAM_SPEC (property)->value_type; g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (default_value), gtype)); value = g_new0 (GValue, 1); g_value_init (value, gtype); if (!g_value_transform (default_value, value)) { g_critical (G_STRLOC ": unable to set the default value for " "property '%s': the type %s of the value is not " "compatible with the type of the %s property", G_PARAM_SPEC (property)->name, g_type_name (G_VALUE_TYPE (default_value)), g_type_name (gtype)); g_value_unset (value); g_free (value); return; } /* takes ownership of value */ property_set_default_for_type (property, class_gtype, value); } /** * g_property_get_default_value_for_type: * @property: a #GProperty * @gtype: a valid #GType * @value: a #GValue initialized to the property type * * Retrieves the default value of the property for the given type. * * This function is meant to be used by language bindings and other * introspection tools; #GObject implementations should use * g_property_get_default() instead. * * Return value: %TRUE if there is a default got the given type, * and %FALSE otherwise. * * Since: 2.36 */ gboolean g_property_get_default_value_for_type (GProperty *property, GType gtype, GValue *value) { const GValue *default_value = NULL; GType iter; g_return_val_if_fail (G_IS_PROPERTY (property), FALSE); g_return_val_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID, FALSE); g_return_val_if_fail (g_type_name (gtype) != 0, FALSE); /* we need to recurse through the inheritance chain... */ iter = gtype; while (iter != G_TYPE_INVALID && default_value == NULL) { default_value = property_get_default_for_type (property, iter); gtype = g_type_parent (iter); } if (default_value != NULL) goto out; /* ... and eventually check the implemented interfaces */ if (default_value == NULL) { GType *ifaces; guint n_ifaces; ifaces = g_type_interfaces (gtype, &n_ifaces); while (n_ifaces-- && default_value == NULL) { iter = ifaces[n_ifaces]; default_value = property_get_default_for_type (property, iter); } g_free (ifaces); } if (default_value != NULL) goto out; /* if the property hasn't been overridden then we look for the default */ default_value = property_get_default_for_type (property, G_TYPE_INVALID); if (default_value == NULL) { g_critical (G_STRLOC ": No default value of property '%s' " "was found for type '%s'", G_PARAM_SPEC (property)->name, g_type_name (gtype)); return FALSE; } out: if (!g_value_transform (default_value, value)) { g_critical (G_STRLOC ": Unable to transform a value of type '%s' " "into a value of type '%s'", g_type_name (G_VALUE_TYPE (default_value)), g_type_name (G_VALUE_TYPE (value))); return FALSE; } return TRUE; } /** * g_property_get_default_value: * @property: a #GProperty * @gobject: a #GObject * @value: a #GValue initialized to the type of the property * * Retrieves the default value of @property for the given @gobject * type. * * This function should only be used by language bindings and other * introspection tools. * * Return value: %TRUE if a default value was found, and %FALSE * otherwise * * Since: 2.36 */ gboolean g_property_get_default_value (GProperty *property, gpointer gobject, GValue *value) { g_return_val_if_fail (G_IS_OBJECT (gobject), FALSE); return g_property_get_default_value_for_type (property, G_OBJECT_TYPE (gobject), value); } /** * g_property_set_default: * @property: a #GProperty * @...: the default value for the property * * Sets the default value of @property. * * This function can only be called once for each property; derived * types should call g_property_override_default() instead. * * See also g_property_override_default() and * g_object_class_override_property_default(). * * Since: 2.36 */ void g_property_set_default (GProperty *property, ...) { GValue *value; GType p_type; gchar *error; va_list var_args; g_return_if_fail (G_IS_PROPERTY (property)); g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID); p_type = G_PARAM_SPEC (property)->value_type; va_start (var_args, property); value = g_new0 (GValue, 1); G_VALUE_COLLECT_INIT (value, p_type, var_args, 0, &error); if (error != NULL) { g_critical (G_STRLOC ": %s", error); g_free (error); g_value_unset (value); g_free (value); } else { /* takes ownership of the GValue */ property_set_default_for_type (property, G_TYPE_INVALID, value); } va_end (var_args); } /** * g_property_get_default: * @property: a #GProperty * @gobject: a #GObject instance * @...: the return location for the default value * * Retrieves the default value of @property for the type of the * instance passed. * * Since: 2.36 */ void g_property_get_default (GProperty *property, gpointer gobject, ...) { GValue value = { 0, }; GType gtype, p_type; gchar *error; va_list var_args; const GValue *default_value = NULL; g_return_if_fail (G_IS_PROPERTY (property)); g_return_if_fail (G_IS_OBJECT (gobject)); g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID); p_type = G_PARAM_SPEC (property)->value_type; /* we perform a copy here because if the default value was not found, * we can use the pre-initialized value safely in G_VALUE_LCOPY and * return something sensible */ g_value_init (&value, p_type); gtype = G_OBJECT_TYPE (gobject); /* we need to recurse through the inheritance chain... */ while (gtype != G_TYPE_INVALID && default_value == NULL) { default_value = property_get_default_for_type (property, gtype); gtype = g_type_parent (gtype); } if (default_value != NULL) goto lcopy; /* ... and eventually check the implemented interfaces */ if (default_value == NULL) { GType *ifaces; guint n_ifaces; gtype = G_OBJECT_TYPE (gobject); ifaces = g_type_interfaces (gtype, &n_ifaces); while (n_ifaces-- && default_value == NULL) { gtype = ifaces[n_ifaces]; default_value = property_get_default_for_type (property, gtype); } g_free (ifaces); } if (default_value != NULL) goto lcopy; /* if the property hasn't been overridden then we look for the default */ default_value = property_get_default_for_type (property, G_TYPE_INVALID); lcopy: if (default_value != NULL) g_value_copy (default_value, &value); else g_critical (G_STRLOC ": No default value of property '%s' " "was found for type '%s'", G_PARAM_SPEC (property)->name, G_OBJECT_TYPE_NAME (gobject)); va_start (var_args, gobject); G_VALUE_LCOPY (&value, var_args, 0, &error); if (error != NULL) { g_warning (G_STRLOC ": %s", error); g_free (error); } va_end (var_args); g_value_unset (&value); } /** * g_property_override_default: * @property: a #GProperty * @class_gtype: the type of the class overriding the default * @...: the new default value for the property * * Overrides the default value of @property for the given class type. * * Since: 2.36 */ void g_property_override_default (GProperty *property, GType class_gtype, ...) { GValue *value; GType p_type; gchar *error; va_list var_args; g_return_if_fail (G_IS_PROPERTY (property)); g_return_if_fail (G_PARAM_SPEC (property)->value_type != G_TYPE_INVALID); g_return_if_fail (g_type_name (class_gtype) != 0); p_type = G_PARAM_SPEC (property)->value_type; va_start (var_args, class_gtype); value = g_new0 (GValue, 1); G_VALUE_COLLECT_INIT (value, p_type, var_args, 0, &error); if (error != NULL) { g_critical (G_STRLOC ": %s", error); g_free (error); g_value_unset (value); g_free (value); } else { /* takes ownership of the GValue */ property_set_default_for_type (property, class_gtype, value); } va_end (var_args); } /** * g_property_set_va: * @property: a #GProperty * @gobject: a #GObject instance * @flags: collection flags, as a bitwise or of #GPropertyCollectFlags values * @args: the value to set, inside a pointer to a #va_list * * Sets the value of @property for the given #GObject instance. * * This function is the va_list variant of g_property_set(). * * Return value: %TRUE if the value was set, and %FALSE otherwise * * Since: 2.36 */ gboolean g_property_set_va (GProperty *property, gpointer gobject, GPropertyCollectFlags flags, va_list *args) { gboolean retval; GType gtype; g_return_val_if_fail (G_IS_PROPERTY (property), FALSE); g_return_val_if_fail (G_IS_OBJECT (gobject), FALSE); g_return_val_if_fail (property->is_installed, FALSE); g_object_ref (gobject); gtype = ((GParamSpec *) property)->value_type; switch (G_TYPE_FUNDAMENTAL (gtype)) { case G_TYPE_BOOLEAN: retval = g_boolean_property_set_value (property, gobject, va_arg (*args, gboolean)); break; case G_TYPE_INT: switch (property->type_size) { case 1: retval = g_int8_property_set_value (property, gobject, va_arg (*args, gint)); break; case 2: retval = g_int16_property_set_value (property, gobject, va_arg (*args, gint)); break; case 4: retval = g_int32_property_set_value (property, gobject, va_arg (*args, gint)); break; default: retval = g_int_property_set_value (property, gobject, va_arg (*args, gint)); break; } break; case G_TYPE_INT64: retval = g_int64_property_set_value (property, gobject, va_arg (*args, gint64)); break; case G_TYPE_LONG: retval = g_long_property_set_value (property, gobject, va_arg (*args, glong)); break; case G_TYPE_UINT: switch (property->type_size) { case 1: retval = g_uint8_property_set_value (property, gobject, va_arg (*args, guint)); break; case 2: retval = g_uint16_property_set_value (property, gobject, va_arg (*args, guint)); break; case 4: retval = g_uint32_property_set_value (property, gobject, va_arg (*args, guint)); break; default: retval = g_uint_property_set_value (property, gobject, va_arg (*args, guint)); break; } break; case G_TYPE_UINT64: retval = g_uint64_property_set_value (property, gobject, va_arg (*args, guint64)); break; case G_TYPE_ULONG: retval = g_ulong_property_set_value (property, gobject, va_arg (*args, gulong)); break; case G_TYPE_ENUM: retval = g_enum_property_set_value (property, gobject, va_arg (*args, glong)); break; case G_TYPE_FLAGS: retval = g_flags_property_set_value (property, gobject, va_arg (*args, gulong)); break; case G_TYPE_FLOAT: retval = g_float_property_set_value (property, gobject, va_arg (*args, gdouble)); break; case G_TYPE_DOUBLE: retval = g_double_property_set_value (property, gobject, va_arg (*args, gdouble)); break; case G_TYPE_STRING: retval = g_string_property_set_value (property, gobject, va_arg (*args, gchar *)); break; case G_TYPE_BOXED: retval = g_boxed_property_set_value (property, gobject, va_arg (*args, gpointer)); break; case G_TYPE_OBJECT: retval = g_object_property_set_value (property, gobject, va_arg (*args, gpointer)); break; case G_TYPE_POINTER: retval = g_pointer_property_set_value (property, gobject, va_arg (*args, gpointer)); break; default: g_critical (G_STRLOC ": Invalid type %s", g_type_name (gtype)); retval = FALSE; break; } g_object_unref (gobject); return retval; } /** * g_property_get_va: * @property: a #GProperty * @gobject: a #GObject instance * @flags: collection flags * @args: a pointer to a #va_list with the property * * Retrieves the value of @property for the given #GObject instance. * * This function is the va_list variant of g_property_get(). * * Return value: %TRUE if the value was successfully retrieved, and * %FALSE otherwise * * Since: 2.36 */ gboolean g_property_get_va (GProperty *property, gpointer gobject, GPropertyCollectFlags flags, va_list *args) { GType gtype; gpointer ret_p = NULL; g_return_val_if_fail (G_IS_PROPERTY (property), FALSE); g_return_val_if_fail (G_IS_OBJECT (gobject), FALSE); g_return_val_if_fail (property->is_installed, FALSE); gtype = G_PARAM_SPEC (property)->value_type; ret_p = va_arg (*args, gpointer); if (ret_p == NULL) { g_critical (G_STRLOC ": value location for a property of type '%s' passed as NULL", g_type_name (gtype)); return FALSE; } switch (G_TYPE_FUNDAMENTAL (gtype)) { case G_TYPE_BOOLEAN: (* (gboolean *) ret_p) = g_boolean_property_get_value (property, gobject); break; case G_TYPE_INT: switch (property->type_size) { case 1: (* (gint8 *) ret_p) = g_int8_property_get_value (property, gobject); break; case 2: (* (gint16 *) ret_p) = g_int16_property_get_value (property, gobject); break; case 4: (* (gint32 *) ret_p) = g_int32_property_get_value (property, gobject); break; default: (* (gint *) ret_p) = g_int_property_get_value (property, gobject); break; } break; case G_TYPE_INT64: (* (gint64 *) ret_p) = g_int64_property_get_value (property, gobject); break; case G_TYPE_LONG: (* (glong *) ret_p) = g_long_property_get_value (property, gobject); break; case G_TYPE_UINT: switch (property->type_size) { case 1: (* (guint8 *) ret_p) = g_uint8_property_get_value (property, gobject); break; case 2: (* (guint16 *) ret_p) = g_uint16_property_get_value (property, gobject); break; case 4: (* (guint32 *) ret_p) = g_uint32_property_get_value (property, gobject); break; default: (* (guint *) ret_p) = g_uint_property_get_value (property, gobject); break; } break; case G_TYPE_UINT64: (* (guint64 *) ret_p) = g_uint64_property_get_value (property, gobject); break; case G_TYPE_ULONG: (* (gulong *) ret_p) = g_ulong_property_get_value (property, gobject); break; case G_TYPE_ENUM: (* (glong *) ret_p) = g_enum_property_get_value (property, gobject); break; case G_TYPE_FLAGS: (* (gulong *) ret_p) = g_flags_property_get_value (property, gobject); break; case G_TYPE_FLOAT: (* (gfloat *) ret_p) = g_float_property_get_value (property, gobject); break; case G_TYPE_DOUBLE: (* (gdouble *) ret_p) = g_double_property_get_value (property, gobject); break; case G_TYPE_STRING: { const gchar *value; value = g_string_property_get_value (property, gobject); if (((flags & G_PROPERTY_COLLECT_COPY) != 0) && (property->flags & G_PROPERTY_COPY_GET) == 0) { (* (gchar **) ret_p) = g_strdup (value); } else (* (gconstpointer *) ret_p) = value; } break; case G_TYPE_BOXED: { gpointer boxed; boxed = g_boxed_property_get_value (property, gobject); if (((flags & G_PROPERTY_COLLECT_COPY) != 0) && (property->flags & G_PROPERTY_COPY_GET) == 0) { if (boxed != NULL) (* (gpointer *) ret_p) = g_boxed_copy (gtype, boxed); else (* (gpointer *) ret_p) = NULL; } else (* (gpointer *) ret_p) = (gpointer) boxed; } break; case G_TYPE_OBJECT: { gpointer obj = g_object_property_get_value (property, gobject); if ((((flags & G_PROPERTY_COLLECT_REF) != 0) && (property->flags & G_PROPERTY_COPY_GET) == 0) && (obj != NULL)) { (* (gpointer *) ret_p) = g_object_ref (obj); } else (* (gpointer *) ret_p) = obj; } break; case G_TYPE_POINTER: (* (gpointer *) ret_p) = g_pointer_property_get_value (property, gobject); break; default: g_critical (G_STRLOC ": Invalid type %s", g_type_name (gtype)); return FALSE; } return TRUE; } /** * g_property_set: * @property: a #GProperty * @gobject: a #GObject instance * @...: the value to be set * * Sets the value of the @property for the given #GObject instance. * * The value will either be copied or have its reference count increased. * * Since: 2.36 */ gboolean g_property_set (GProperty *property, gpointer gobject, ...) { va_list args; gboolean res; va_start (args, gobject); res = g_property_set_va (property, gobject, 0, &args); va_end (args); return res; } /** * g_property_get: * @property: a #GProperty * @gobject: a #GObject instance * @...: a pointer to the value to be retrieved * * Retrieves the value of the @property for the given #GObject instance. * * Since: 2.36 */ gboolean g_property_get (GProperty *property, gpointer gobject, ...) { va_list args; gboolean retval; va_start (args, gobject); retval = g_property_get_va (property, gobject, 0, &args); va_end (args); return retval; } /** * g_property_set_value: * @property: a #GProperty * @gobject: a #GObject instance * @value: a #GValue * * Sets the value of the @property for the given #GObject instance * by unboxing it from the #GValue, honouring eventual transformation * functions between the #GValue type and the property type. * * Since: 2.36 */ void g_property_set_value (GProperty *property, gpointer gobject, const GValue *value) { GValue copy = { 0, }; GType gtype; g_return_if_fail (G_IS_PROPERTY (property)); g_return_if_fail (G_IS_OBJECT (gobject)); g_return_if_fail (value != NULL); g_return_if_fail (property->is_installed); gtype = G_PARAM_SPEC (property)->value_type; g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (value), gtype)); g_value_init (©, gtype); if (!g_value_transform (value, ©)) { g_critical (G_STRLOC ": Unable to transform a value of type '%s' " "into a value of type '%s'", g_type_name (G_VALUE_TYPE (value)), g_type_name (gtype)); return; } g_object_ref (gobject); switch (G_TYPE_FUNDAMENTAL (gtype)) { case G_TYPE_BOOLEAN: g_boolean_property_set_value (property, gobject, g_value_get_boolean (©)); break; case G_TYPE_INT: { gint val = g_value_get_int (©); switch (property->type_size) { case 1: g_int8_property_set_value (property, gobject, val); break; case 2: g_int16_property_set_value (property, gobject, val); break; case 4: g_int32_property_set_value (property, gobject, val); break; default: g_int_property_set_value (property, gobject, val); break; } } break; case G_TYPE_INT64: g_int64_property_set_value (property, gobject, g_value_get_int64 (©)); break; case G_TYPE_LONG: g_long_property_set_value (property, gobject, g_value_get_long (©)); break; case G_TYPE_UINT: { guint val = g_value_get_uint (©); switch (property->type_size) { case 1: g_uint8_property_set_value (property, gobject, val); break; case 2: g_uint16_property_set_value (property, gobject, val); break; case 4: g_uint32_property_set_value (property, gobject, val); break; default: g_uint_property_set_value (property, gobject, val); break; } } break; case G_TYPE_UINT64: g_uint64_property_set_value (property, gobject, g_value_get_uint64 (©)); break; case G_TYPE_ULONG: g_ulong_property_set_value (property, gobject, g_value_get_ulong (©)); break; case G_TYPE_FLOAT: g_float_property_set_value (property, gobject, g_value_get_float (©)); break; case G_TYPE_DOUBLE: g_double_property_set_value (property, gobject, g_value_get_double (©)); break; case G_TYPE_ENUM: g_enum_property_set_value (property, gobject, g_value_get_enum (©)); break; case G_TYPE_FLAGS: g_flags_property_set_value (property, gobject, g_value_get_flags (©)); break; case G_TYPE_STRING: g_string_property_set_value (property, gobject, g_value_get_string (©)); break; case G_TYPE_BOXED: g_boxed_property_set_value (property, gobject, g_value_get_boxed (©)); break; case G_TYPE_OBJECT: g_object_property_set_value (property, gobject, g_value_get_object (©)); break; case G_TYPE_POINTER: g_pointer_property_set_value (property, gobject, g_value_get_pointer (©)); break; default: g_critical (G_STRLOC ": Invalid type %s", g_type_name (G_VALUE_TYPE (©))); break; } g_object_unref (gobject); g_value_unset (©); } /** * g_property_get_value: * @property: a #GProperty * @gobject: a #GObject instance * @value: a #GValue, initialized to the type of the property or to a * type that satisfies the transformable relation * * Retrieves the value of @property for the object instance, and * boxes it inside a #GValue, honouring eventual transformation * functions between the #GValue type and the property type. * * Since: 2.36 */ void g_property_get_value (GProperty *property, gpointer gobject, GValue *value) { GType gtype; GValue copy = { 0, }; g_return_if_fail (G_IS_PROPERTY (property)); g_return_if_fail (G_IS_OBJECT (gobject)); g_return_if_fail (value != NULL); g_return_if_fail (property->is_installed); gtype = G_PARAM_SPEC (property)->value_type; g_return_if_fail (g_value_type_transformable (G_VALUE_TYPE (value), gtype)); g_value_init (©, gtype); switch (G_TYPE_FUNDAMENTAL (gtype)) { case G_TYPE_BOOLEAN: g_value_set_boolean (©, g_boolean_property_get_value (property, gobject)); break; case G_TYPE_INT: { gint val; switch (property->type_size) { case 1: val = g_int8_property_get_value (property, gobject); break; case 2: val = g_int16_property_get_value (property, gobject); break; case 4: val = g_int32_property_get_value (property, gobject); break; default: val = g_int_property_get_value (property, gobject); break; } g_value_set_int (©, val); } break; case G_TYPE_INT64: g_value_set_int64 (©, g_int64_property_get_value (property, gobject)); break; case G_TYPE_LONG: g_value_set_long (©, g_long_property_get_value (property, gobject)); break; case G_TYPE_UINT: { guint val; switch (property->type_size) { case 1: val = g_uint8_property_get_value (property, gobject); break; case 2: val = g_uint16_property_get_value (property, gobject); break; case 4: val = g_uint32_property_get_value (property, gobject); break; default: val = g_uint_property_get_value (property, gobject); break; } g_value_set_uint (©, val); } break; case G_TYPE_UINT64: g_value_set_uint64 (©, g_uint64_property_get_value (property, gobject)); break; case G_TYPE_ULONG: g_value_set_ulong (©, g_ulong_property_get_value (property, gobject)); break; case G_TYPE_STRING: g_value_set_string (©, g_string_property_get_value (property, gobject)); break; case G_TYPE_CHAR: g_value_set_schar (©, g_int8_property_get_value (property, gobject)); break; case G_TYPE_UCHAR: g_value_set_uchar (©, g_uint8_property_get_value (property, gobject)); break; case G_TYPE_ENUM: g_value_set_enum (©, g_enum_property_get_value (property, gobject)); break; case G_TYPE_FLAGS: g_value_set_flags (©, g_flags_property_get_value (property, gobject)); break; case G_TYPE_FLOAT: g_value_set_float (©, g_float_property_get_value (property, gobject)); break; case G_TYPE_DOUBLE: g_value_set_double (©, g_double_property_get_value (property, gobject)); break; case G_TYPE_BOXED: g_value_set_boxed (©, g_boxed_property_get_value (property, gobject)); break; case G_TYPE_OBJECT: g_value_set_object (©, g_object_property_get_value (property, gobject)); break; case G_TYPE_POINTER: g_value_set_pointer (©, g_pointer_property_get_value (property, gobject)); break; default: g_critical (G_STRLOC ": Invalid type %s", g_type_name (gtype)); break; } if (!g_value_transform (©, value)) { g_critical (G_STRLOC ": Unable to transform a value of type '%s' into " "a value of type '%s'", g_type_name (gtype), g_type_name (G_VALUE_TYPE (value))); } g_value_unset (©); } /** * g_property_get_value_type: * @property: a #GProperty * * Retrieves the #GType of the value stored by the property. * * If a prerequisite type has been set, it will be the returned type. * * Return value: a #GType * * Since: 2.36 */ GType g_property_get_value_type (GProperty *property) { g_return_val_if_fail (G_IS_PROPERTY (property), G_TYPE_INVALID); return G_PARAM_SPEC (property)->value_type; } /** * g_property_validate: * @property: a #GProperty * @...: the value to validate * * Validates the passed value against the validation rules of * the @property. * * Return value: %TRUE if the value is valid, and %FALSE otherwise * * Since: 2.36 */ gboolean g_property_validate (GProperty *property, ...) { gboolean retval = FALSE; GType gtype; va_list args; g_return_val_if_fail (G_IS_PROPERTY (property), FALSE); va_start (args, property); gtype = G_PARAM_SPEC (property)->value_type; switch (G_TYPE_FUNDAMENTAL (gtype)) { case G_TYPE_BOOLEAN: retval = g_boolean_property_validate (property, va_arg (args, gboolean)); break; case G_TYPE_INT: switch (property->type_size) { case 1: retval = g_int8_property_validate (property, va_arg (args, gint)); break; case 2: retval = g_int16_property_validate (property, va_arg (args, gint)); break; case 4: retval = g_int32_property_validate (property, va_arg (args, gint)); break; default: retval = g_int_property_validate (property, va_arg (args, gint)); break; } break; case G_TYPE_INT64: retval = g_int64_property_validate (property, va_arg (args, gint64)); break; case G_TYPE_LONG: retval = g_long_property_validate (property, va_arg (args, glong)); break; case G_TYPE_UINT: switch (property->type_size) { case 1: retval = g_uint8_property_validate (property, va_arg (args, guint)); break; case 2: retval = g_uint16_property_validate (property, va_arg (args, guint)); break; case 4: retval = g_uint32_property_validate (property, va_arg (args, guint)); break; default: retval = g_uint_property_validate (property, va_arg (args, guint)); break; } break; case G_TYPE_UINT64: retval = g_uint64_property_validate (property, va_arg (args, guint64)); break; case G_TYPE_ULONG: retval = g_ulong_property_validate (property, va_arg (args, gulong)); break; case G_TYPE_FLOAT: retval = g_float_property_validate (property, va_arg (args, gdouble)); break; case G_TYPE_DOUBLE: retval = g_double_property_validate (property, va_arg (args, gdouble)); break; case G_TYPE_ENUM: retval = g_enum_property_validate (property, va_arg (args, glong)); break; case G_TYPE_FLAGS: retval = g_enum_property_validate (property, va_arg (args, gulong)); break; case G_TYPE_STRING: retval = g_string_property_validate (property, va_arg (args, gchar *)); break; case G_TYPE_BOXED: retval = g_boxed_property_validate (property, va_arg (args, gpointer)); break; case G_TYPE_OBJECT: retval = g_object_property_validate (property, va_arg (args, gpointer)); break; default: g_critical (G_STRLOC ": Invalid type %s", g_type_name (gtype)); break; } va_end (args); return retval; } /** * g_property_validate_value: * @property: a #GProperty * @value: a #GValue initialized to the property type or to a type * that is transformable into the property type * * Validates the value stored inside the passed #GValue against the * @property rules. * * Return value: %TRUE if the value is valid, and %FALSE otherwise * * Since: 2.36 */ gboolean g_property_validate_value (GProperty *property, GValue *value) { GValue copy = { 0, }; gboolean retval = FALSE; GType gtype; g_return_val_if_fail (G_IS_PROPERTY (property), FALSE); g_return_val_if_fail (value != NULL, FALSE); gtype = G_PARAM_SPEC (property)->value_type; g_return_val_if_fail (g_value_type_transformable (gtype, G_VALUE_TYPE (value)), FALSE); g_value_init (©, gtype); if (!g_value_transform (value, ©)) { g_critical (G_STRLOC ": Unable to transform a value of type '%s' " "to a value of type '%s'", g_type_name (G_VALUE_TYPE (value)), g_type_name (gtype)); g_value_unset (©); return FALSE; } switch (G_TYPE_FUNDAMENTAL (gtype)) { case G_TYPE_BOOLEAN: retval = g_boolean_property_validate (property, g_value_get_boolean (©)); break; case G_TYPE_INT: { gint val = g_value_get_int (©); switch (property->type_size) { case 1: retval = g_int8_property_validate (property, val); break; case 2: retval = g_int16_property_validate (property, val); break; case 4: retval = g_int32_property_validate (property, val); break; default: retval = g_int_property_validate (property, val); break; } } break; case G_TYPE_INT64: retval = g_int64_property_validate (property, g_value_get_int64 (©)); break; case G_TYPE_LONG: retval = g_long_property_validate (property, g_value_get_long (©)); break; case G_TYPE_UINT: { guint val = g_value_get_uint (©); switch (property->type_size) { case 1: retval = g_uint8_property_validate (property, val); break; case 2: retval = g_uint16_property_validate (property, val); break; case 4: retval = g_uint32_property_validate (property, val); break; default: retval = g_uint_property_validate (property, val); break; } } break; case G_TYPE_UINT64: retval = g_uint64_property_validate (property, g_value_get_uint64 (©)); break; case G_TYPE_ULONG: retval = g_ulong_property_validate (property, g_value_get_ulong (©)); break; case G_TYPE_FLOAT: retval = g_float_property_validate (property, g_value_get_float (©)); break; case G_TYPE_DOUBLE: retval = g_double_property_validate (property, g_value_get_double (©)); break; case G_TYPE_ENUM: retval = g_enum_property_validate (property, g_value_get_enum (©)); break; case G_TYPE_FLAGS: retval = g_flags_property_validate (property, g_value_get_flags (©)); break; case G_TYPE_STRING: retval = g_string_property_validate (property, g_value_get_string (©)); break; case G_TYPE_BOXED: retval = g_boxed_property_validate (property, g_value_get_boxed (©)); break; case G_TYPE_OBJECT: retval = g_object_property_validate (property, g_value_get_object (©)); break; default: g_critical (G_STRLOC ": Invalid type %s", g_type_name (gtype)); retval = FALSE; break; } g_value_unset (©); return retval; } /** * g_property_is_writable: * @property: a #GProperty * * Checks whether the @property has the %G_PROPERTY_WRITABLE flag set. * * Return value: %TRUE if the flag is set, and %FALSE otherwise * * Since: 2.36 */ gboolean g_property_is_writable (GProperty *property) { g_return_val_if_fail (G_IS_PROPERTY (property), FALSE); return (property->flags & G_PROPERTY_WRITABLE) != 0; } /** * g_property_is_readable: * @property: a #GProperty * * Checks whether the @property has the %G_PROPERTY_READABLE flag set. * * Return value: %TRUE if the flag is set, and %FALSE otherwise * * Since: 2.36 */ gboolean g_property_is_readable (GProperty *property) { g_return_val_if_fail (G_IS_PROPERTY (property), FALSE); return (property->flags & G_PROPERTY_READABLE) != 0; } /** * g_property_is_deprecated: * @property: a #GProperty * * Checks whether the @property has the %G_PROPERTY_DEPRECATED flag set. * * Return value: %TRUE if the flag is set, and %FALSE otherwise * * Since: 2.36 */ gboolean g_property_is_deprecated (GProperty *property) { g_return_val_if_fail (G_IS_PROPERTY (property), FALSE); return (property->flags & G_PROPERTY_DEPRECATED) != 0; } /** * g_property_is_atomic: * @property: a #GProperty * * Checks whether the @property has the %G_PROPERTY_ATOMIC flag set. * * Return value: %TRUE if the flag is set, and %FALSE otherwise * * Since: 2.36 */ gboolean g_property_is_atomic (GProperty *property) { g_return_val_if_fail (G_IS_PROPERTY (property), FALSE); return (property->flags & G_PROPERTY_ATOMIC) != 0; } /** * g_property_is_copy_set: * @property: a #GProperty * * Checks whether the @property has the %G_PROPERTY_COPY_SET flag set. * * Return value: %TRUE if the flag is set, and %FALSE otherwise * * Since: 2.36 */ gboolean g_property_is_copy_set (GProperty *property) { g_return_val_if_fail (G_IS_PROPERTY (property), FALSE); return (property->flags & G_PROPERTY_COPY_SET) != 0; } /** * g_property_is_copy_get: * @property: a #GProperty * * Checks whether the @property has the %G_PROPERTY_COPY_GET flag set. * * Return value: %TRUE if the flag is set, and %FALSE otherwise * * Since: 2.36 */ gboolean g_property_is_copy_get (GProperty *property) { g_return_val_if_fail (G_IS_PROPERTY (property), FALSE); return (property->flags & G_PROPERTY_COPY_GET) != 0; } gboolean g_property_is_direct_set (GProperty *property) { g_return_val_if_fail (G_IS_PROPERTY (property), FALSE); return (property->flags & G_PROPERTY_DIRECT_SET) != 0; } gboolean g_property_is_direct_get (GProperty *property) { g_return_val_if_fail (G_IS_PROPERTY (property), FALSE); return (property->flags & G_PROPERTY_DIRECT_GET) != 0; } /** * g_property_lock: * @property: a #GProperty * @gobject: a #GObject * * Locks a property on the given object. * * Use g_property_unlock() to unlock the property when done. * * Since: 2.36 */ void g_property_lock (GProperty *property, gpointer gobject) { g_return_if_fail (G_IS_PROPERTY (property)); g_return_if_fail (G_IS_OBJECT (gobject)); property_lock_internal (property, gobject); } /** * g_property_unlock: * @property: a #GProperty * @gobject: a #GObject * * Unlocks a property on the given object previously locked * using g_property_lock(). * * Since: 2.36 */ void g_property_unlock (GProperty *property, gpointer gobject) { g_return_if_fail (G_IS_PROPERTY (property)); g_return_if_fail (G_IS_OBJECT (gobject)); property_unlock_internal (property, gobject); } /** * g_property_set_lock_functions: * @property: a #GProperty * @lock_func: (allow-none): the function to be called when locking * the @property, or %NULL for the default locking function * @unlock_func: (allow-none): the function to be called when unlocking * the @property, or %NULL for the default unlocking function * * Replaces the locking and unlocking functions for @property with * custom functions. * * Since: 2.36 */ void g_property_set_lock_functions (GProperty *property, GPropertyLockFunc lock_func, GPropertyUnlockFunc unlock_func) { g_return_if_fail (G_IS_PROPERTY (property)); g_return_if_fail (!property->is_installed); if (lock_func == NULL) g_return_if_fail (unlock_func == NULL); property->lock_func = lock_func; property->unlock_func = unlock_func; } static void property_finalize (GParamSpec *pspec) { GParamSpecClass *parent_class = g_type_class_peek (g_type_parent (G_TYPE_PROPERTY)); parent_class->finalize (pspec); } static void property_set_default (GParamSpec *pspec, GValue *value) { GProperty *property = G_PROPERTY (pspec); const GValue *default_value; default_value = property_get_default_for_type (property, G_TYPE_INVALID); if (default_value != NULL) g_value_copy (default_value, value); } static gboolean property_validate (GParamSpec *pspec, GValue *value) { GProperty *property = G_PROPERTY (pspec); if (!g_value_type_transformable (G_VALUE_TYPE (value), pspec->value_type)) return TRUE; return !g_property_validate_value (property, value); } static gint property_values_cmp (GParamSpec *pspec, const GValue *value1, const GValue *value2) { return 0; } static void property_class_init (GParamSpecClass *klass) { klass->value_type = G_TYPE_INVALID; klass->value_set_default = property_set_default; klass->value_validate = property_validate; klass->values_cmp = property_values_cmp; klass->finalize = property_finalize; } static void property_init (GParamSpec *pspec) { GProperty *property = G_PROPERTY (pspec); pspec->value_type = G_TYPE_INVALID; property->field_offset = -1; property->priv_offset = -1; property->lock_func = NULL; property->unlock_func = NULL; } GType g_property_get_type (void) { static volatile gsize pspec_type_id__volatile = 0; if (g_once_init_enter (&pspec_type_id__volatile)) { const GTypeInfo info = { sizeof (GParamSpecClass), NULL, NULL, (GClassInitFunc) property_class_init, NULL, NULL, sizeof (GProperty), 0, (GInstanceInitFunc) property_init, }; GType pspec_type_id = g_type_register_static (G_TYPE_PARAM, g_intern_static_string ("GProperty"), &info, 0); g_once_init_leave (&pspec_type_id__volatile, pspec_type_id); } return pspec_type_id__volatile; }