/src/glib/gobject/gparam.c
Line  | Count  | Source (jump to first uncovered line)  | 
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  | 16  | #define PARAM_FLOATING_FLAG                     0x2  | 
59  | 8  | #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  | 2.54k  | { | 
98  | 2.54k  |   return &G_STRUCT_MEMBER (GParamSpecPrivate, pspec, g_param_private_offset);  | 
99  | 2.54k  | }  | 
100  |  |  | 
101  |  | void  | 
102  |  | _g_param_type_init (void)  | 
103  | 4  | { | 
104  | 4  |   static const GTypeFundamentalInfo finfo = { | 
105  | 4  |     (G_TYPE_FLAG_CLASSED |  | 
106  | 4  |      G_TYPE_FLAG_INSTANTIATABLE |  | 
107  | 4  |      G_TYPE_FLAG_DERIVABLE |  | 
108  | 4  |      G_TYPE_FLAG_DEEP_DERIVABLE),  | 
109  | 4  |   };  | 
110  | 4  |   static const GTypeValueTable param_value_table = { | 
111  | 4  |     value_param_init,           /* value_init */  | 
112  | 4  |     value_param_free_value,     /* value_free */  | 
113  | 4  |     value_param_copy_value,     /* value_copy */  | 
114  | 4  |     value_param_peek_pointer,   /* value_peek_pointer */  | 
115  | 4  |     "p",      /* collect_format */  | 
116  | 4  |     value_param_collect_value,  /* collect_value */  | 
117  | 4  |     "p",      /* lcopy_format */  | 
118  | 4  |     value_param_lcopy_value,    /* lcopy_value */  | 
119  | 4  |   };  | 
120  | 4  |   const GTypeInfo param_spec_info = { | 
121  | 4  |     sizeof (GParamSpecClass),  | 
122  |  |  | 
123  | 4  |     (GBaseInitFunc) g_param_spec_class_base_init,  | 
124  | 4  |     (GBaseFinalizeFunc) g_param_spec_class_base_finalize,  | 
125  | 4  |     (GClassInitFunc) g_param_spec_class_init,  | 
126  | 4  |     (GClassFinalizeFunc) NULL,  | 
127  | 4  |     NULL, /* class_data */  | 
128  |  |  | 
129  | 4  |     sizeof (GParamSpec),  | 
130  | 4  |     0,    /* n_preallocs */  | 
131  | 4  |     (GInstanceInitFunc) g_param_spec_init,  | 
132  |  |  | 
133  | 4  |     ¶m_value_table,  | 
134  | 4  |   };  | 
135  | 4  |   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  | 4  |   type = g_type_register_fundamental (G_TYPE_PARAM, g_intern_static_string ("GParam"), ¶m_spec_info, &finfo, G_TYPE_FLAG_ABSTRACT); | 
143  | 4  |   g_assert (type == G_TYPE_PARAM);  | 
144  | 4  |   g_param_private_offset = g_type_add_instance_private (type, sizeof (GParamSpecPrivate));  | 
145  | 4  |   g_value_register_transform_func (G_TYPE_PARAM, G_TYPE_PARAM, value_param_transform_value);  | 
146  | 4  | }  | 
147  |  |  | 
148  |  | static void  | 
149  |  | g_param_spec_class_base_init (GParamSpecClass *class)  | 
150  | 85  | { | 
151  | 85  | }  | 
152  |  |  | 
153  |  | static void  | 
154  |  | g_param_spec_class_base_finalize (GParamSpecClass *class)  | 
155  | 0  | { | 
156  | 0  | }  | 
157  |  |  | 
158  |  | static void  | 
159  |  | g_param_spec_class_init (GParamSpecClass *class,  | 
160  |  |        gpointer         class_data)  | 
161  | 4  | { | 
162  | 4  |   class->value_type = G_TYPE_NONE;  | 
163  | 4  |   class->finalize = g_param_spec_finalize;  | 
164  | 4  |   class->value_set_default = NULL;  | 
165  | 4  |   class->value_validate = NULL;  | 
166  | 4  |   class->values_cmp = NULL;  | 
167  |  |  | 
168  | 4  |   g_type_class_adjust_private_offset (class, &g_param_private_offset);  | 
169  | 4  | }  | 
170  |  |  | 
171  |  | static void  | 
172  |  | g_param_spec_init (GParamSpec      *pspec,  | 
173  |  |        GParamSpecClass *class)  | 
174  | 8  | { | 
175  | 8  |   pspec->name = NULL;  | 
176  | 8  |   pspec->_nick = NULL;  | 
177  | 8  |   pspec->_blurb = NULL;  | 
178  | 8  |   pspec->flags = 0;  | 
179  | 8  |   pspec->value_type = class->value_type;  | 
180  | 8  |   pspec->owner_type = 0;  | 
181  | 8  |   pspec->qdata = NULL;  | 
182  | 8  |   g_datalist_set_flags (&pspec->qdata, PARAM_FLOATING_FLAG);  | 
183  | 8  |   pspec->ref_count = 1;  | 
184  | 8  |   pspec->param_id = 0;  | 
185  | 8  | }  | 
186  |  |  | 
187  |  | static void  | 
188  |  | g_param_spec_finalize (GParamSpec *pspec)  | 
189  | 0  | { | 
190  | 0  |   GParamSpecPrivate *priv = g_param_spec_get_private (pspec);  | 
191  |  | 
  | 
192  | 0  |   if (priv->default_value.g_type)  | 
193  | 0  |     g_value_reset (&priv->default_value);  | 
194  |  | 
  | 
195  | 0  |   g_datalist_clear (&pspec->qdata);  | 
196  |  | 
  | 
197  | 0  |   if (!(pspec->flags & G_PARAM_STATIC_NICK))  | 
198  | 0  |     g_free (pspec->_nick);  | 
199  |  | 
  | 
200  | 0  |   if (!(pspec->flags & G_PARAM_STATIC_BLURB))  | 
201  | 0  |     g_free (pspec->_blurb);  | 
202  |  | 
  | 
203  | 0  |   g_type_free_instance ((GTypeInstance*) pspec);  | 
204  | 0  | }  | 
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  | 8  | { | 
217  | 8  |   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);  | 
218  |  |  | 
219  | 8  |   g_atomic_int_inc ((int *)&pspec->ref_count);  | 
220  |  |  | 
221  | 8  |   return pspec;  | 
222  | 8  | }  | 
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  | 0  | { | 
233  | 0  |   gboolean is_zero;  | 
234  |  | 
  | 
235  | 0  |   g_return_if_fail (G_IS_PARAM_SPEC (pspec));  | 
236  |  |  | 
237  | 0  |   is_zero = g_atomic_int_dec_and_test ((int *)&pspec->ref_count);  | 
238  |  | 
  | 
239  | 0  |   if (G_UNLIKELY (is_zero))  | 
240  | 0  |     { | 
241  | 0  |       G_PARAM_SPEC_GET_CLASS (pspec)->finalize (pspec);  | 
242  | 0  |     }  | 
243  | 0  | }  | 
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  | 0  | { | 
260  | 0  |   gsize oldvalue;  | 
261  | 0  |   g_return_if_fail (G_IS_PARAM_SPEC (pspec));  | 
262  |  |  | 
263  | 0  |   oldvalue = g_atomic_pointer_and (&pspec->qdata, ~(gsize)PARAM_FLOATING_FLAG);  | 
264  | 0  |   if (oldvalue & PARAM_FLOATING_FLAG)  | 
265  | 0  |     g_param_spec_unref (pspec);  | 
266  | 0  | }  | 
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  | 8  | { | 
280  | 8  |   gsize oldvalue;  | 
281  | 8  |   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);  | 
282  |  |  | 
283  | 8  |   oldvalue = g_atomic_pointer_and (&pspec->qdata, ~(gsize)PARAM_FLOATING_FLAG);  | 
284  | 8  |   if (!(oldvalue & PARAM_FLOATING_FLAG))  | 
285  | 0  |     g_param_spec_ref (pspec);  | 
286  |  |  | 
287  | 8  |   return pspec;  | 
288  | 8  | }  | 
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  | 0  | { | 
304  | 0  |   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);  | 
305  |  |  | 
306  | 0  |   return pspec->name;  | 
307  | 0  | }  | 
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  | 0  | { | 
320  | 0  |   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);  | 
321  |  |  | 
322  | 0  |   if (pspec->_nick)  | 
323  | 0  |     return pspec->_nick;  | 
324  | 0  |   else  | 
325  | 0  |     { | 
326  | 0  |       GParamSpec *redirect_target;  | 
327  |  | 
  | 
328  | 0  |       redirect_target = g_param_spec_get_redirect_target (pspec);  | 
329  | 0  |       if (redirect_target && redirect_target->_nick)  | 
330  | 0  |   return redirect_target->_nick;  | 
331  | 0  |     }  | 
332  |  |  | 
333  | 0  |   return pspec->name;  | 
334  | 0  | }  | 
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  | 0  | { | 
347  | 0  |   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);  | 
348  |  |  | 
349  | 0  |   if (pspec->_blurb)  | 
350  | 0  |     return pspec->_blurb;  | 
351  | 0  |   else  | 
352  | 0  |     { | 
353  | 0  |       GParamSpec *redirect_target;  | 
354  |  | 
  | 
355  | 0  |       redirect_target = g_param_spec_get_redirect_target (pspec);  | 
356  | 0  |       if (redirect_target && redirect_target->_blurb)  | 
357  | 0  |   return redirect_target->_blurb;  | 
358  | 0  |     }  | 
359  |  |  | 
360  | 0  |   return NULL;  | 
361  | 0  | }  | 
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  | 0  | { | 
368  | 0  |   gchar *p;  | 
369  |  |     | 
370  | 0  |   for (p = key; *p != 0; p++)  | 
371  | 0  |     { | 
372  | 0  |       gchar c = *p;  | 
373  |  |         | 
374  | 0  |       if (c == '_')  | 
375  | 0  |         *p = '-';  | 
376  | 0  |     }  | 
377  | 0  | }  | 
378  |  |  | 
379  |  | /* @key must have already been validated with is_valid() */  | 
380  |  | static gboolean  | 
381  |  | is_canonical (const gchar *key)  | 
382  | 29  | { | 
383  | 29  |   return (strchr (key, '_') == NULL);  | 
384  | 29  | }  | 
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  | 11  | { | 
403  | 11  |   const gchar *p;  | 
404  |  |  | 
405  |  |   /* First character must be a letter. */  | 
406  | 11  |   if ((name[0] < 'A' || name[0] > 'Z') &&  | 
407  | 11  |       (name[0] < 'a' || name[0] > 'z'))  | 
408  | 0  |     return FALSE;  | 
409  |  |  | 
410  | 123  |   for (p = name; *p != 0; p++)  | 
411  | 112  |     { | 
412  | 112  |       const gchar c = *p;  | 
413  |  |  | 
414  | 112  |       if (c != '-' && c != '_' &&  | 
415  | 112  |           (c < '0' || c > '9') &&  | 
416  | 112  |           (c < 'A' || c > 'Z') &&  | 
417  | 112  |           (c < 'a' || c > 'z'))  | 
418  | 0  |         return FALSE;  | 
419  | 112  |     }  | 
420  |  |  | 
421  | 11  |   return TRUE;  | 
422  | 11  | }  | 
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  | 8  | { | 
455  | 8  |   GParamSpec *pspec;  | 
456  | 8  |   GParamSpecPrivate *priv;  | 
457  |  |     | 
458  | 8  |   g_return_val_if_fail (G_TYPE_IS_PARAM (param_type) && param_type != G_TYPE_PARAM, NULL);  | 
459  | 8  |   g_return_val_if_fail (name != NULL, NULL);  | 
460  | 8  |   g_return_val_if_fail (g_param_spec_is_valid_name (name), NULL);  | 
461  | 8  |   g_return_val_if_fail (!(flags & G_PARAM_STATIC_NAME) || is_canonical (name), NULL);  | 
462  |  |     | 
463  | 8  |   pspec = (gpointer) g_type_create_instance (param_type);  | 
464  |  |  | 
465  | 8  |   if (flags & G_PARAM_STATIC_NAME)  | 
466  | 5  |     { | 
467  |  |       /* pspec->name is not freed if (flags & G_PARAM_STATIC_NAME) */  | 
468  | 5  |       pspec->name = (gchar *) g_intern_static_string (name);  | 
469  | 5  |       if (!is_canonical (pspec->name))  | 
470  | 0  |         g_warning ("G_PARAM_STATIC_NAME used with non-canonical pspec name: %s", pspec->name); | 
471  | 5  |     }  | 
472  | 3  |   else  | 
473  | 3  |     { | 
474  | 3  |       if (is_canonical (name))  | 
475  | 3  |         pspec->name = (gchar *) g_intern_string (name);  | 
476  | 0  |       else  | 
477  | 0  |         { | 
478  | 0  |           gchar *tmp = g_strdup (name);  | 
479  | 0  |           canonicalize_key (tmp);  | 
480  | 0  |           pspec->name = (gchar *) g_intern_string (tmp);  | 
481  | 0  |           g_free (tmp);  | 
482  | 0  |         }  | 
483  | 3  |     }  | 
484  |  |  | 
485  | 8  |   priv = g_param_spec_get_private (pspec);  | 
486  | 8  |   priv->name_quark = g_quark_from_string (pspec->name);  | 
487  |  |  | 
488  | 8  |   if (flags & G_PARAM_STATIC_NICK)  | 
489  | 5  |     pspec->_nick = (gchar*) nick;  | 
490  | 3  |   else  | 
491  | 3  |     pspec->_nick = g_strdup (nick);  | 
492  |  |  | 
493  | 8  |   if (flags & G_PARAM_STATIC_BLURB)  | 
494  | 5  |     pspec->_blurb = (gchar*) blurb;  | 
495  | 3  |   else  | 
496  | 3  |     pspec->_blurb = g_strdup (blurb);  | 
497  |  |  | 
498  | 8  |   pspec->flags = (flags & G_PARAM_USER_MASK) | (flags & G_PARAM_MASK);  | 
499  |  |     | 
500  | 8  |   return pspec;  | 
501  | 8  | }  | 
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  | 0  | { | 
516  | 0  |   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);  | 
517  |  |     | 
518  | 0  |   return quark ? g_datalist_id_get_data (&pspec->qdata, quark) : NULL;  | 
519  | 0  | }  | 
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  | 0  | { | 
539  | 0  |   g_return_if_fail (G_IS_PARAM_SPEC (pspec));  | 
540  | 0  |   g_return_if_fail (quark > 0);  | 
541  |  |  | 
542  | 0  |   g_datalist_id_set_data (&pspec->qdata, quark, data);  | 
543  | 0  | }  | 
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  | 0  | { | 
565  | 0  |   g_return_if_fail (G_IS_PARAM_SPEC (pspec));  | 
566  | 0  |   g_return_if_fail (quark > 0);  | 
567  |  |  | 
568  | 0  |   g_datalist_id_set_data_full (&pspec->qdata, quark, data, data ? destroy : (GDestroyNotify) NULL);  | 
569  | 0  | }  | 
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  | 0  | { | 
587  | 0  |   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);  | 
588  | 0  |   g_return_val_if_fail (quark > 0, NULL);  | 
589  |  |     | 
590  | 0  |   return g_datalist_id_remove_no_notify (&pspec->qdata, quark);  | 
591  | 0  | }  | 
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  | 0  | { | 
613  | 0  |   GTypeInstance *inst = (GTypeInstance *)pspec;  | 
614  |  | 
  | 
615  | 0  |   if (inst && inst->g_class && inst->g_class->g_type == G_TYPE_PARAM_OVERRIDE)  | 
616  | 0  |     return ((GParamSpecOverride*)pspec)->overridden;  | 
617  | 0  |   else  | 
618  | 0  |     return NULL;  | 
619  | 0  | }  | 
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  | 3  | { | 
633  | 3  |   g_return_if_fail (G_IS_PARAM_SPEC (pspec));  | 
634  |  |  | 
635  | 3  |   if (G_VALUE_TYPE (value) == G_TYPE_INVALID)  | 
636  | 0  |     { | 
637  | 0  |       g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));  | 
638  | 0  |     }  | 
639  | 3  |   else  | 
640  | 3  |     { | 
641  | 3  |       g_return_if_fail (G_IS_VALUE (value));  | 
642  | 3  |       g_return_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value));  | 
643  | 3  |       g_value_reset (value);  | 
644  | 3  |     }  | 
645  |  |  | 
646  | 3  |   G_PARAM_SPEC_GET_CLASS (pspec)->value_set_default (pspec, value);  | 
647  | 3  | }  | 
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  | 0  | { | 
662  | 0  |   GValue dflt_value = G_VALUE_INIT;  | 
663  | 0  |   gboolean defaults;  | 
664  |  | 
  | 
665  | 0  |   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);  | 
666  | 0  |   g_return_val_if_fail (G_IS_VALUE (value), FALSE);  | 
667  | 0  |   g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value), FALSE);  | 
668  |  |  | 
669  | 0  |   g_value_init (&dflt_value, G_PARAM_SPEC_VALUE_TYPE (pspec));  | 
670  | 0  |   G_PARAM_SPEC_GET_CLASS (pspec)->value_set_default (pspec, &dflt_value);  | 
671  | 0  |   defaults = G_PARAM_SPEC_GET_CLASS (pspec)->values_cmp (pspec, value, &dflt_value) == 0;  | 
672  | 0  |   g_value_unset (&dflt_value);  | 
673  |  | 
  | 
