* 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.
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
#include "gparam.h"
#include "gparamspecs.h"
#include "gvaluecollector.h"
-
+#include "gtype-private.h"
/**
* SECTION:gparamspec
* #GParamSpec is an object structure that encapsulates the metadata
* required to specify parameters, such as e.g. #GObject properties.
*
- * <para id="canonical-parameter-name">
- * Parameter names need to start with a letter (a-z or A-Z). Subsequent
- * characters can be letters, numbers or a '-'.
+ * ## Parameter names # {#canonical-parameter-names}
+ *
+ * Parameter names need to start with a letter (a-z or A-Z).
+ * Subsequent characters can be letters, numbers or a '-'.
* All other characters are replaced by a '-' during construction.
- * The result of this replacement is called the canonical name of the
- * parameter.
- * </para>
+ * The result of this replacement is called the canonical name of
+ * the parameter.
*/
#define PARAM_FLOATING_FLAG 0x2
#define G_PARAM_USER_MASK (~0 << G_PARAM_USER_SHIFT)
#define PSPEC_APPLIES_TO_VALUE(pspec, value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_PARAM_SPEC_VALUE_TYPE (pspec)))
-#define G_SLOCK(mutex) g_static_mutex_lock (mutex)
-#define G_SUNLOCK(mutex) g_static_mutex_unlock (mutex)
-
/* --- prototypes --- */
static void g_param_spec_class_base_init (GParamSpecClass *class);
GTypeCValue *collect_values,
guint collect_flags);
+typedef struct
+{
+ GValue default_value;
+} GParamSpecPrivate;
+
+static gint g_param_private_offset;
/* --- functions --- */
+static inline GParamSpecPrivate *
+g_param_spec_get_private (GParamSpec *pspec)
+{
+ return &G_STRUCT_MEMBER (GParamSpecPrivate, pspec, g_param_private_offset);
+}
+
void
-g_param_type_init (void)
+_g_param_type_init (void)
{
static const GTypeFundamentalInfo finfo = {
(G_TYPE_FLAG_CLASSED |
"p", /* lcopy_format */
value_param_lcopy_value, /* lcopy_value */
};
- static const GTypeInfo param_spec_info = {
+ const GTypeInfo param_spec_info = {
sizeof (GParamSpecClass),
(GBaseInitFunc) g_param_spec_class_base_init,
};
GType type;
- /* This should be registred as GParamSpec instead of GParam, for
+ /* This should be registered as GParamSpec instead of GParam, for
* consistency sake, so that type name can be mapped to struct name,
- * However, some language bindings, most noticable the python ones
+ * However, some language bindings, most noticeable the python ones
* depends on the "GParam" identifier, see #548689
*/
type = g_type_register_fundamental (G_TYPE_PARAM, g_intern_static_string ("GParam"), ¶m_spec_info, &finfo, G_TYPE_FLAG_ABSTRACT);
g_assert (type == G_TYPE_PARAM);
+ g_param_private_offset = g_type_add_instance_private (type, sizeof (GParamSpecPrivate));
g_value_register_transform_func (G_TYPE_PARAM, G_TYPE_PARAM, value_param_transform_value);
}
class->value_set_default = NULL;
class->value_validate = NULL;
class->values_cmp = NULL;
+
+ g_type_class_adjust_private_offset (class, &g_param_private_offset);
}
static void
pspec->value_type = class->value_type;
pspec->owner_type = 0;
pspec->qdata = NULL;
- g_datalist_init (&pspec->qdata);
g_datalist_set_flags (&pspec->qdata, PARAM_FLOATING_FLAG);
pspec->ref_count = 1;
pspec->param_id = 0;
static void
g_param_spec_finalize (GParamSpec *pspec)
{
+ GParamSpecPrivate *priv = g_param_spec_get_private (pspec);
+
+ if (priv->default_value.g_type)
+ g_value_reset (&priv->default_value);
+
g_datalist_clear (&pspec->qdata);
- if (!(pspec->flags & G_PARAM_STATIC_NAME))
- g_free (pspec->name);
-
if (!(pspec->flags & G_PARAM_STATIC_NICK))
g_free (pspec->_nick);
}
/**
- * g_param_spec_ref:
+ * g_param_spec_ref: (skip)
* @pspec: a valid #GParamSpec
*
* Increments the reference count of @pspec.
g_param_spec_ref (GParamSpec *pspec)
{
g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
- g_return_val_if_fail (pspec->ref_count > 0, NULL);
g_atomic_int_inc ((int *)&pspec->ref_count);
}
/**
- * g_param_spec_unref:
+ * g_param_spec_unref: (skip)
* @pspec: a valid #GParamSpec
*
* Decrements the reference count of a @pspec.
gboolean is_zero;
g_return_if_fail (G_IS_PARAM_SPEC (pspec));
- g_return_if_fail (pspec->ref_count > 0);
is_zero = g_atomic_int_dec_and_test ((int *)&pspec->ref_count);
* The initial reference count of a newly created #GParamSpec is 1,
* even though no one has explicitly called g_param_spec_ref() on it
* yet. So the initial reference count is flagged as "floating", until
- * someone calls <literal>g_param_spec_ref (pspec); g_param_spec_sink
- * (pspec);</literal> in sequence on it, taking over the initial
+ * someone calls `g_param_spec_ref (pspec); g_param_spec_sink
+ * (pspec);` in sequence on it, taking over the initial
* reference count (thus ending up with a @pspec that has a reference
* count of 1 still, but is not flagged "floating" anymore).
*/
void
g_param_spec_sink (GParamSpec *pspec)
{
- gpointer oldvalue;
+ gsize oldvalue;
g_return_if_fail (G_IS_PARAM_SPEC (pspec));
- g_return_if_fail (pspec->ref_count > 0);
- do
- oldvalue = g_atomic_pointer_get (&pspec->qdata);
- while (!g_atomic_pointer_compare_and_exchange ((void**) &pspec->qdata, oldvalue,
- (gpointer) ((gsize) oldvalue & ~(gsize) PARAM_FLOATING_FLAG)));
- if ((gsize) oldvalue & PARAM_FLOATING_FLAG)
+ oldvalue = g_atomic_pointer_and (&pspec->qdata, ~(gsize)PARAM_FLOATING_FLAG);
+ if (oldvalue & PARAM_FLOATING_FLAG)
g_param_spec_unref (pspec);
}
/**
- * g_param_spec_ref_sink:
+ * g_param_spec_ref_sink: (skip)
* @pspec: a valid #GParamSpec
*
* Convenience function to ref and sink a #GParamSpec.
GParamSpec*
g_param_spec_ref_sink (GParamSpec *pspec)
{
+ gsize oldvalue;
g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
- g_return_val_if_fail (pspec->ref_count > 0, NULL);
- g_param_spec_ref (pspec);
- g_param_spec_sink (pspec);
+ oldvalue = g_atomic_pointer_and (&pspec->qdata, ~(gsize)PARAM_FLOATING_FLAG);
+ if (!(oldvalue & PARAM_FLOATING_FLAG))
+ g_param_spec_ref (pspec);
+
return pspec;
}
*
* Get the name of a #GParamSpec.
*
+ * The name is always an "interned" string (as per g_intern_string()).
+ * This allows for pointer-value comparisons.
+ *
* Returns: the name of @pspec.
*/
-G_CONST_RETURN gchar*
+const gchar *
g_param_spec_get_name (GParamSpec *pspec)
{
g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
*
* Returns: the nickname of @pspec.
*/
-G_CONST_RETURN gchar*
+const gchar *
g_param_spec_get_nick (GParamSpec *pspec)
{
g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
*
* Returns: the short description of @pspec.
*/
-G_CONST_RETURN gchar*
+const gchar *
g_param_spec_get_blurb (GParamSpec *pspec)
{
g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
}
/**
- * g_param_spec_internal:
+ * g_param_spec_internal: (skip)
* @param_type: the #GType for the property; must be derived from #G_TYPE_PARAM
* @name: the canonical name of the property
* @nick: the nickname of the property
* efficient and in fact required when using property names as detail
* strings for signals.
*
- * Beyond the name, #GParamSpec<!-- -->s have two more descriptive
+ * Beyond the name, #GParamSpecs have two more descriptive
* strings associated with them, the @nick, which should be suitable
* for use as a label for the property in a property editor, and the
* @blurb, which should be a somewhat longer description, suitable for
if (flags & G_PARAM_STATIC_NAME)
{
- pspec->name = g_intern_static_string (name);
+ /* pspec->name is not freed if (flags & G_PARAM_STATIC_NAME) */
+ pspec->name = (gchar *) g_intern_static_string (name);
if (!is_canonical (pspec->name))
g_warning ("G_PARAM_STATIC_NAME used with non-canonical pspec name: %s", pspec->name);
}
else
{
- pspec->name = g_strdup (name);
- canonicalize_key (pspec->name);
- g_intern_string (pspec->name);
+ if (is_canonical (name))
+ pspec->name = (gchar *) g_intern_string (name);
+ else
+ {
+ gchar *tmp = g_strdup (name);
+ canonicalize_key (tmp);
+ pspec->name = (gchar *) g_intern_string (tmp);
+ g_free (tmp);
+ }
}
if (flags & G_PARAM_STATIC_NICK)
*
* Gets back user data pointers stored via g_param_spec_set_qdata().
*
- * Returns: the user data pointer set, or %NULL
+ * Returns: (transfer none): the user data pointer set, or %NULL
*/
gpointer
g_param_spec_get_qdata (GParamSpec *pspec,
}
/**
- * g_param_spec_set_qdata_full:
+ * g_param_spec_set_qdata_full: (skip)
* @pspec: the #GParamSpec to set store a user data pointer
* @quark: a #GQuark, naming the user data pointer
* @data: an opaque user data pointer
* be freed
*
* This function works like g_param_spec_set_qdata(), but in addition,
- * a <literal>void (*destroy) (gpointer)</literal> function may be
+ * a `void (*destroy) (gpointer)` function may be
* specified which is called with @data as argument when the @pspec is
* finalized, or the data is being overwritten by a call to
* g_param_spec_set_qdata() with the same @quark.
* function (if any was set). Usually, calling this function is only
* required to update user data pointers with a destroy notifier.
*
- * Returns: the user data pointer set, or %NULL
+ * Returns: (transfer none): the user data pointer set, or %NULL
*/
gpointer
g_param_spec_steal_qdata (GParamSpec *pspec,
*
* Since: 2.4
*
- * Returns: paramspec to which requests on this paramspec should
- * be redirected, or %NULL if none.
+ * Returns: (transfer none): paramspec to which requests on this
+ * paramspec should be redirected, or %NULL if none.
*/
GParamSpec*
g_param_spec_get_redirect_target (GParamSpec *pspec)
g_param_value_defaults (GParamSpec *pspec,
GValue *value)
{
- GValue dflt_value = { 0, };
+ GValue dflt_value = G_VALUE_INIT;
gboolean defaults;
g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
GValue *dest_value,
gboolean strict_validation)
{
- GValue tmp_value = { 0, };
+ GValue tmp_value = G_VALUE_INIT;
g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
g_return_val_if_fail (G_IS_VALUE (src_value), FALSE);
GParamSpec *param = collect_values[0].v_pointer;
if (param->g_type_instance.g_class == NULL)
- return g_strconcat ("invalid unclassed param spec pointer for value type `",
+ return g_strconcat ("invalid unclassed param spec pointer for value type '",
G_VALUE_TYPE_NAME (value),
"'",
NULL);
else if (!g_value_type_compatible (G_PARAM_SPEC_TYPE (param), G_VALUE_TYPE (value)))
- return g_strconcat ("invalid param spec type `",
+ return g_strconcat ("invalid param spec type '",
G_PARAM_SPEC_TYPE_NAME (param),
- "' for value type `",
+ "' for value type '",
G_VALUE_TYPE_NAME (value),
"'",
NULL);
GParamSpec **param_p = collect_values[0].v_pointer;
if (!param_p)
- return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
+ return g_strdup_printf ("value location for '%s' passed as NULL", G_VALUE_TYPE_NAME (value));
if (!value->data[0].v_pointer)
*param_p = NULL;
/**
* GParamSpecPool:
*
- * A #GParamSpecPool maintains a collection of #GParamSpec<!-- -->s which can be
+ * A #GParamSpecPool maintains a collection of #GParamSpecs which can be
* quickly accessed by owner and name. The implementation of the #GObject property
* system uses such a pool to store the #GParamSpecs of the properties all object
* types.
*/
struct _GParamSpecPool
{
- GStaticMutex smutex;
+ GMutex mutex;
gboolean type_prefixing;
GHashTable *hash_table;
};
* property name, like "GtkContainer:border-width". This feature is
* deprecated, so you should always set @type_prefixing to %FALSE.
*
- * Returns: a newly allocated #GParamSpecPool.
+ * Returns: (transfer none): a newly allocated #GParamSpecPool.
*/
GParamSpecPool*
g_param_spec_pool_new (gboolean type_prefixing)
{
- static GStaticMutex init_smutex = G_STATIC_MUTEX_INIT;
+ static GMutex init_mutex;
GParamSpecPool *pool = g_new (GParamSpecPool, 1);
- memcpy (&pool->smutex, &init_smutex, sizeof (init_smutex));
+ memcpy (&pool->mutex, &init_mutex, sizeof (init_mutex));
pool->type_prefixing = type_prefixing != FALSE;
pool->hash_table = g_hash_table_new (param_spec_pool_hash, param_spec_pool_equals);
GParamSpec *pspec,
GType owner_type)
{
- gchar *p;
+ const gchar *p;
if (pool && pspec && owner_type > 0 && pspec->owner_type == 0)
{
- G_SLOCK (&pool->smutex);
for (p = pspec->name; *p; p++)
{
if (!strchr (G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-_", *p))
{
g_warning (G_STRLOC ": pspec name \"%s\" contains invalid characters", pspec->name);
- G_SUNLOCK (&pool->smutex);
return;
}
}
-
+ g_mutex_lock (&pool->mutex);
pspec->owner_type = owner_type;
g_param_spec_ref (pspec);
g_hash_table_insert (pool->hash_table, pspec, pspec);
- G_SUNLOCK (&pool->smutex);
+ g_mutex_unlock (&pool->mutex);
}
else
{
{
if (pool && pspec)
{
- G_SLOCK (&pool->smutex);
+ g_mutex_lock (&pool->mutex);
if (g_hash_table_remove (pool->hash_table, pspec))
g_param_spec_unref (pspec);
else
- g_warning (G_STRLOC ": attempt to remove unknown pspec `%s' from pool", pspec->name);
- G_SUNLOCK (&pool->smutex);
+ g_warning (G_STRLOC ": attempt to remove unknown pspec '%s' from pool", pspec->name);
+ g_mutex_unlock (&pool->mutex);
}
else
{
if (!pspec && !is_canonical (param_name))
{
+ gchar *canonical;
+
+ canonical = g_strdup (key.name);
+ canonicalize_key (canonical);
+
/* try canonicalized form */
- key.name = g_strdup (param_name);
+ key.name = canonical;
key.owner_type = owner_type;
-
- canonicalize_key (key.name);
+
if (walk_ancestors)
- do
- {
- pspec = g_hash_table_lookup (hash_table, &key);
- if (pspec)
- {
- g_free (key.name);
- return pspec;
- }
- key.owner_type = g_type_parent (key.owner_type);
- }
- while (key.owner_type);
+ do
+ {
+ pspec = g_hash_table_lookup (hash_table, &key);
+ if (pspec)
+ {
+ g_free (canonical);
+ return pspec;
+ }
+ key.owner_type = g_type_parent (key.owner_type);
+ }
+ while (key.owner_type);
else
- pspec = g_hash_table_lookup (hash_table, &key);
- g_free (key.name);
+ pspec = g_hash_table_lookup (hash_table, &key);
+
+ g_free (canonical);
}
return pspec;
*
* Looks up a #GParamSpec in the pool.
*
- * Returns: The found #GParamSpec, or %NULL if no matching #GParamSpec was found.
+ * Returns: (transfer none): The found #GParamSpec, or %NULL if no
+ * matching #GParamSpec was found.
*/
GParamSpec*
g_param_spec_pool_lookup (GParamSpecPool *pool,
g_return_val_if_fail (param_name != NULL, NULL);
}
- G_SLOCK (&pool->smutex);
+ g_mutex_lock (&pool->mutex);
delim = pool->type_prefixing ? strchr (param_name, ':') : NULL;
if (!delim)
{
pspec = param_spec_ht_lookup (pool->hash_table, param_name, owner_type, walk_ancestors);
- G_SUNLOCK (&pool->smutex);
+ g_mutex_unlock (&pool->mutex);
return pspec;
}
/* sanity check, these cases don't make a whole lot of sense */
if ((!walk_ancestors && type != owner_type) || !g_type_is_a (owner_type, type))
{
- G_SUNLOCK (&pool->smutex);
+ g_mutex_unlock (&pool->mutex);
return NULL;
}
owner_type = type;
param_name += l + 2;
pspec = param_spec_ht_lookup (pool->hash_table, param_name, owner_type, walk_ancestors);
- G_SUNLOCK (&pool->smutex);
+ g_mutex_unlock (&pool->mutex);
return pspec;
}
}
/* malformed param_name */
- G_SUNLOCK (&pool->smutex);
+ g_mutex_unlock (&pool->mutex);
return NULL;
}
* @pool: a #GParamSpecPool
* @owner_type: the owner to look for
*
- * Gets an #GList of all #GParamSpec<!-- -->s owned by @owner_type in
+ * Gets an #GList of all #GParamSpecs owned by @owner_type in
* the pool.
*
- * Returns: a #GList of all #GParamSpec<!-- -->s owned by @owner_type
- * in the pool#GParamSpec<!-- -->s.
+ * Returns: (transfer container) (element-type GObject.ParamSpec): a
+ * #GList of all #GParamSpecs owned by @owner_type in
+ * the pool#GParamSpecs.
*/
GList*
g_param_spec_pool_list_owned (GParamSpecPool *pool,
g_return_val_if_fail (pool != NULL, NULL);
g_return_val_if_fail (owner_type > 0, NULL);
- G_SLOCK (&pool->smutex);
+ g_mutex_lock (&pool->mutex);
data[0] = NULL;
data[1] = (gpointer) owner_type;
g_hash_table_foreach (pool->hash_table, pool_list, &data);
- G_SUNLOCK (&pool->smutex);
+ g_mutex_unlock (&pool->mutex);
return data[0];
}
* g_param_spec_pool_list:
* @pool: a #GParamSpecPool
* @owner_type: the owner to look for
- * @n_pspecs_p: return location for the length of the returned array
+ * @n_pspecs_p: (out): return location for the length of the returned array
*
- * Gets an array of all #GParamSpec<!-- -->s owned by @owner_type in
+ * Gets an array of all #GParamSpecs owned by @owner_type in
* the pool.
*
- * Returns: a newly allocated array containing pointers to all
- * #GParamSpec<!-- -->s owned by @owner_type in the pool
+ * Returns: (array length=n_pspecs_p) (transfer container): a newly
+ * allocated array containing pointers to all #GParamSpecs
+ * owned by @owner_type in the pool
*/
GParamSpec**
g_param_spec_pool_list (GParamSpecPool *pool,
g_return_val_if_fail (owner_type > 0, NULL);
g_return_val_if_fail (n_pspecs_p != NULL, NULL);
- G_SLOCK (&pool->smutex);
+ g_mutex_lock (&pool->mutex);
*n_pspecs_p = 0;
d = g_type_depth (owner_type);
slists = g_new0 (GSList*, d);
}
*p++ = NULL;
g_free (slists);
- G_SUNLOCK (&pool->smutex);
+ g_mutex_unlock (&pool->mutex);
return pspecs;
}
-/* --- auxillary functions --- */
+/* --- auxiliary functions --- */
typedef struct
{
/* class portion */
/**
* g_value_set_param:
* @value: a valid #GValue of type %G_TYPE_PARAM
- * @param: the #GParamSpec to be set
+ * @param: (allow-none): the #GParamSpec to be set
*
* Set the contents of a %G_TYPE_PARAM #GValue to @param.
*/
}
/**
- * g_value_set_param_take_ownership:
+ * g_value_set_param_take_ownership: (skip)
* @value: a valid #GValue of type %G_TYPE_PARAM
- * @param: the #GParamSpec to be set
+ * @param: (allow-none): the #GParamSpec to be set
*
* This is an internal function introduced mainly for C marshallers.
*
}
/**
- * g_value_take_param:
+ * g_value_take_param: (skip)
* @value: a valid #GValue of type %G_TYPE_PARAM
- * @param: the #GParamSpec to be set
+ * @param: (allow-none): the #GParamSpec to be set
*
* Sets the contents of a %G_TYPE_PARAM #GValue to @param and takes
* over the ownership of the callers reference to @param; the caller
return value->data[0].v_pointer ? g_param_spec_ref (value->data[0].v_pointer) : NULL;
}
+
+/**
+ * g_param_get_default_value:
+ * @param: a #GParamSpec
+ *
+ * Gets the default value of @param as a pointer to a #GValue.
+ *
+ * The #GValue will remain value for the life of @param.
+ *
+ * Returns: a pointer to a #GValue which must not be modified
+ *
+ * Since: 2.38
+ **/
+const GValue *
+g_param_spec_get_default_value (GParamSpec *pspec)
+{
+ GParamSpecPrivate *priv = g_param_spec_get_private (pspec);
+
+ /* We use the type field of the GValue as the key for the once because
+ * it will be zero before it is initialised and non-zero after. We
+ * have to take care that we don't write a non-zero value to the type
+ * field before we are completely done, however, because then another
+ * thread could come along and find the value partially-initialised.
+ *
+ * In order to accomplish this we store the default value in a
+ * stack-allocated GValue. We then set the type field in that value
+ * to zero and copy the contents into place. We then end by storing
+ * the type as the last step in order to ensure that we're completely
+ * done before a g_once_init_enter() could take the fast path in
+ * another thread.
+ */
+ if (g_once_init_enter (&priv->default_value.g_type))
+ {
+ GValue default_value = G_VALUE_INIT;
+
+ g_value_init (&default_value, pspec->value_type);
+ g_param_value_set_default (pspec, &default_value);
+
+ /* store all but the type */
+ default_value.g_type = 0;
+ priv->default_value = default_value;
+
+ g_once_init_leave (&priv->default_value.g_type, pspec->value_type);
+ }
+
+ return &priv->default_value;
+}