Migrating docs.
[platform/upstream/glib.git] / gobject / gparam.c
1 /* GObject - GLib Type, Object, Parameter and Signal Library
2  * Copyright (C) 1997-1999, 2000-2001 Tim Janik and Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General
15  * Public License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 /**
20  * SECTION:gparamspec
21  * @Short_description: Metadata for parameter specifications
22  * @See_also:g_object_class_install_property(), g_object_set(), g_object_get(),
23  * g_object_set_property(), g_object_get_property(), g_value_register_transform_func()
24  * @Title: GParamSpec
25  * 
26  * #GParamSpec is an object structure that encapsulates the metadata
27  * required to specify parameters, such as e.g. #GObject properties.
28  * 
29  * <para id="canonical-parameter-name">
30  * Parameter names need to start with a letter (a-z or A-Z). Subsequent
31  * characters can be letters, numbers or a '-'.
32  * All other characters are replaced by a '-' during construction.
33  * The result of this replacement is called the canonical name of the
34  * parameter.
35  * </para>
36  */
37 /*
38  * MT safe
39  */
40
41 #include        "gparam.h"
42 #include        "gparamspecs.h"
43
44 #include        "gvaluecollector.h"
45 #include        "gobjectalias.h"
46 #include        <string.h>
47
48
49
50 /* --- defines --- */
51 #define PARAM_FLOATING_FLAG                     0x2
52 #define G_PARAM_USER_MASK                       (~0 << G_PARAM_USER_SHIFT)
53 #define PSPEC_APPLIES_TO_VALUE(pspec, value)    (G_TYPE_CHECK_VALUE_TYPE ((value), G_PARAM_SPEC_VALUE_TYPE (pspec)))
54 #define G_SLOCK(mutex)                          g_static_mutex_lock (mutex)
55 #define G_SUNLOCK(mutex)                        g_static_mutex_unlock (mutex)
56
57
58 /* --- prototypes --- */
59 static void     g_param_spec_class_base_init     (GParamSpecClass       *class);
60 static void     g_param_spec_class_base_finalize (GParamSpecClass       *class);
61 static void     g_param_spec_class_init          (GParamSpecClass       *class,
62                                                   gpointer               class_data);
63 static void     g_param_spec_init                (GParamSpec            *pspec,
64                                                   GParamSpecClass       *class);
65 static void     g_param_spec_finalize            (GParamSpec            *pspec);
66 static void     value_param_init                (GValue         *value);
67 static void     value_param_free_value          (GValue         *value);
68 static void     value_param_copy_value          (const GValue   *src_value,
69                                                  GValue         *dest_value);
70 static void     value_param_transform_value     (const GValue   *src_value,
71                                                  GValue         *dest_value);
72 static gpointer value_param_peek_pointer        (const GValue   *value);
73 static gchar*   value_param_collect_value       (GValue         *value,
74                                                  guint           n_collect_values,
75                                                  GTypeCValue    *collect_values,
76                                                  guint           collect_flags);
77 static gchar*   value_param_lcopy_value         (const GValue   *value,
78                                                  guint           n_collect_values,
79                                                  GTypeCValue    *collect_values,
80                                                  guint           collect_flags);
81
82
83 /* --- functions --- */
84 void
85 g_param_type_init (void)
86 {
87   static const GTypeFundamentalInfo finfo = {
88     (G_TYPE_FLAG_CLASSED |
89      G_TYPE_FLAG_INSTANTIATABLE |
90      G_TYPE_FLAG_DERIVABLE |
91      G_TYPE_FLAG_DEEP_DERIVABLE),
92   };
93   static const GTypeValueTable param_value_table = {
94     value_param_init,           /* value_init */
95     value_param_free_value,     /* value_free */
96     value_param_copy_value,     /* value_copy */
97     value_param_peek_pointer,   /* value_peek_pointer */
98     "p",                        /* collect_format */
99     value_param_collect_value,  /* collect_value */
100     "p",                        /* lcopy_format */
101     value_param_lcopy_value,    /* lcopy_value */
102   };
103   static const GTypeInfo param_spec_info = {
104     sizeof (GParamSpecClass),
105
106     (GBaseInitFunc) g_param_spec_class_base_init,
107     (GBaseFinalizeFunc) g_param_spec_class_base_finalize,
108     (GClassInitFunc) g_param_spec_class_init,
109     (GClassFinalizeFunc) NULL,
110     NULL,       /* class_data */
111
112     sizeof (GParamSpec),
113     0,          /* n_preallocs */
114     (GInstanceInitFunc) g_param_spec_init,
115
116     &param_value_table,
117   };
118   GType type;
119
120   type = g_type_register_fundamental (G_TYPE_PARAM, g_intern_static_string ("GParam"), &param_spec_info, &finfo, G_TYPE_FLAG_ABSTRACT);
121   g_assert (type == G_TYPE_PARAM);
122   g_value_register_transform_func (G_TYPE_PARAM, G_TYPE_PARAM, value_param_transform_value);
123 }
124
125 static void
126 g_param_spec_class_base_init (GParamSpecClass *class)
127 {
128 }
129
130 static void
131 g_param_spec_class_base_finalize (GParamSpecClass *class)
132 {
133 }
134
135 static void
136 g_param_spec_class_init (GParamSpecClass *class,
137                          gpointer         class_data)
138 {
139   class->value_type = G_TYPE_NONE;
140   class->finalize = g_param_spec_finalize;
141   class->value_set_default = NULL;
142   class->value_validate = NULL;
143   class->values_cmp = NULL;
144 }
145
146 static void
147 g_param_spec_init (GParamSpec      *pspec,
148                    GParamSpecClass *class)
149 {
150   pspec->name = NULL;
151   pspec->_nick = NULL;
152   pspec->_blurb = NULL;
153   pspec->flags = 0;
154   pspec->value_type = class->value_type;
155   pspec->owner_type = 0;
156   pspec->qdata = NULL;
157   g_datalist_init (&pspec->qdata);
158   g_datalist_set_flags (&pspec->qdata, PARAM_FLOATING_FLAG);
159   pspec->ref_count = 1;
160   pspec->param_id = 0;
161 }
162
163 static void
164 g_param_spec_finalize (GParamSpec *pspec)
165 {
166   g_datalist_clear (&pspec->qdata);
167
168   if (!(pspec->flags & G_PARAM_STATIC_NAME))
169     g_free (pspec->name);
170   
171   if (!(pspec->flags & G_PARAM_STATIC_NICK))
172     g_free (pspec->_nick);
173
174   if (!(pspec->flags & G_PARAM_STATIC_BLURB))
175     g_free (pspec->_blurb);
176
177   g_type_free_instance ((GTypeInstance*) pspec);
178 }
179
180 /**
181  * g_param_spec_ref:
182  * @pspec: a valid #GParamSpec
183  * 
184  * Increments the reference count of @pspec.
185  * 
186  * Returns: the #GParamSpec that was passed into this function
187  */
188 GParamSpec*
189 g_param_spec_ref (GParamSpec *pspec)
190 {
191   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
192   g_return_val_if_fail (pspec->ref_count > 0, NULL);
193
194   g_atomic_int_inc (&pspec->ref_count);
195
196   return pspec;
197 }
198
199 /**
200  * g_param_spec_unref:
201  * @pspec: a valid #GParamSpec
202  * 
203  * Decrements the reference count of a @pspec.
204  */
205 void
206 g_param_spec_unref (GParamSpec *pspec)
207 {
208   gboolean is_zero;
209
210   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
211   g_return_if_fail (pspec->ref_count > 0);
212
213   is_zero = g_atomic_int_dec_and_test (&pspec->ref_count);
214
215   if (G_UNLIKELY (is_zero))
216     {
217       G_PARAM_SPEC_GET_CLASS (pspec)->finalize (pspec);
218     }
219 }
220
221 /**
222  * g_param_spec_sink:
223  * @pspec: a valid #GParamSpec
224  * 
225  * The initial reference count of a newly created #GParamSpec is 1, even 
226  * though no one has explicitly called g_param_spec_ref() on it yet. So the 
227  * initial reference count is flagged as "floating", until someone calls 
228  * <literal>g_param_spec_ref (pspec); g_param_spec_sink (pspec);</literal>
229  * in sequence on it, taking over the initial reference count (thus
230  * ending up with a @pspec that has a reference count of 1 still, but is
231  * not flagged "floating" anymore).
232  */
233 void
234 g_param_spec_sink (GParamSpec *pspec)
235 {
236   gpointer oldvalue;
237   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
238   g_return_if_fail (pspec->ref_count > 0);
239
240   do
241     oldvalue = g_atomic_pointer_get (&pspec->qdata);
242   while (!g_atomic_pointer_compare_and_exchange ((void**) &pspec->qdata, oldvalue,
243                                                  (gpointer) ((gsize) oldvalue & ~(gsize) PARAM_FLOATING_FLAG)));
244   if ((gsize) oldvalue & PARAM_FLOATING_FLAG)
245     g_param_spec_unref (pspec);
246 }
247
248 /**
249  * g_param_spec_ref_sink:
250  * @pspec: a valid #GParamSpec
251  * 
252  * Convenience function to ref and sink a #GParamSpec.
253  * 
254  * Since: 2.10
255  * Returns: the #GParamSpec that was passed into this function
256  */
257 GParamSpec*
258 g_param_spec_ref_sink (GParamSpec *pspec)
259 {
260   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
261   g_return_val_if_fail (pspec->ref_count > 0, NULL);
262
263   g_param_spec_ref (pspec);
264   g_param_spec_sink (pspec);
265   return pspec;
266 }
267
268 /**
269  * g_param_spec_get_name:
270  * @pspec: a valid #GParamSpec
271  * 
272  * Get the name of a #GParamSpec.
273  * 
274  * Returns: the name of @pspec.
275  */
276 G_CONST_RETURN gchar*
277 g_param_spec_get_name (GParamSpec *pspec)
278 {
279   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
280
281   return pspec->name;
282 }
283
284 /**
285  * g_param_spec_get_nick:
286  * @pspec: a valid #GParamSpec
287  * 
288  * Get the nickname of a #GParamSpec.
289  * 
290  * Returns: the nickname of @pspec.
291  */
292 G_CONST_RETURN gchar*
293 g_param_spec_get_nick (GParamSpec *pspec)
294 {
295   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
296
297   if (pspec->_nick)
298     return pspec->_nick;
299   else
300     {
301       GParamSpec *redirect_target;
302
303       redirect_target = g_param_spec_get_redirect_target (pspec);
304       if (redirect_target && redirect_target->_nick)
305         return redirect_target->_nick;
306     }
307
308   return pspec->name;
309 }
310
311 /**
312  * g_param_spec_get_blurb:
313  * @pspec: a valid #GParamSpec
314  * 
315  * Get the short description of a #GParamSpec.
316  * 
317  * Returns: the short description of @pspec.
318  */
319 G_CONST_RETURN gchar*
320 g_param_spec_get_blurb (GParamSpec *pspec)
321 {
322   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
323
324   if (pspec->_blurb)
325     return pspec->_blurb;
326   else
327     {
328       GParamSpec *redirect_target;
329
330       redirect_target = g_param_spec_get_redirect_target (pspec);
331       if (redirect_target && redirect_target->_blurb)
332         return redirect_target->_blurb;
333     }
334
335   return NULL;
336 }
337
338 static void
339 canonicalize_key (gchar *key)
340 {
341   gchar *p;
342   
343   for (p = key; *p != 0; p++)
344     {
345       gchar c = *p;
346       
347       if (c != '-' &&
348           (c < '0' || c > '9') &&
349           (c < 'A' || c > 'Z') &&
350           (c < 'a' || c > 'z'))
351         *p = '-';
352     }
353 }
354
355 static gboolean
356 is_canonical (const gchar *key)
357 {
358   const gchar *p;
359
360   for (p = key; *p != 0; p++)
361     {
362       gchar c = *p;
363       
364       if (c != '-' &&
365           (c < '0' || c > '9') &&
366           (c < 'A' || c > 'Z') &&
367           (c < 'a' || c > 'z'))
368         return FALSE;
369     }
370
371   return TRUE;
372 }
373
374 /**
375  * g_param_spec_internal:
376  * @param_type: the #GType for the property; must be derived from #G_TYPE_PARAM
377  * @name: the canonical name of the property
378  * @nick: the nickname of the property
379  * @blurb: a short description of the property
380  * @flags: a combination of #GParamFlags
381  * 
382  * Creates a new #GParamSpec instance.
383  * 
384  * A property name consists of segments consisting of ASCII letters and
385  * digits, separated by either the '-' or '_' character. The first
386  * character of a property name must be a letter. Names which violate these
387  * rules lead to undefined behaviour. 
388  * 
389  * When creating and looking up a #GParamSpec, either separator can be used, 
390  * but they cannot be mixed. Using '-' is considerably more efficient and in 
391  * fact required when using property names as detail strings for signals.
392  * 
393  * Beyond the name, #GParamSpec<!-- -->s have two more descriptive strings 
394  * associated with them, the @nick, which should be suitable for use as 
395  * a label for the property in a property editor, and the @blurb, which should
396  * be a somewhat longer description, suitable for e.g. a tooltip. The @nick
397  * and @blurb should ideally be localized.
398  * 
399  * Returns: a newly allocated #GParamSpec instance
400  */
401 gpointer
402 g_param_spec_internal (GType        param_type,
403                        const gchar *name,
404                        const gchar *nick,
405                        const gchar *blurb,
406                        GParamFlags  flags)
407 {
408   GParamSpec *pspec;
409   
410   g_return_val_if_fail (G_TYPE_IS_PARAM (param_type) && param_type != G_TYPE_PARAM, NULL);
411   g_return_val_if_fail (name != NULL, NULL);
412   g_return_val_if_fail ((name[0] >= 'A' && name[0] <= 'Z') || (name[0] >= 'a' && name[0] <= 'z'), NULL);
413   g_return_val_if_fail (!(flags & G_PARAM_STATIC_NAME) || is_canonical (name), NULL);
414   
415   pspec = (gpointer) g_type_create_instance (param_type);
416
417   if (flags & G_PARAM_STATIC_NAME)
418     {
419       pspec->name = g_intern_static_string (name);
420       if (!is_canonical (pspec->name))
421         g_warning ("G_PARAM_STATIC_NAME used with non-canonical pspec name: %s", pspec->name);
422     }
423   else
424     {
425       pspec->name = g_strdup (name);
426       canonicalize_key (pspec->name);
427       g_intern_string (pspec->name);
428     }
429
430   if (flags & G_PARAM_STATIC_NICK)
431     pspec->_nick = (gchar*) nick;
432   else
433     pspec->_nick = g_strdup (nick);
434
435   if (flags & G_PARAM_STATIC_BLURB)
436     pspec->_blurb = (gchar*) blurb;
437   else
438     pspec->_blurb = g_strdup (blurb);
439
440   pspec->flags = (flags & G_PARAM_USER_MASK) | (flags & G_PARAM_MASK);
441   
442   return pspec;
443 }
444
445 /**
446  * g_param_spec_get_qdata:
447  * @pspec: a valid #GParamSpec
448  * @quark: a #GQuark, naming the user data pointer
449  * 
450  * Gets back user data pointers stored via g_param_spec_set_qdata().
451  * 
452  * Returns: the user data pointer set, or %NULL
453  */
454 gpointer
455 g_param_spec_get_qdata (GParamSpec *pspec,
456                         GQuark      quark)
457 {
458   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
459   
460   return quark ? g_datalist_id_get_data (&pspec->qdata, quark) : NULL;
461 }
462
463 /**
464  * g_param_spec_set_qdata:
465  * @pspec: the #GParamSpec to set store a user data pointer
466  * @quark: a #GQuark, naming the user data pointer
467  * @data: an opaque user data pointer
468  * 
469  * Sets an opaque, named pointer on a #GParamSpec. The name is specified 
470  * through a #GQuark (retrieved e.g. via g_quark_from_static_string()), and 
471  * the pointer can be gotten back from the @pspec with g_param_spec_get_qdata().
472  * Setting a previously set user data pointer, overrides (frees)
473  * the old pointer set, using %NULL as pointer essentially
474  * removes the data stored.
475  */
476 void
477 g_param_spec_set_qdata (GParamSpec *pspec,
478                         GQuark      quark,
479                         gpointer    data)
480 {
481   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
482   g_return_if_fail (quark > 0);
483
484   g_datalist_id_set_data (&pspec->qdata, quark, data);
485 }
486
487 /**
488  * g_param_spec_set_qdata_full:
489  * @pspec: the #GParamSpec to set store a user data pointer
490  * @quark: a #GQuark, naming the user data pointer
491  * @data: an opaque user data pointer
492  * @destroy: function to invoke with @data as argument, when @data needs to
493  *  be freed
494  * 
495  * This function works like g_param_spec_set_qdata(), but in addition, 
496  * a <literal>void (*destroy) (gpointer)</literal> function may be 
497  * specified which is called with @data as argument when the @pspec is 
498  * finalized, or the data is being overwritten by a call to 
499  * g_param_spec_set_qdata() with the same @quark.
500  */
501 void
502 g_param_spec_set_qdata_full (GParamSpec    *pspec,
503                              GQuark         quark,
504                              gpointer       data,
505                              GDestroyNotify destroy)
506 {
507   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
508   g_return_if_fail (quark > 0);
509
510   g_datalist_id_set_data_full (&pspec->qdata, quark, data, data ? destroy : (GDestroyNotify) NULL);
511 }
512
513 /**
514  * g_param_spec_steal_qdata:
515  * @pspec: the #GParamSpec to get a stored user data pointer from
516  * @quark: a #GQuark, naming the user data pointer
517  * 
518  * Gets back user data pointers stored via g_param_spec_set_qdata() and 
519  * removes the @data from @pspec without invoking it's destroy() function 
520  * (if any was set).
521  * Usually, calling this function is only required to update
522  * user data pointers with a destroy notifier.
523  * 
524  * Returns: the user data pointer set, or %NULL
525  */
526 gpointer
527 g_param_spec_steal_qdata (GParamSpec *pspec,
528                           GQuark      quark)
529 {
530   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
531   g_return_val_if_fail (quark > 0, NULL);
532   
533   return g_datalist_id_remove_no_notify (&pspec->qdata, quark);
534 }
535
536 /**
537  * g_param_spec_get_redirect_target:
538  * @pspec: a #GParamSpec
539  * 
540  * If the paramspec redirects operations to another paramspec,
541  * returns that paramspec. Redirect is used typically for
542  * providing a new implementation of a property in a derived
543  * type while preserving all the properties from the parent
544  * type. Redirection is established by creating a property
545  * of type #GParamSpecOverride. See g_object_class_override_property()
546  * for an example of the use of this capability.
547  * 
548  * Since: 2.4
549  * Returns: paramspec to which requests on this paramspec should
550  *  be redirected, or %NULL if none.
551  */
552 GParamSpec*
553 g_param_spec_get_redirect_target (GParamSpec *pspec)
554 {
555   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
556
557   if (G_IS_PARAM_SPEC_OVERRIDE (pspec))
558     {
559       GParamSpecOverride *ospec = G_PARAM_SPEC_OVERRIDE (pspec);
560
561       return ospec->overridden;
562     }
563   else
564     return NULL;
565 }
566
567 /**
568  * g_param_value_set_default:
569  * @pspec: a valid #GParamSpec
570  * @value: a #GValue of correct type for @pspec
571  * 
572  * Sets @value to its default value as specified in @pspec.
573  */
574 void
575 g_param_value_set_default (GParamSpec *pspec,
576                            GValue     *value)
577 {
578   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
579   g_return_if_fail (G_IS_VALUE (value));
580   g_return_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value));
581
582   g_value_reset (value);
583   G_PARAM_SPEC_GET_CLASS (pspec)->value_set_default (pspec, value);
584 }
585
586 /**
587  * g_param_value_defaults:
588  * @pspec: a valid #GParamSpec
589  * @value: a #GValue of correct type for @pspec
590  * 
591  * Checks whether @value contains the default value as specified in @pspec.
592  * 
593  * Returns: whether @value contains the canonical default for this @pspec
594  */
595 gboolean
596 g_param_value_defaults (GParamSpec *pspec,
597                         GValue     *value)
598 {
599   GValue dflt_value = { 0, };
600   gboolean defaults;
601
602   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
603   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
604   g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value), FALSE);
605
606   g_value_init (&dflt_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
607   G_PARAM_SPEC_GET_CLASS (pspec)->value_set_default (pspec, &dflt_value);
608   defaults = G_PARAM_SPEC_GET_CLASS (pspec)->values_cmp (pspec, value, &dflt_value) == 0;
609   g_value_unset (&dflt_value);
610
611   return defaults;
612 }
613
614 /**
615  * g_param_value_validate:
616  * @pspec: a valid #GParamSpec
617  * @value: a #GValue of correct type for @pspec
618  * 
619  * Ensures that the contents of @value comply with the specifications
620  * set out by @pspec. For example, a #GParamSpecInt might require
621  * that integers stored in @value may not be smaller than -42 and not be
622  * greater than +42. If @value contains an integer outside of this range,
623  * it is modified accordingly, so the resulting value will fit into the
624  * range -42 .. +42.
625  * 
626  * Returns: whether modifying @value was necessary to ensure validity
627  */
628 gboolean
629 g_param_value_validate (GParamSpec *pspec,
630                         GValue     *value)
631 {
632   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
633   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
634   g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value), FALSE);
635
636   if (G_PARAM_SPEC_GET_CLASS (pspec)->value_validate)
637     {
638       GValue oval = *value;
639
640       if (G_PARAM_SPEC_GET_CLASS (pspec)->value_validate (pspec, value) ||
641           memcmp (&oval.data, &value->data, sizeof (oval.data)))
642         return TRUE;
643     }
644
645   return FALSE;
646 }
647
648 /**
649  * g_param_value_convert:
650  * @pspec: a valid #GParamSpec
651  * @src_value: souce #GValue
652  * @dest_value: destination #GValue of correct type for @pspec
653  * @strict_validation: %TRUE requires @dest_value to conform to @pspec without modifications
654  * 
655  * Transforms @src_value into @dest_value if possible, and then validates 
656  * @dest_value, in order for it to conform to @pspec.
657  * If @strict_validation is %TRUE this function will only succeed if
658  * the transformed @dest_value complied to @pspec without modifications.
659  * 
660  * See also g_value_type_transformable(), g_value_transform() and
661  * g_param_value_validate().
662  * 
663  * Returns: %TRUE if transformation and validation were successful,
664  *  %FALSE otherwise and @dest_value is left untouched.
665  */
666 gboolean
667 g_param_value_convert (GParamSpec   *pspec,
668                        const GValue *src_value,
669                        GValue       *dest_value,
670                        gboolean      strict_validation)
671 {
672   GValue tmp_value = { 0, };
673
674   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
675   g_return_val_if_fail (G_IS_VALUE (src_value), FALSE);
676   g_return_val_if_fail (G_IS_VALUE (dest_value), FALSE);
677   g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, dest_value), FALSE);
678
679   /* better leave dest_value untouched when returning FALSE */
680
681   g_value_init (&tmp_value, G_VALUE_TYPE (dest_value));
682   if (g_value_transform (src_value, &tmp_value) &&
683       (!g_param_value_validate (pspec, &tmp_value) || !strict_validation))
684     {
685       g_value_unset (dest_value);
686       
687       /* values are relocatable */
688       memcpy (dest_value, &tmp_value, sizeof (tmp_value));
689       
690       return TRUE;
691     }
692   else
693     {
694       g_value_unset (&tmp_value);
695       
696       return FALSE;
697     }
698 }
699
700 /**
701  * g_param_values_cmp:
702  * @pspec: a valid #GParamSpec
703  * @value1: a #GValue of correct type for @pspec
704  * @value2: a #GValue of correct type for @pspec
705  * 
706  * Compares @value1 with @value2 according to @pspec, and return -1, 0 or +1,
707  * if @value1 is found to be less than, equal to or greater than @value2, 
708  * respectively.
709  * 
710  * Returns: -1, 0 or +1, for a less than, equal to or greater than result
711  */
712 gint
713 g_param_values_cmp (GParamSpec   *pspec,
714                     const GValue *value1,
715                     const GValue *value2)
716 {
717   gint cmp;
718
719   /* param_values_cmp() effectively does: value1 - value2
720    * so the return values are:
721    * -1)  value1 < value2
722    *  0)  value1 == value2
723    *  1)  value1 > value2
724    */
725   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), 0);
726   g_return_val_if_fail (G_IS_VALUE (value1), 0);
727   g_return_val_if_fail (G_IS_VALUE (value2), 0);
728   g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value1), 0);
729   g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value2), 0);
730
731   cmp = G_PARAM_SPEC_GET_CLASS (pspec)->values_cmp (pspec, value1, value2);
732
733   return CLAMP (cmp, -1, 1);
734 }
735
736 static void
737 value_param_init (GValue *value)
738 {
739   value->data[0].v_pointer = NULL;
740 }
741
742 static void
743 value_param_free_value (GValue *value)
744 {
745   if (value->data[0].v_pointer)
746     g_param_spec_unref (value->data[0].v_pointer);
747 }
748
749 static void
750 value_param_copy_value (const GValue *src_value,
751                         GValue       *dest_value)
752 {
753   if (src_value->data[0].v_pointer)
754     dest_value->data[0].v_pointer = g_param_spec_ref (src_value->data[0].v_pointer);
755   else
756     dest_value->data[0].v_pointer = NULL;
757 }
758
759 static void
760 value_param_transform_value (const GValue *src_value,
761                              GValue       *dest_value)
762 {
763   if (src_value->data[0].v_pointer &&
764       g_type_is_a (G_PARAM_SPEC_TYPE (dest_value->data[0].v_pointer), G_VALUE_TYPE (dest_value)))
765     dest_value->data[0].v_pointer = g_param_spec_ref (src_value->data[0].v_pointer);
766   else
767     dest_value->data[0].v_pointer = NULL;
768 }
769
770 static gpointer
771 value_param_peek_pointer (const GValue *value)
772 {
773   return value->data[0].v_pointer;
774 }
775
776 static gchar*
777 value_param_collect_value (GValue      *value,
778                            guint        n_collect_values,
779                            GTypeCValue *collect_values,
780                            guint        collect_flags)
781 {
782   if (collect_values[0].v_pointer)
783     {
784       GParamSpec *param = collect_values[0].v_pointer;
785
786       if (param->g_type_instance.g_class == NULL)
787         return g_strconcat ("invalid unclassed param spec pointer for value type `",
788                             G_VALUE_TYPE_NAME (value),
789                             "'",
790                             NULL);
791       else if (!g_value_type_compatible (G_PARAM_SPEC_TYPE (param), G_VALUE_TYPE (value)))
792         return g_strconcat ("invalid param spec type `",
793                             G_PARAM_SPEC_TYPE_NAME (param),
794                             "' for value type `",
795                             G_VALUE_TYPE_NAME (value),
796                             "'",
797                             NULL);
798       value->data[0].v_pointer = g_param_spec_ref (param);
799     }
800   else
801     value->data[0].v_pointer = NULL;
802
803   return NULL;
804 }
805
806 static gchar*
807 value_param_lcopy_value (const GValue *value,
808                          guint         n_collect_values,
809                          GTypeCValue  *collect_values,
810                          guint         collect_flags)
811 {
812   GParamSpec **param_p = collect_values[0].v_pointer;
813
814   if (!param_p)
815     return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
816
817   if (!value->data[0].v_pointer)
818     *param_p = NULL;
819   else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
820     *param_p = value->data[0].v_pointer;
821   else
822     *param_p = g_param_spec_ref (value->data[0].v_pointer);
823
824   return NULL;
825 }
826
827
828 /* --- param spec pool --- */
829 /**
830  * GParamSpecPool:
831  * 
832  * A #GParamSpecPool maintains a collection of #GParamSpec<!-- -->s which can be
833  * quickly accessed by owner and name. The implementation of the #GObject property
834  * system uses such a pool to store the #GParamSpecs of the properties all object
835  * types. 
836  */
837 struct _GParamSpecPool
838 {
839   GStaticMutex smutex;
840   gboolean     type_prefixing;
841   GHashTable  *hash_table;
842 };
843
844 static guint
845 param_spec_pool_hash (gconstpointer key_spec)
846 {
847   const GParamSpec *key = key_spec;
848   const gchar *p;
849   guint h = key->owner_type;
850
851   for (p = key->name; *p; p++)
852     h = (h << 5) - h + *p;
853
854   return h;
855 }
856
857 static gboolean
858 param_spec_pool_equals (gconstpointer key_spec_1,
859                         gconstpointer key_spec_2)
860 {
861   const GParamSpec *key1 = key_spec_1;
862   const GParamSpec *key2 = key_spec_2;
863
864   return (key1->owner_type == key2->owner_type &&
865           strcmp (key1->name, key2->name) == 0);
866 }
867
868 /**
869  * g_param_spec_pool_new:
870  * @type_prefixing: Whether the pool will support type-prefixed property names.
871  * 
872  * Creates a new #GParamSpecPool.
873  * 
874  * If @type_prefixing is %TRUE, lookups in the newly created pool will
875  * allow to specify the owner as a colon-separated prefix of the property name, 
876  * like "GtkContainer:border-width". This feature is deprecated, so you should 
877  * always set @type_prefixing to %FALSE.
878  * 
879  * Returns: a newly allocated #GParamSpecPool.
880  */
881 GParamSpecPool*
882 g_param_spec_pool_new (gboolean type_prefixing)
883 {
884   static GStaticMutex init_smutex = G_STATIC_MUTEX_INIT;
885   GParamSpecPool *pool = g_new (GParamSpecPool, 1);
886
887   memcpy (&pool->smutex, &init_smutex, sizeof (init_smutex));
888   pool->type_prefixing = type_prefixing != FALSE;
889   pool->hash_table = g_hash_table_new (param_spec_pool_hash, param_spec_pool_equals);
890
891   return pool;
892 }
893
894 /**
895  * g_param_spec_pool_insert:
896  * @pool: a #GParamSpecPool.
897  * @pspec: the #GParamSpec to insert
898  * @owner_type: a #GType identifying the owner of @pspec
899  * 
900  * Inserts a #GParamSpec in the pool.
901  */void
902 g_param_spec_pool_insert (GParamSpecPool *pool,
903                           GParamSpec     *pspec,
904                           GType           owner_type)
905 {
906   gchar *p;
907   
908   if (pool && pspec && owner_type > 0 && pspec->owner_type == 0)
909     {
910       G_SLOCK (&pool->smutex);
911       for (p = pspec->name; *p; p++)
912         {
913           if (!strchr (G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-_", *p))
914             {
915               g_warning (G_STRLOC ": pspec name \"%s\" contains invalid characters", pspec->name);
916               G_SUNLOCK (&pool->smutex);
917               return;
918             }
919         }
920       
921       pspec->owner_type = owner_type;
922       g_param_spec_ref (pspec);
923       g_hash_table_insert (pool->hash_table, pspec, pspec);
924       G_SUNLOCK (&pool->smutex);
925     }
926   else
927     {
928       g_return_if_fail (pool != NULL);
929       g_return_if_fail (pspec);
930       g_return_if_fail (owner_type > 0);
931       g_return_if_fail (pspec->owner_type == 0);
932     }
933 }
934
935 /**
936  * g_param_spec_pool_remove:
937  * @pool: a #GParamSpecPool
938  * @pspec: the #GParamSpec to remove
939  * 
940  * Removes a #GParamSpec from the pool.
941  */
942 void
943 g_param_spec_pool_remove (GParamSpecPool *pool,
944                           GParamSpec     *pspec)
945 {
946   if (pool && pspec)
947     {
948       G_SLOCK (&pool->smutex);
949       if (g_hash_table_remove (pool->hash_table, pspec))
950         g_param_spec_unref (pspec);
951       else
952         g_warning (G_STRLOC ": attempt to remove unknown pspec `%s' from pool", pspec->name);
953       G_SUNLOCK (&pool->smutex);
954     }
955   else
956     {
957       g_return_if_fail (pool != NULL);
958       g_return_if_fail (pspec);
959     }
960 }
961
962 static inline GParamSpec*
963 param_spec_ht_lookup (GHashTable  *hash_table,
964                       const gchar *param_name,
965                       GType        owner_type,
966                       gboolean     walk_ancestors)
967 {
968   GParamSpec key, *pspec;
969
970   key.owner_type = owner_type;
971   key.name = (gchar*) param_name;
972   if (walk_ancestors)
973     do
974       {
975         pspec = g_hash_table_lookup (hash_table, &key);
976         if (pspec)
977           return pspec;
978         key.owner_type = g_type_parent (key.owner_type);
979       }
980     while (key.owner_type);
981   else
982     pspec = g_hash_table_lookup (hash_table, &key);
983
984   if (!pspec && !is_canonical (param_name))
985     {
986       /* try canonicalized form */
987       key.name = g_strdup (param_name);
988       key.owner_type = owner_type;
989       
990       canonicalize_key (key.name);
991       if (walk_ancestors)
992         do
993           {
994             pspec = g_hash_table_lookup (hash_table, &key);
995             if (pspec)
996               {
997                 g_free (key.name);
998                 return pspec;
999               }
1000             key.owner_type = g_type_parent (key.owner_type);
1001           }
1002         while (key.owner_type);
1003       else
1004         pspec = g_hash_table_lookup (hash_table, &key);
1005       g_free (key.name);
1006     }
1007
1008   return pspec;
1009 }
1010
1011 /**
1012  * g_param_spec_pool_lookup:
1013  * @pool: a #GParamSpecPool
1014  * @param_name: the name to look for
1015  * @owner_type: the owner to look for
1016  * @walk_ancestors: If %TRUE, also try to find a #GParamSpec with @param_name 
1017  *  owned by an ancestor of @owner_type.
1018  * 
1019  * Looks up a #GParamSpec in the pool.
1020  * 
1021  * Returns: The found #GParamSpec, or %NULL if no matching #GParamSpec was found.
1022  */
1023 GParamSpec*
1024 g_param_spec_pool_lookup (GParamSpecPool *pool,
1025                           const gchar    *param_name,
1026                           GType           owner_type,
1027                           gboolean        walk_ancestors)
1028 {
1029   GParamSpec *pspec;
1030   gchar *delim;
1031
1032   if (!pool || !param_name)
1033     {
1034       g_return_val_if_fail (pool != NULL, NULL);
1035       g_return_val_if_fail (param_name != NULL, NULL);
1036     }
1037
1038   G_SLOCK (&pool->smutex);
1039
1040   delim = pool->type_prefixing ? strchr (param_name, ':') : NULL;
1041
1042   /* try quick and away, i.e. without prefix */
1043   if (!delim)
1044     {
1045       pspec = param_spec_ht_lookup (pool->hash_table, param_name, owner_type, walk_ancestors);
1046       G_SUNLOCK (&pool->smutex);
1047
1048       return pspec;
1049     }
1050
1051   /* strip type prefix */
1052   if (pool->type_prefixing && delim[1] == ':')
1053     {
1054       guint l = delim - param_name;
1055       gchar stack_buffer[32], *buffer = l < 32 ? stack_buffer : g_new (gchar, l + 1);
1056       GType type;
1057       
1058       strncpy (buffer, param_name, delim - param_name);
1059       buffer[l] = 0;
1060       type = g_type_from_name (buffer);
1061       if (l >= 32)
1062         g_free (buffer);
1063       if (type)         /* type==0 isn't a valid type pefix */
1064         {
1065           /* sanity check, these cases don't make a whole lot of sense */
1066           if ((!walk_ancestors && type != owner_type) || !g_type_is_a (owner_type, type))
1067             {
1068               G_SUNLOCK (&pool->smutex);
1069
1070               return NULL;
1071             }
1072           owner_type = type;
1073           param_name += l + 2;
1074           pspec = param_spec_ht_lookup (pool->hash_table, param_name, owner_type, walk_ancestors);
1075           G_SUNLOCK (&pool->smutex);
1076
1077           return pspec;
1078         }
1079     }
1080   /* malformed param_name */
1081
1082   G_SUNLOCK (&pool->smutex);
1083
1084   return NULL;
1085 }
1086
1087 static void
1088 pool_list (gpointer key,
1089            gpointer value,
1090            gpointer user_data)
1091 {
1092   GParamSpec *pspec = value;
1093   gpointer *data = user_data;
1094   GType owner_type = (GType) data[1];
1095
1096   if (owner_type == pspec->owner_type)
1097     data[0] = g_list_prepend (data[0], pspec);
1098 }
1099
1100 /**
1101  * g_param_spec_pool_list_owned:
1102  * @pool: a #GParamSpecPool
1103  * @owner_type: the owner to look for
1104  * 
1105  * Gets an #GList of all #GParamSpec<!-- -->s owned by @owner_type in the pool. 
1106  * 
1107  * Returns: a #GList of all #GParamSpec<!-- -->s owned by @owner_type in 
1108  *  the pool#GParamSpec<!-- -->s.
1109  */
1110 GList*
1111 g_param_spec_pool_list_owned (GParamSpecPool *pool,
1112                               GType           owner_type)
1113 {
1114   gpointer data[2];
1115
1116   g_return_val_if_fail (pool != NULL, NULL);
1117   g_return_val_if_fail (owner_type > 0, NULL);
1118   
1119   G_SLOCK (&pool->smutex);
1120   data[0] = NULL;
1121   data[1] = (gpointer) owner_type;
1122   g_hash_table_foreach (pool->hash_table, pool_list, &data);
1123   G_SUNLOCK (&pool->smutex);
1124
1125   return data[0];
1126 }
1127
1128 static gint
1129 pspec_compare_id (gconstpointer a,
1130                   gconstpointer b)
1131 {
1132   const GParamSpec *pspec1 = a, *pspec2 = b;
1133
1134   return pspec1->param_id < pspec2->param_id ? -1 : pspec1->param_id > pspec2->param_id;
1135 }
1136
1137 static inline GSList*
1138 pspec_list_remove_overridden_and_redirected (GSList     *plist,
1139                                              GHashTable *ht,
1140                                              GType       owner_type,
1141                                              guint      *n_p)
1142 {
1143   GSList *rlist = NULL;
1144
1145   while (plist)
1146     {
1147       GSList *tmp = plist->next;
1148       GParamSpec *pspec = plist->data;
1149       GParamSpec *found;
1150       gboolean remove = FALSE;
1151
1152       /* Remove paramspecs that are redirected, and also paramspecs
1153        * that have are overridden by non-redirected properties.
1154        * The idea is to get the single paramspec for each name that
1155        * best corresponds to what the application sees.
1156        */
1157       if (g_param_spec_get_redirect_target (pspec))
1158         remove = TRUE;
1159       else
1160         {
1161           found = param_spec_ht_lookup (ht, pspec->name, owner_type, TRUE);
1162           if (found != pspec)
1163             {
1164               GParamSpec *redirect = g_param_spec_get_redirect_target (found);
1165               if (redirect != pspec)
1166                 remove = TRUE;
1167             }
1168         }
1169
1170       if (remove)
1171         {
1172           g_slist_free_1 (plist);
1173         }
1174       else
1175         {
1176           plist->next = rlist;
1177           rlist = plist;
1178           *n_p += 1;
1179         }
1180       plist = tmp;
1181     }
1182   return rlist;
1183 }
1184
1185 static void
1186 pool_depth_list (gpointer key,
1187                  gpointer value,
1188                  gpointer user_data)
1189 {
1190   GParamSpec *pspec = value;
1191   gpointer *data = user_data;
1192   GSList **slists = data[0];
1193   GType owner_type = (GType) data[1];
1194
1195   if (g_type_is_a (owner_type, pspec->owner_type))
1196     {
1197       if (G_TYPE_IS_INTERFACE (pspec->owner_type))
1198         {
1199           slists[0] = g_slist_prepend (slists[0], pspec);
1200         }
1201       else
1202         {
1203           guint d = g_type_depth (pspec->owner_type);
1204
1205           slists[d - 1] = g_slist_prepend (slists[d - 1], pspec);
1206         }
1207     }
1208 }
1209
1210 /* We handle interfaces specially since we don't want to
1211  * count interface prerequisites like normal inheritance;
1212  * the property comes from the direct inheritance from
1213  * the prerequisite class, not from the interface that
1214  * prerequires it.
1215  * 
1216  * also 'depth' isn't a meaningful concept for interface
1217  * prerequites.
1218  */
1219 static void
1220 pool_depth_list_for_interface (gpointer key,
1221                                gpointer value,
1222                                gpointer user_data)
1223 {
1224   GParamSpec *pspec = value;
1225   gpointer *data = user_data;
1226   GSList **slists = data[0];
1227   GType owner_type = (GType) data[1];
1228
1229   if (pspec->owner_type == owner_type)
1230     slists[0] = g_slist_prepend (slists[0], pspec);
1231 }
1232
1233 /**
1234  * g_param_spec_pool_list:
1235  * @pool: a #GParamSpecPool
1236  * @owner_type: the owner to look for
1237  * @n_pspecs_p: return location for the length of the returned array
1238  * 
1239  * Gets an array of all #GParamSpec<!-- -->s owned by @owner_type in the pool. 
1240  * 
1241  * Returns: a newly allocated array containing pointers to all 
1242  *  #GParamSpec<!-- -->s owned by @owner_type in the pool
1243  */
1244 GParamSpec**
1245 g_param_spec_pool_list (GParamSpecPool *pool,
1246                         GType           owner_type,
1247                         guint          *n_pspecs_p)
1248 {
1249   GParamSpec **pspecs, **p;
1250   GSList **slists, *node;
1251   gpointer data[2];
1252   guint d, i;
1253
1254   g_return_val_if_fail (pool != NULL, NULL);
1255   g_return_val_if_fail (owner_type > 0, NULL);
1256   g_return_val_if_fail (n_pspecs_p != NULL, NULL);
1257   
1258   G_SLOCK (&pool->smutex);
1259   *n_pspecs_p = 0;
1260   d = g_type_depth (owner_type);
1261   slists = g_new0 (GSList*, d);
1262   data[0] = slists;
1263   data[1] = (gpointer) owner_type;
1264
1265   g_hash_table_foreach (pool->hash_table,
1266                         G_TYPE_IS_INTERFACE (owner_type) ?
1267                            pool_depth_list_for_interface :
1268                            pool_depth_list,
1269                         &data);
1270   
1271   for (i = 0; i < d; i++)
1272     slists[i] = pspec_list_remove_overridden_and_redirected (slists[i], pool->hash_table, owner_type, n_pspecs_p);
1273   pspecs = g_new (GParamSpec*, *n_pspecs_p + 1);
1274   p = pspecs;
1275   for (i = 0; i < d; i++)
1276     {
1277       slists[i] = g_slist_sort (slists[i], pspec_compare_id);
1278       for (node = slists[i]; node; node = node->next)
1279         *p++ = node->data;
1280       g_slist_free (slists[i]);
1281     }
1282   *p++ = NULL;
1283   g_free (slists);
1284   G_SUNLOCK (&pool->smutex);
1285
1286   return pspecs;
1287 }
1288
1289
1290 /* --- auxillary functions --- */
1291 typedef struct
1292 {
1293   /* class portion */
1294   GType           value_type;
1295   void          (*finalize)             (GParamSpec   *pspec);
1296   void          (*value_set_default)    (GParamSpec   *pspec,
1297                                          GValue       *value);
1298   gboolean      (*value_validate)       (GParamSpec   *pspec,
1299                                          GValue       *value);
1300   gint          (*values_cmp)           (GParamSpec   *pspec,
1301                                          const GValue *value1,
1302                                          const GValue *value2);
1303 } ParamSpecClassInfo;
1304
1305 static void
1306 param_spec_generic_class_init (gpointer g_class,
1307                                gpointer class_data)
1308 {
1309   GParamSpecClass *class = g_class;
1310   ParamSpecClassInfo *info = class_data;
1311
1312   class->value_type = info->value_type;
1313   if (info->finalize)
1314     class->finalize = info->finalize;                   /* optional */
1315   class->value_set_default = info->value_set_default;
1316   if (info->value_validate)
1317     class->value_validate = info->value_validate;       /* optional */
1318   class->values_cmp = info->values_cmp;
1319   g_free (class_data);
1320 }
1321
1322 static void
1323 default_value_set_default (GParamSpec *pspec,
1324                            GValue     *value)
1325 {
1326   /* value is already zero initialized */
1327 }
1328
1329 static gint
1330 default_values_cmp (GParamSpec   *pspec,
1331                     const GValue *value1,
1332                     const GValue *value2)
1333 {
1334   return memcmp (&value1->data, &value2->data, sizeof (value1->data));
1335 }
1336
1337 /**
1338  * g_param_type_register_static:
1339  * @name: 0-terminated string used as the name of the new #GParamSpec type.
1340  * @pspec_info: The #GParamSpecTypeInfo for this #GParamSpec type.
1341  * 
1342  * Registers @name as the name of a new static type derived from
1343  * #G_TYPE_PARAM. The type system uses the information contained in the
1344  * #GParamSpecTypeInfo structure pointed to by @info to manage the #GParamSpec 
1345  * type and its instances. 
1346  * 
1347  * Returns: The new type identifier.
1348  */
1349 GType
1350 g_param_type_register_static (const gchar              *name,
1351                               const GParamSpecTypeInfo *pspec_info)
1352 {
1353   GTypeInfo info = {
1354     sizeof (GParamSpecClass),      /* class_size */
1355     NULL,                          /* base_init */
1356     NULL,                          /* base_destroy */
1357     param_spec_generic_class_init, /* class_init */
1358     NULL,                          /* class_destroy */
1359     NULL,                          /* class_data */
1360     0,                             /* instance_size */
1361     16,                            /* n_preallocs */
1362     NULL,                          /* instance_init */
1363   };
1364   ParamSpecClassInfo *cinfo;
1365
1366   g_return_val_if_fail (name != NULL, 0);
1367   g_return_val_if_fail (pspec_info != NULL, 0);
1368   g_return_val_if_fail (g_type_from_name (name) == 0, 0);
1369   g_return_val_if_fail (pspec_info->instance_size >= sizeof (GParamSpec), 0);
1370   g_return_val_if_fail (g_type_name (pspec_info->value_type) != NULL, 0);
1371   /* default: g_return_val_if_fail (pspec_info->value_set_default != NULL, 0); */
1372   /* optional: g_return_val_if_fail (pspec_info->value_validate != NULL, 0); */
1373   /* default: g_return_val_if_fail (pspec_info->values_cmp != NULL, 0); */
1374
1375   info.instance_size = pspec_info->instance_size;
1376   info.n_preallocs = pspec_info->n_preallocs;
1377   info.instance_init = (GInstanceInitFunc) pspec_info->instance_init;
1378   cinfo = g_new (ParamSpecClassInfo, 1);
1379   cinfo->value_type = pspec_info->value_type;
1380   cinfo->finalize = pspec_info->finalize;
1381   cinfo->value_set_default = pspec_info->value_set_default ? pspec_info->value_set_default : default_value_set_default;
1382   cinfo->value_validate = pspec_info->value_validate;
1383   cinfo->values_cmp = pspec_info->values_cmp ? pspec_info->values_cmp : default_values_cmp;
1384   info.class_data = cinfo;
1385
1386   return g_type_register_static (G_TYPE_PARAM, name, &info, 0);
1387 }
1388
1389 /**
1390  * g_value_set_param:
1391  * @value: a valid #GValue of type %G_TYPE_PARAM
1392  * @param: the #GParamSpec to be set
1393  * 
1394  * Set the contents of a %G_TYPE_PARAM #GValue to @param.
1395  */
1396 void
1397 g_value_set_param (GValue     *value,
1398                    GParamSpec *param)
1399 {
1400   g_return_if_fail (G_VALUE_HOLDS_PARAM (value));
1401   if (param)
1402     g_return_if_fail (G_IS_PARAM_SPEC (param));
1403
1404   if (value->data[0].v_pointer)
1405     g_param_spec_unref (value->data[0].v_pointer);
1406   value->data[0].v_pointer = param;
1407   if (value->data[0].v_pointer)
1408     g_param_spec_ref (value->data[0].v_pointer);
1409 }
1410
1411 /**
1412  * g_value_set_param_take_ownership:
1413  * @value: a valid #GValue of type %G_TYPE_PARAM
1414  * @param: the #GParamSpec to be set
1415  * 
1416  * This is an internal function introduced mainly for C marshallers.
1417  * 
1418  * Deprecated: 2.4: Use g_value_take_param() instead.
1419  */
1420 void
1421 g_value_set_param_take_ownership (GValue     *value,
1422                                   GParamSpec *param)
1423 {
1424   g_value_take_param (value, param);
1425 }
1426
1427 /**
1428  * g_value_take_param:
1429  * @value: a valid #GValue of type %G_TYPE_PARAM
1430  * @param: the #GParamSpec to be set
1431  * 
1432  * Sets the contents of a %G_TYPE_PARAM #GValue to @param and
1433  * takes over the ownership of the callers reference to @param; 
1434  * the caller doesn't have to unref it any more.
1435  * 
1436  * Since: 2.4
1437  */
1438 void
1439 g_value_take_param (GValue     *value,
1440                     GParamSpec *param)
1441 {
1442   g_return_if_fail (G_VALUE_HOLDS_PARAM (value));
1443   if (param)
1444     g_return_if_fail (G_IS_PARAM_SPEC (param));
1445
1446   if (value->data[0].v_pointer)
1447     g_param_spec_unref (value->data[0].v_pointer);
1448   value->data[0].v_pointer = param; /* we take over the reference count */
1449 }
1450
1451 /**
1452  * g_value_get_param:
1453  * @value: a valid #GValue whose type is derived from %G_TYPE_PARAM
1454  * 
1455  * Get the contents of a %G_TYPE_PARAM #GValue.
1456  * 
1457  * Returns: #GParamSpec content of @value
1458  */
1459 GParamSpec*
1460 g_value_get_param (const GValue *value)
1461 {
1462   g_return_val_if_fail (G_VALUE_HOLDS_PARAM (value), NULL);
1463
1464   return value->data[0].v_pointer;
1465 }
1466
1467 /**
1468  * g_value_dup_param:
1469  * @value: a valid #GValue whose type is derived from %G_TYPE_PARAM
1470  * 
1471  * Get the contents of a %G_TYPE_PARAM #GValue, increasing its reference count.
1472  * 
1473  * Returns: #GParamSpec content of @value, should be unreferenced when no longer needed.
1474  */
1475 GParamSpec*
1476 g_value_dup_param (const GValue *value)
1477 {
1478   g_return_val_if_fail (G_VALUE_HOLDS_PARAM (value), NULL);
1479
1480   return value->data[0].v_pointer ? g_param_spec_ref (value->data[0].v_pointer) : NULL;
1481 }
1482
1483 #define __G_PARAM_C__
1484 #include "gobjectaliasdef.c"