674  | 0  |   return defaults;  | 
675  | 0  | }  | 
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  | 1.69k  | { | 
695  | 1.69k  |   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);  | 
696  | 1.69k  |   g_return_val_if_fail (G_IS_VALUE (value), FALSE);  | 
697  | 1.69k  |   g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value), FALSE);  | 
698  |  |  | 
699  | 1.69k  |   if (G_PARAM_SPEC_GET_CLASS (pspec)->value_validate)  | 
700  | 1.69k  |     { | 
701  | 1.69k  |       GValue oval = *value;  | 
702  |  |  | 
703  | 1.69k  |       if (G_PARAM_SPEC_GET_CLASS (pspec)->value_validate (pspec, value) ||  | 
704  | 1.69k  |     memcmp (&oval.data, &value->data, sizeof (oval.data)))  | 
705  | 0  |   return TRUE;  | 
706  | 1.69k  |     }  | 
707  |  |  | 
708  | 1.69k  |   return FALSE;  | 
709  | 1.69k  | }  | 
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  | 0  | { | 
728  | 0  |   GParamSpecClass *class;  | 
729  |  | 
  | 
730  | 0  |   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), TRUE);  | 
731  | 0  |   g_return_val_if_fail (G_IS_VALUE (value), TRUE);  | 
732  | 0  |   g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value), TRUE);  | 
733  |  |  | 
734  | 0  |   class = G_PARAM_SPEC_GET_CLASS (pspec);  | 
735  |  | 
  | 
