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