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