736  | 0  |   if (class->value_is_valid)  | 
737  | 0  |     return class->value_is_valid (pspec, value);  | 
738  | 0  |   else if (class->value_validate)  | 
739  | 0  |     { | 
740  | 0  |       GValue val = G_VALUE_INIT;  | 
741  | 0  |       gboolean changed;  | 
742  |  | 
  | 
743  | 0  |       g_value_init (&val, G_VALUE_TYPE (value));  | 
744  | 0  |       g_value_copy (value, &val);  | 
745  |  | 
  | 
746  | 0  |       changed = class->value_validate (pspec, &val);  | 
747  |  | 
  | 
748  | 0  |       g_value_unset (&val);  | 
749  |  | 
  | 
750  | 0  |       return !changed;  | 
751  | 0  |     }  | 
752  |  |  | 
753  | 0  |   return TRUE;  | 
754  | 0  | }  | 
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  | 0  | { | 
781  | 0  |   GValue tmp_value = G_VALUE_INIT;  | 
782  |  | 
  | 
783  | 0  |   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);  | 
784  | 0  |   g_return_val_if_fail (G_IS_VALUE (src_value), FALSE);  | 
785  | 0  |   g_return_val_if_fail (G_IS_VALUE (dest_value), FALSE);  | 
786  | 0  |   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  | 0  |   g_value_init (&tmp_value, G_VALUE_TYPE (dest_value));  | 
791  | 0  |   if (g_value_transform (src_value, &tmp_value) &&  | 
792  | 0  |       (!g_param_value_validate (pspec, &tmp_value) || !strict_validation))  | 
793  | 0  |     { | 
794  | 0  |       g_value_unset (dest_value);  | 
795  |  |         | 
796  |  |       /* values are relocatable */  | 
797  | 0  |       memcpy (dest_value, &tmp_value, sizeof (tmp_value));  | 
798  |  |         | 
799  | 0  |       return TRUE;  | 
800  | 0  |     }  | 
801  | 0  |   else  | 
802  | 0  |     { | 
803  | 0  |       g_value_unset (&tmp_value);  | 
804  |  |         | 
805  | 0  |       return FALSE;  | 
806  | 0  |     }  | 
807  | 0  | }  | 
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  | 0  | { | 
826  | 0  |   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  | 0  |   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), 0);  | 
835  | 0  |   g_return_val_if_fail (G_IS_VALUE (value1), 0);  | 
836  | 0  |   g_return_val_if_fail (G_IS_VALUE (value2), 0);  | 
837  | 0  |   g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value1), 0);  | 
838  | 0  |   g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value2), 0);  | 
839  |  |  | 
840  | 0  |   cmp = G_PARAM_SPEC_GET_CLASS (pspec)->values_cmp (pspec, value1, value2);  | 
841  |  | 
  | 
