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