842  | 0  |   return CLAMP (cmp, -1, 1);  | 
843  | 0  | }  | 
844  |  |  | 
845  |  | static void  | 
846  |  | value_param_init (GValue *value)  | 
847  | 0  | { | 
848  | 0  |   value->data[0].v_pointer = NULL;  | 
849  | 0  | }  | 
850  |  |  | 
851  |  | static void  | 
852  |  | value_param_free_value (GValue *value)  | 
853  | 0  | { | 
854  | 0  |   if (value->data[0].v_pointer)  | 
855  | 0  |     g_param_spec_unref (value->data[0].v_pointer);  | 
856  | 0  | }  | 
857  |  |  | 
858  |  | static void  | 
859  |  | value_param_copy_value (const GValue *src_value,  | 
860  |  |       GValue       *dest_value)  | 
861  | 0  | { | 
862  | 0  |   if (src_value->data[0].v_pointer)  | 
863  | 0  |     dest_value->data[0].v_pointer = g_param_spec_ref (src_value->data[0].v_pointer);  | 
864  | 0  |   else  | 
865  | 0  |     dest_value->data[0].v_pointer = NULL;  | 
866  | 0  | }  | 
867  |  |  | 
868  |  | static void  | 
869  |  | value_param_transform_value (const GValue *src_value,  | 
870  |  |            GValue       *dest_value)  | 
871  | 0  | { | 
872  | 0  |   if (src_value->data[0].v_pointer &&  | 
873  | 0  |       g_type_is_a (G_PARAM_SPEC_TYPE (dest_value->data[0].v_pointer), G_VALUE_TYPE (dest_value)))  | 
874  | 0  |     dest_value->data[0].v_pointer = g_param_spec_ref (src_value->data[0].v_pointer);  | 
875  | 0  |   else  | 
876  | 0  |     dest_value->data[0].v_pointer = NULL;  | 
877  | 0  | }  | 
878  |  |  | 
879  |  | static gpointer  | 
880  |  | value_param_peek_pointer (const GValue *value)  | 
881  | 0  | { | 
882  | 0  |   return value->data[0].v_pointer;  | 
883  | 0  | }  | 
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  | 0  | { | 
891  | 0  |   if (collect_values[0].v_pointer)  | 
892  | 0  |     { | 
893  | 0  |       GParamSpec *param = collect_values[0].v_pointer;  | 
894  |  | 
  | 
895  | 0  |       if (param->g_type_instance.g_class == NULL)  | 
896  | 0  |   return g_strconcat ("invalid unclassed param spec pointer for value type '", | 
897  | 0  |           G_VALUE_TYPE_NAME (value),  | 
898  | 0  |           "'",  | 
899  | 0  |           NULL);  | 
900  | 0  |       else if (!g_value_type_compatible (G_PARAM_SPEC_TYPE (param), G_VALUE_TYPE (value)))  | 
901  | 0  |   return g_strconcat ("invalid param spec type '", | 
902  | 0  |           G_PARAM_SPEC_TYPE_NAME (param),  | 
903  | 0  |           "' for value type '",  | 
904  | 0  |           G_VALUE_TYPE_NAME (value),  | 
905  | 0  |           "'",  | 
906  | 0  |           NULL);  | 
907  | 0  |       value->data[0].v_pointer = g_param_spec_ref (param);  | 
908  | 0  |     }  | 
909  | 0  |   else  | 
910  | 0  |     value->data[0].v_pointer = NULL;  | 
911  |  |  | 
912  | 0  |   return NULL;  | 
913  | 0  | }  | 
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  | 0  | { | 
921  | 0  |   GParamSpec **param_p = collect_values[0].v_pointer;  | 
922  |  | 
  | 
923  | 0  |   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  | 0  |   if (!value->data[0].v_pointer)  | 
926  | 0  |     *param_p = NULL;  | 
927  | 0  |   else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)  | 
928  | 0  |     *param_p = value->data[0].v_pointer;  | 
929  | 0  |   else  | 
930  | 0  |     *param_p = g_param_spec_ref (value->data[0].v_pointer);  | 
931  |  | 
  | 
932  | 0  |   return NULL;  | 
933  | 0  | }  | 
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  | 4.66k  | { | 
956  | 4.66k  |   const GParamSpec *key = key_spec;  | 
957  | 4.66k  |   const gchar *p;  | 
958  | 4.66k  |   guint h = (guint) key->owner_type;  | 
959  |  |  | 
960  | 51.3k  |   for (p = key->name; *p; p++)  | 
961  | 46.6k  |     h = (h << 5) - h + *p;  | 
962  |  |  | 
963  | 4.66k  |   return h;  | 
964  | 4.66k  | }  | 
965  |  |  | 
966  |  | static gboolean  | 
967  |  | param_spec_pool_equals (gconstpointer key_spec_1,  | 
968  |  |       gconstpointer key_spec_2)  | 
969  | 4.63k  | { | 
970  | 4.63k  |   const GParamSpec *key1 = key_spec_1;  | 
971  | 4.63k  |   const GParamSpec *key2 = key_spec_2;  | 
972  |  |  | 
973  | 4.63k  |   return (key1->owner_type == key2->owner_type &&  | 
974  | 4.63k  |           (key1->name == key2->name ||  | 
975  | 4.63k  |      strcmp (key1->name, key2->name) == 0));  | 
976  | 4.63k  | }  | 
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  | 2  | { | 
994  | 2  |   static GMutex init_mutex;  | 
995  | 2  |   GParamSpecPool *pool = g_new (GParamSpecPool, 1);  | 
996  |  |  | 
997  | 2  |   memcpy (&pool->mutex, &init_mutex, sizeof (init_mutex));  | 
998  | 2  |   pool->type_prefixing = type_prefixing != FALSE;  | 
999  | 2  |   pool->hash_table = g_hash_table_new (param_spec_pool_hash, param_spec_pool_equals);  | 
1000  |  |  | 
1001  | 2  |   return pool;  | 
1002  | 2  | }  | 
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  | 8  | { | 
1017  | 8  |   const gchar *p;  | 
1018  |  |     | 
1019  | 8  |   if (pool && pspec && owner_type > 0 && pspec->owner_type == 0)  | 
1020  | 8  |     { | 
1021  | 91  |       for (p = pspec->name; *p; p++)  | 
1022  | 83  |   { | 
1023  | 83  |     if (!strchr (G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-_", *p))  | 
1024  | 0  |       { | 
1025  | 0  |         g_critical (G_STRLOC ": pspec name \"%s\" contains invalid characters", pspec->name);  | 
1026  | 0  |         return;  | 
1027  | 0  |       }  | 
1028  | 83  |   }  | 
1029  | 8  |       g_mutex_lock (&pool->mutex);  | 
1030  | 8  |       pspec->owner_type = owner_type;  | 
1031  | 8  |       g_param_spec_ref (pspec);  | 
1032  | 8  |       g_hash_table_add (pool->hash_table, pspec);  | 
1033  | 8  |       g_mutex_unlock (&pool->mutex);  | 
1034  | 8  |     }  | 
1035  | 0  |   else  | 
1036  | 0  |     { | 
1037  | 0  |       g_return_if_fail (pool != NULL);  | 
1038  | 0  |       g_return_if_fail (pspec);  | 
1039  | 0  |       g_return_if_fail (owner_type > 0);  | 
1040  | 0  |       g_return_if_fail (pspec->owner_type == 0);  | 
1041  | 0  |     }  | 
1042  | 8  | }  | 
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  | 0  | { | 
1055  | 0  |   if (pool && pspec)  | 
1056  | 0  |     { | 
1057  | 0  |       g_mutex_lock (&pool->mutex);  | 
1058  | 0  |       if (g_hash_table_remove (pool->hash_table, pspec))  | 
1059  | 0  |   g_param_spec_unref (pspec);  | 
1060  | 0  |       else  | 
1061  | 0  |   g_critical (G_STRLOC ": attempt to remove unknown pspec '%s' from pool", pspec->name);  | 
1062  | 0  |       g_mutex_unlock (&pool->mutex);  | 
1063  | 0  |     }  | 
1064  | 0  |   else  | 
1065  | 0  |     { | 
1066  | 0  |       g_return_if_fail (pool != NULL);  | 
1067  | 0  |       g_return_if_fail (pspec);  | 
1068  | 0  |     }  | 
1069  | 0  | }  | 
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  | 4.65k  | { | 
1077  | 4.65k  |   GParamSpec key, *pspec;  | 
1078  |  |  | 
1079  | 4.65k  |   key.owner_type = owner_type;  | 
1080  | 4.65k  |   key.name = (gchar*) param_name;  | 
1081  | 4.65k  |   if (walk_ancestors)  | 
1082  | 4.64k  |     do  | 
1083  | 4.64k  |       { | 
1084  | 4.64k  |   pspec = g_hash_table_lookup (hash_table, &key);  | 
1085  | 4.64k  |   if (pspec)  | 
1086  | 4.63k  |     return pspec;  | 
1087  | 13  |   key.owner_type = g_type_parent (key.owner_type);  | 
1088  | 13  |       }  | 
1089  | 4.64k  |     while (key.owner_type);  | 
1090  | 8  |   else  | 
1091  | 8  |     pspec = g_hash_table_lookup (hash_table, &key);  | 
1092  |  |  | 
1093  | 16  |   if (!pspec && !is_canonical (param_name))  | 
1094  | 0  |     { | 
1095  | 0  |       gchar *canonical;  | 
1096  |  | 
  | 
1097  | 0  |       canonical = g_strdup (key.name);  | 
1098  | 0  |       canonicalize_key (canonical);  | 
1099  |  |  | 
1100  |  |       /* try canonicalized form */  | 
1101  | 0  |       key.name = canonical;  | 
1102  | 0  |       key.owner_type = owner_type;  | 
1103  |  | 
  | 
1104  | 0  |       if (walk_ancestors)  | 
1105  | 0  |         do  | 
1106  | 0  |           { | 
1107  | 0  |             pspec = g_hash_table_lookup (hash_table, &key);  | 
1108  | 0  |             if (pspec)  | 
1109  | 0  |               { | 
1110  | 0  |                 g_free (canonical);  | 
1111  | 0  |                 return pspec;  | 
1112  | 0  |               }  | 
1113  | 0  |             key.owner_type = g_type_parent (key.owner_type);  | 
1114  | 0  |           }  | 
1115  | 0  |         while (key.owner_type);  | 
1116  | 0  |       else  | 
1117  | 0  |         pspec = g_hash_table_lookup (hash_table, &key);  | 
1118  |  |  | 
1119  | 0  |       g_free (canonical);  | 
1120  | 0  |     }  | 
1121  |  |  | 
1122  | 16  |   return pspec;  | 
1123  | 16  | }  | 
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  | 4.65k  | { | 
1144  | 4.65k  |   GParamSpec *pspec;  | 
1145  |  |  | 
1146  | 4.65k  |   g_return_val_if_fail (pool != NULL, NULL);  | 
1147  | 4.65k  |   g_return_val_if_fail (param_name != NULL, NULL);  | 
1148  |  |  | 
1149  | 4.65k  |   g_mutex_lock (&pool->mutex);  | 
1150  |  |  | 
1151  |  |   /* try quick and away, i.e. without prefix */  | 
1152  | 4.65k  |   pspec = param_spec_ht_lookup (pool->hash_table, param_name, owner_type, walk_ancestors);  | 
1153  | 4.65k  |   if (pspec)  | 
1154  | 4.63k  |     { | 
1155  | 4.63k  |       g_mutex_unlock (&pool->mutex);  | 
1156  | 4.63k  |       return pspec;  | 
1157  | 4.63k  |     }  | 
1158  |  |  | 
1159  | 16  |   if (pool->type_prefixing)  | 
1160  | 16  |     { | 
1161  | 16  |       char *delim;  | 
1162  |  |  | 
1163  | 16  |       delim = strchr (param_name, ':');  | 
1164  |  |  | 
1165  |  |       /* strip type prefix */  | 
1166  | 16  |       if (delim && delim[1] == ':')  | 
1167  | 0  |         { | 
1168  | 0  |           guint l = delim - param_name;  | 
1169  | 0  |           gchar stack_buffer[32], *buffer = l < 32 ? stack_buffer : g_new (gchar, l + 1);  | 
1170  | 0  |           GType type;  | 
1171  |  | 
  | 
1172  | 0  |           strncpy (buffer, param_name, delim - param_name);  | 
1173  | 0  |           buffer[l] = 0;  | 
1174  | 0  |           type = g_type_from_name (buffer);  | 
1175  | 0  |           if (l >= 32)  | 
1176  | 0  |             g_free (buffer);  | 
1177  | 0  |           if (type)         /* type==0 isn't a valid type pefix */  | 
1178  | 0  |             { | 
1179  |  |               /* sanity check, these cases don't make a whole lot of sense */  | 
1180  | 0  |               if ((!walk_ancestors && type != owner_type) || !g_type_is_a (owner_type, type))  | 
1181  | 0  |                 { | 
1182  | 0  |                   g_mutex_unlock (&pool->mutex);  | 
1183  |  | 
  | 
1184  | 0  |                   return NULL;  | 
1185  | 0  |                 }  | 
1186  | 0  |               owner_type = type;  | 
1187  | 0  |               param_name += l + 2;  | 
1188  | 0  |               pspec = param_spec_ht_lookup (pool->hash_table, param_name, owner_type, walk_ancestors);  | 
1189  | 0  |               g_mutex_unlock (&pool->mutex);  | 
1190  |  | 
  | 
1191  | 0  |               return pspec;  | 
1192  | 0  |             }  | 
1193  | 0  |         }  | 
1194  | 16  |     }  | 
1195  |  |  | 
1196  |  |   /* malformed param_name */  | 
1197  |  |  | 
1198  | 16  |   g_mutex_unlock (&pool->mutex);  | 
1199  |  |  | 
1200  | 16  |   return NULL;  | 
1201  | 16  | }  | 
1202  |  |  | 
1203  |  | static void  | 
1204  |  | pool_list (gpointer key,  | 
1205  |  |      gpointer value,  | 
1206  |  |      gpointer user_data)  | 
1207  | 0  | { | 
1208  | 0  |   GParamSpec *pspec = value;  | 
1209  | 0  |   gpointer *data = user_data;  | 
1210  | 0  |   GType owner_type = (GType) data[1];  | 
1211  |  | 
  | 
1212  | 0  |   if (owner_type == pspec->owner_type)  | 
1213  | 0  |     data[0] = g_list_prepend (data[0], pspec);  | 
1214  | 0  | }  | 
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  | 0  | { | 
1232  | 0  |   gpointer data[2];  | 
1233  |  | 
  | 
1234  | 0  |   g_return_val_if_fail (pool != NULL, NULL);  | 
1235  | 0  |   g_return_val_if_fail (owner_type > 0, NULL);  | 
1236  |  |     | 
1237  | 0  |   g_mutex_lock (&pool->mutex);  | 
1238  | 0  |   data[0] = NULL;  | 
1239  | 0  |   data[1] = (gpointer) owner_type;  | 
1240  | 0  |   g_hash_table_foreach (pool->hash_table, pool_list, &data);  | 
1241  | 0  |   g_mutex_unlock (&pool->mutex);  | 
1242  |  | 
  | 
1243  | 0  |   return data[0];  | 
1244  | 0  | }  | 
1245  |  |  | 
1246  |  | static gint  | 
1247  |  | pspec_compare_id (gconstpointer a,  | 
1248  |  |       gconstpointer b)  | 
1249  | 0  | { | 
1250  | 0  |   const GParamSpec *pspec1 = a, *pspec2 = b;  | 
1251  |  | 
  | 
1252  | 0  |   if (pspec1->param_id < pspec2->param_id)  | 
1253  | 0  |     return -1;  | 
1254  |  |  | 
1255  | 0  |   if (pspec1->param_id > pspec2->param_id)  | 
1256  | 0  |     return 1;  | 
1257  |  |  | 
1258  | 0  |   return strcmp (pspec1->name, pspec2->name);  | 
1259  | 0  | }  | 
1260  |  |  | 
1261  |  | static inline gboolean  | 
1262  |  | should_list_pspec (GParamSpec *pspec,  | 
1263  |  |                    GType      owner_type,  | 
1264  |  |                    GHashTable *ht)  | 
1265  | 0  | { | 
1266  | 0  |   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  | 0  |   if (g_param_spec_get_redirect_target (pspec))  | 
1274  | 0  |     return FALSE;  | 
1275  |  |  | 
1276  | 0  |   found = param_spec_ht_lookup (ht, pspec->name, owner_type, TRUE);  | 
1277  | 0  |   if (found != pspec)  | 
1278  | 0  |     { | 
1279  | 0  |       GParamSpec *redirect = g_param_spec_get_redirect_target (found);  | 
1280  | 0  |       if (redirect != pspec)  | 
1281  | 0  |         return FALSE;  | 
1282  | 0  |     }  | 
1283  |  |  | 
1284  | 0  |   return TRUE;  | 
1285  | 0  | }  | 
1286  |  |  | 
1287  |  | static void  | 
1288  |  | pool_depth_list (gpointer key,  | 
1289  |  |      gpointer value,  | 
1290  |  |      gpointer user_data)  | 
1291  | 0  | { | 
1292  | 0  |   GParamSpec *pspec = value;  | 
1293  | 0  |   gpointer *data = user_data;  | 
1294  | 0  |   GSList **slists = data[0];  | 
1295  | 0  |   GType owner_type = (GType) data[1];  | 
1296  | 0  |   GHashTable *ht = data[2];  | 
1297  | 0  |   int *count = data[3];  | 
1298  |  | 
  | 
1299  | 0  |   if (g_type_is_a (owner_type, pspec->owner_type) &&  | 
1300  | 0  |       should_list_pspec (pspec, owner_type, ht))  | 
1301  | 0  |     { | 
1302  | 0  |       if (G_TYPE_IS_INTERFACE (pspec->owner_type))  | 
1303  | 0  |   { | 
1304  | 0  |     slists[0] = g_slist_prepend (slists[0], pspec);  | 
1305  | 0  |           *count = *count + 1;  | 
1306  | 0  |   }  | 
1307  | 0  |       else  | 
1308  | 0  |   { | 
1309  | 0  |           guint d = g_type_depth (pspec->owner_type);  | 
1310  |  | 
  | 
1311  | 0  |           slists[d - 1] = g_slist_prepend (slists[d - 1], pspec);  | 
1312  | 0  |           *count = *count + 1;  | 
1313  | 0  |   }  | 
1314  | 0  |     }  | 
1315  | 0  | }  | 
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  | 10  | { | 
1331  | 10  |   GParamSpec *pspec = value;  | 
1332  | 10  |   gpointer *data = user_data;  | 
1333  | 10  |   GSList **slists = data[0];  | 
1334  | 10  |   GType owner_type = (GType) data[1];  | 
1335  | 10  |   GHashTable *ht = data[2];  | 
1336  | 10  |   int *count = data[3];  | 
1337  |  |  | 
1338  | 10  |   if (pspec->owner_type == owner_type &&  | 
1339  | 10  |       should_list_pspec (pspec, owner_type, ht))  | 
1340  | 0  |     { | 
1341  | 0  |       slists[0] = g_slist_prepend (slists[0], pspec);  | 
1342  | 0  |       *count = *count + 1;  | 
1343  | 0  |     }  | 
1344  | 10  | }  | 
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  | 2  | { | 
1364  | 2  |   GParamSpec **pspecs, **p;  | 
1365  | 2  |   GSList **slists, *node;  | 
1366  | 2  |   gpointer data[4];  | 
1367  | 2  |   guint d, i;  | 
1368  | 2  |   int n_pspecs = 0;  | 
1369  |  |  | 
1370  | 2  |   g_return_val_if_fail (pool != NULL, NULL);  | 
1371  | 2  |   g_return_val_if_fail (owner_type > 0, NULL);  | 
1372  | 2  |   g_return_val_if_fail (n_pspecs_p != NULL, NULL);  | 
1373  |  |     | 
1374  | 2  |   g_mutex_lock (&pool->mutex);  | 
1375  | 2  |   d = g_type_depth (owner_type);  | 
1376  | 2  |   slists = g_new0 (GSList*, d);  | 
1377  | 2  |   data[0] = slists;  | 
1378  | 2  |   data[1] = (gpointer) owner_type;  | 
1379  | 2  |   data[2] = pool->hash_table;  | 
1380  | 2  |   data[3] = &n_pspecs;  | 
1381  |  |  | 
1382  | 2  |   g_hash_table_foreach (pool->hash_table,  | 
1383  | 2  |                         G_TYPE_IS_INTERFACE (owner_type) ?  | 
1384  | 2  |                           pool_depth_list_for_interface :  | 
1385  | 2  |                           pool_depth_list,  | 
1386  | 2  |                         &data);  | 
1387  |  |  | 
1388  | 2  |   pspecs = g_new (GParamSpec*, n_pspecs + 1);  | 
1389  | 2  |   p = pspecs;  | 
1390  | 6  |   for (i = 0; i < d; i++)  | 
1391  | 4  |     { | 
1392  | 4  |       slists[i] = g_slist_sort (slists[i], pspec_compare_id);  | 
1393  | 4  |       for (node = slists[i]; node; node = node->next)  | 
1394  | 0  |   *p++ = node->data;  | 
1395  | 4  |       g_slist_free (slists[i]);  | 
1396  | 4  |     }  | 
1397  | 2  |   *p++ = NULL;  | 
1398  | 2  |   g_free (slists);  | 
1399  | 2  |   g_mutex_unlock (&pool->mutex);  | 
1400  |  |  | 
1401  | 2  |   *n_pspecs_p = n_pspecs;  | 
1402  |  |  | 
1403  | 2  |   return pspecs;  | 
1404  | 2  | }  | 
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  | 81  | { | 
1425  | 81  |   GParamSpecClass *class = g_class;  | 
1426  | 81  |   ParamSpecClassInfo *info = class_data;  | 
1427  |  |  | 
1428  | 81  |   class->value_type = info->value_type;  | 
1429  | 81  |   if (info->finalize)  | 
1430  | 20  |     class->finalize = info->finalize;     /* optional */  | 
1431  | 81  |   class->value_set_default = info->value_set_default;  | 
1432  | 81  |   if (info->value_validate)  | 
1433  | 80  |     class->value_validate = info->value_validate; /* optional */  | 
1434  | 81  |   class->values_cmp = info->values_cmp;  | 
1435  | 81  |   g_free (class_data);  | 
1436  | 81  | }  | 
1437  |  |  | 
1438  |  | static void  | 
1439  |  | default_value_set_default (GParamSpec *pspec,  | 
1440  |  |          GValue     *value)  | 
1441  | 0  | { | 
1442  |  |   /* value is already zero initialized */  | 
1443  | 0  | }  | 
1444  |  |  | 
1445  |  | static gint  | 
1446  |  | default_values_cmp (GParamSpec   *pspec,  | 
1447  |  |         const GValue *value1,  | 
1448  |  |         const GValue *value2)  | 
1449  | 0  | { | 
1450  | 0  |   return memcmp (&value1->data, &value2->data, sizeof (value1->data));  | 
1451  | 0  | }  | 
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  | 92  | { | 
1471  | 92  |   GTypeInfo info = { | 
1472  | 92  |     sizeof (GParamSpecClass),      /* class_size */  | 
1473  | 92  |     NULL,                          /* base_init */  | 
1474  | 92  |     NULL,                          /* base_destroy */  | 
1475  | 92  |     param_spec_generic_class_init, /* class_init */  | 
1476  | 92  |     NULL,                          /* class_destroy */  | 
1477  | 92  |     NULL,                          /* class_data */  | 
1478  | 92  |     0,                             /* instance_size */  | 
1479  | 92  |     16,                            /* n_preallocs */  | 
1480  | 92  |     NULL,                          /* instance_init */  | 
1481  | 92  |     NULL,                          /* value_table */  | 
1482  | 92  |   };  | 
1483  | 92  |   ParamSpecClassInfo *cinfo;  | 
1484  |  |  | 
1485  | 92  |   g_return_val_if_fail (name != NULL, 0);  | 
1486  | 92  |   g_return_val_if_fail (pspec_info != NULL, 0);  | 
1487  | 92  |   g_return_val_if_fail (g_type_from_name (name) == 0, 0);  | 
1488  | 92  |   g_return_val_if_fail (pspec_info->instance_size >= sizeof (GParamSpec), 0);  | 
1489  | 92  |   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  | 92  |   info.instance_size = pspec_info->instance_size;  | 
1495  | 92  |   info.n_preallocs = pspec_info->n_preallocs;  | 
1496  | 92  |   info.instance_init = (GInstanceInitFunc) pspec_info->instance_init;  | 
1497  | 92  |   cinfo = g_new (ParamSpecClassInfo, 1);  | 
1498  | 92  |   cinfo->value_type = pspec_info->value_type;  | 
1499  | 92  |   cinfo->finalize = pspec_info->finalize;  | 
1500  | 92  |   cinfo->value_set_default = pspec_info->value_set_default ? pspec_info->value_set_default : default_value_set_default;  | 
1501  | 92  |   cinfo->value_validate = pspec_info->value_validate;  | 
1502  | 92  |   cinfo->values_cmp = pspec_info->values_cmp ? pspec_info->values_cmp : default_values_cmp;  | 
1503  | 92  |   info.class_data = cinfo;  | 
1504  |  |  | 
1505  | 92  |   return g_type_register_static (G_TYPE_PARAM, name, &info, 0);  | 
1506  | 92  | }  | 
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  | 0  | { | 
1519  | 0  |   g_return_if_fail (G_VALUE_HOLDS_PARAM (value));  | 
1520  | 0  |   if (param)  | 
1521  | 0  |     g_return_if_fail (G_IS_PARAM_SPEC (param));  | 
1522  |  |  | 
1523  | 0  |   if (value->data[0].v_pointer)  | 
1524  | 0  |     g_param_spec_unref (value->data[0].v_pointer);  | 
1525  | 0  |   value->data[0].v_pointer = param;  | 
1526  | 0  |   if (value->data[0].v_pointer)  | 
1527  | 0  |     g_param_spec_ref (value->data[0].v_pointer);  | 
1528  | 0  | }  | 
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  | 0  | { | 
1543  | 0  |   g_value_take_param (value, param);  | 
1544  | 0  | }  | 
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  | 0  | { | 
1561  | 0  |   g_return_if_fail (G_VALUE_HOLDS_PARAM (value));  | 
1562  | 0  |   if (param)  | 
1563  | 0  |     g_return_if_fail (G_IS_PARAM_SPEC (param));  | 
1564  |  |  | 
1565  | 0  |   if (value->data[0].v_pointer)  | 
1566  | 0  |     g_param_spec_unref (value->data[0].v_pointer);  | 
1567  | 0  |   value->data[0].v_pointer = param; /* we take over the reference count */  | 
1568  | 0  | }  | 
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  | 0  | { | 
1581  | 0  |   g_return_val_if_fail (G_VALUE_HOLDS_PARAM (value), NULL);  | 
1582  |  |  | 
1583  | 0  |   return value->data[0].v_pointer;  | 
1584  | 0  | }  | 
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  | 0  | { | 
1599  | 0  |   g_return_val_if_fail (G_VALUE_HOLDS_PARAM (value), NULL);  | 
1600  |  |  | 
1601  | 0  |   return value->data[0].v_pointer ? g_param_spec_ref (value->data[0].v_pointer) : NULL;  | 
1602  | 0  | }  | 
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  | 2.53k  | { | 
1619  | 2.53k  |   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  | 2.53k  |   if (g_once_init_enter (&priv->default_value.g_type))  | 
1635  | 3  |     { | 
1636  | 3  |       GValue default_value = G_VALUE_INIT;  | 
1637  |  |  | 
1638  | 3  |       g_value_init (&default_value, pspec->value_type);  | 
1639  | 3  |       g_param_value_set_default (pspec, &default_value);  | 
1640  |  |  | 
1641  |  |       /* store all but the type */  | 
1642  | 3  |       memcpy (priv->default_value.data, default_value.data, sizeof (default_value.data));  | 
1643  |  |  | 
1644  | 3  |       g_once_init_leave (&priv->default_value.g_type, pspec->value_type);  | 
1645  | 3  |     }  | 
1646  |  |  | 
1647  | 2.53k  |   return &priv->default_value;  | 
1648  | 2.53k  | }  | 
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  | 0  | { | 
1663  | 0  |   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  | 0  |   return priv->name_quark;  | 
1671  | 0  | }  |