1 /* GObject - GLib Type, Object, Parameter and Signal Library
2 * Copyright (C) 1997-1999, 2000-2001 Tim Janik and Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General
15 * Public License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17 * Boston, MA 02111-1307, USA.
27 #include "gvaluecollector.h"
33 #define G_PARAM_SPEC_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_PARAM, GParamSpecClass))
34 #define G_PARAM_USER_MASK (~0 << G_PARAM_USER_SHIFT)
35 #define PSPEC_APPLIES_TO_VALUE(pspec, value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_PARAM_SPEC_VALUE_TYPE (pspec)))
36 #define G_SLOCK(mutex) g_static_mutex_lock (mutex)
37 #define G_SUNLOCK(mutex) g_static_mutex_unlock (mutex)
40 /* --- prototypes --- */
41 static void g_param_spec_class_base_init (GParamSpecClass
*class);
42 static void g_param_spec_class_base_finalize (GParamSpecClass
*class);
43 static void g_param_spec_class_init (GParamSpecClass
*class,
45 static void g_param_spec_init (GParamSpec
*pspec
,
46 GParamSpecClass
*class);
47 static void g_param_spec_finalize (GParamSpec
*pspec
);
48 static void value_param_init (GValue
*value
);
49 static void value_param_free_value (GValue
*value
);
50 static void value_param_copy_value (const GValue
*src_value
,
52 static void value_param_transform_value (const GValue
*src_value
,
54 static gpointer
value_param_peek_pointer (const GValue
*value
);
55 static gchar
* value_param_collect_value (GValue
*value
,
56 guint n_collect_values
,
57 GTypeCValue
*collect_values
,
59 static gchar
* value_param_lcopy_value (const GValue
*value
,
60 guint n_collect_values
,
61 GTypeCValue
*collect_values
,
65 /* --- variables --- */
66 static GQuark quark_floating
= 0;
67 G_LOCK_DEFINE_STATIC (pspec_ref_count
);
70 /* --- functions --- */
72 g_param_type_init (void) /* sync with gtype.c */
74 static const GTypeFundamentalInfo finfo
= {
75 (G_TYPE_FLAG_CLASSED
|
76 G_TYPE_FLAG_INSTANTIATABLE
|
77 G_TYPE_FLAG_DERIVABLE
|
78 G_TYPE_FLAG_DEEP_DERIVABLE
),
80 static const GTypeValueTable param_value_table
= {
81 value_param_init
, /* value_init */
82 value_param_free_value
, /* value_free */
83 value_param_copy_value
, /* value_copy */
84 value_param_peek_pointer
, /* value_peek_pointer */
85 "p", /* collect_format */
86 value_param_collect_value
, /* collect_value */
87 "p", /* lcopy_format */
88 value_param_lcopy_value
, /* lcopy_value */
90 static const GTypeInfo param_spec_info
= {
91 sizeof (GParamSpecClass
),
93 (GBaseInitFunc
) g_param_spec_class_base_init
,
94 (GBaseFinalizeFunc
) g_param_spec_class_base_finalize
,
95 (GClassInitFunc
) g_param_spec_class_init
,
96 (GClassFinalizeFunc
) NULL
,
97 NULL
, /* class_data */
101 (GInstanceInitFunc
) g_param_spec_init
,
107 type
= g_type_register_fundamental (G_TYPE_PARAM
, "GParam", ¶m_spec_info
, &finfo
, G_TYPE_FLAG_ABSTRACT
);
108 g_assert (type
== G_TYPE_PARAM
);
109 g_value_register_transform_func (G_TYPE_PARAM
, G_TYPE_PARAM
, value_param_transform_value
);
113 g_param_spec_class_base_init (GParamSpecClass
*class)
118 g_param_spec_class_base_finalize (GParamSpecClass
*class)
123 g_param_spec_class_init (GParamSpecClass
*class,
126 quark_floating
= g_quark_from_static_string ("GParamSpec-floating");
128 class->value_type
= G_TYPE_NONE
;
129 class->finalize
= g_param_spec_finalize
;
130 class->value_set_default
= NULL
;
131 class->value_validate
= NULL
;
132 class->values_cmp
= NULL
;
136 g_param_spec_init (GParamSpec
*pspec
,
137 GParamSpecClass
*class)
141 pspec
->_blurb
= NULL
;
143 pspec
->value_type
= class->value_type
;
144 pspec
->owner_type
= 0;
146 pspec
->ref_count
= 1;
148 g_datalist_id_set_data (&pspec
->qdata
, quark_floating
, GUINT_TO_POINTER (TRUE
));
152 g_param_spec_finalize (GParamSpec
*pspec
)
154 g_datalist_clear (&pspec
->qdata
);
156 g_free (pspec
->name
);
157 g_free (pspec
->_nick
);
158 g_free (pspec
->_blurb
);
160 g_type_free_instance ((GTypeInstance
*) pspec
);
164 g_param_spec_ref (GParamSpec
*pspec
)
166 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec
), NULL
);
168 G_LOCK (pspec_ref_count
);
169 if (pspec
->ref_count
> 0)
171 pspec
->ref_count
+= 1;
172 G_UNLOCK (pspec_ref_count
);
176 G_UNLOCK (pspec_ref_count
);
177 g_return_val_if_fail (pspec
->ref_count
> 0, NULL
);
184 g_param_spec_unref (GParamSpec
*pspec
)
186 g_return_if_fail (G_IS_PARAM_SPEC (pspec
));
188 G_LOCK (pspec_ref_count
);
189 if (pspec
->ref_count
> 0)
191 gboolean need_finalize
;
193 /* sync with _sink */
194 pspec
->ref_count
-= 1;
195 need_finalize
= pspec
->ref_count
== 0;
196 G_UNLOCK (pspec_ref_count
);
198 G_PARAM_SPEC_GET_CLASS (pspec
)->finalize (pspec
);
202 G_UNLOCK (pspec_ref_count
);
203 g_return_if_fail (pspec
->ref_count
> 0);
208 g_param_spec_sink (GParamSpec
*pspec
)
210 g_return_if_fail (G_IS_PARAM_SPEC (pspec
));
212 G_LOCK (pspec_ref_count
);
213 if (pspec
->ref_count
> 0)
215 if (g_datalist_id_remove_no_notify (&pspec
->qdata
, quark_floating
))
217 /* sync with _unref */
218 if (pspec
->ref_count
> 1)
219 pspec
->ref_count
-= 1;
222 G_UNLOCK (pspec_ref_count
);
223 g_param_spec_unref (pspec
);
228 G_UNLOCK (pspec_ref_count
);
232 G_UNLOCK (pspec_ref_count
);
233 g_return_if_fail (pspec
->ref_count
> 0);
237 G_CONST_RETURN gchar
*
238 g_param_get_name (GParamSpec
*pspec
)
240 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec
), NULL
);
245 G_CONST_RETURN gchar
*
246 g_param_get_nick (GParamSpec
*pspec
)
248 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec
), NULL
);
250 return pspec
->_nick
? pspec
->_nick
: pspec
->name
;
253 G_CONST_RETURN gchar
*
254 g_param_get_blurb (GParamSpec
*pspec
)
256 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec
), NULL
);
258 return pspec
->_blurb
;
262 g_param_spec_internal (GType param_type
,
270 g_return_val_if_fail (G_TYPE_IS_PARAM (param_type
) && param_type
!= G_TYPE_PARAM
, NULL
);
271 g_return_val_if_fail (name
!= NULL
, NULL
);
272 g_return_val_if_fail ((name
[0] >= 'A' && name
[0] <= 'Z') || (name
[0] >= 'a' && name
[0] <= 'z'), NULL
);
274 pspec
= (gpointer
) g_type_create_instance (param_type
);
275 pspec
->name
= g_strdup (name
);
276 g_strcanon (pspec
->name
, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS
"-", '-');
277 pspec
->_nick
= g_strdup (nick
);
278 pspec
->_blurb
= g_strdup (blurb
);
279 pspec
->flags
= (flags
& G_PARAM_USER_MASK
) | (flags
& G_PARAM_MASK
);
285 g_param_spec_get_qdata (GParamSpec
*pspec
,
288 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec
), NULL
);
290 return quark
? g_datalist_id_get_data (&pspec
->qdata
, quark
) : NULL
;
294 g_param_spec_set_qdata (GParamSpec
*pspec
,
298 g_return_if_fail (G_IS_PARAM_SPEC (pspec
));
299 g_return_if_fail (quark
> 0);
301 g_datalist_id_set_data (&pspec
->qdata
, quark
, data
);
305 g_param_spec_set_qdata_full (GParamSpec
*pspec
,
308 GDestroyNotify destroy
)
310 g_return_if_fail (G_IS_PARAM_SPEC (pspec
));
311 g_return_if_fail (quark
> 0);
313 g_datalist_id_set_data_full (&pspec
->qdata
, quark
, data
, data
? destroy
: (GDestroyNotify
) NULL
);
317 g_param_spec_steal_qdata (GParamSpec
*pspec
,
320 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec
), NULL
);
321 g_return_val_if_fail (quark
> 0, NULL
);
323 return g_datalist_id_remove_no_notify (&pspec
->qdata
, quark
);
327 g_param_value_set_default (GParamSpec
*pspec
,
330 g_return_if_fail (G_IS_PARAM_SPEC (pspec
));
331 g_return_if_fail (G_IS_VALUE (value
));
332 g_return_if_fail (PSPEC_APPLIES_TO_VALUE (pspec
, value
));
334 g_value_reset (value
);
335 G_PARAM_SPEC_GET_CLASS (pspec
)->value_set_default (pspec
, value
);
339 g_param_value_defaults (GParamSpec
*pspec
,
342 GValue dflt_value
= { 0, };
345 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec
), FALSE
);
346 g_return_val_if_fail (G_IS_VALUE (value
), FALSE
);
347 g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec
, value
), FALSE
);
349 g_value_init (&dflt_value
, G_PARAM_SPEC_VALUE_TYPE (pspec
));
350 G_PARAM_SPEC_GET_CLASS (pspec
)->value_set_default (pspec
, &dflt_value
);
351 defaults
= G_PARAM_SPEC_GET_CLASS (pspec
)->values_cmp (pspec
, value
, &dflt_value
) == 0;
352 g_value_unset (&dflt_value
);
358 g_param_value_validate (GParamSpec
*pspec
,
361 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec
), FALSE
);
362 g_return_val_if_fail (G_IS_VALUE (value
), FALSE
);
363 g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec
, value
), FALSE
);
365 if (G_PARAM_SPEC_GET_CLASS (pspec
)->value_validate
)
367 GValue oval
= *value
;
369 if (G_PARAM_SPEC_GET_CLASS (pspec
)->value_validate (pspec
, value
) ||
370 memcmp (&oval
.data
, &value
->data
, sizeof (oval
.data
)))
378 g_param_value_convert (GParamSpec
*pspec
,
379 const GValue
*src_value
,
381 gboolean strict_validation
)
383 GValue tmp_value
= { 0, };
385 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec
), FALSE
);
386 g_return_val_if_fail (G_IS_VALUE (src_value
), FALSE
);
387 g_return_val_if_fail (G_IS_VALUE (dest_value
), FALSE
);
388 g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec
, dest_value
), FALSE
);
390 /* better leave dest_value untouched when returning FALSE */
392 g_value_init (&tmp_value
, G_VALUE_TYPE (dest_value
));
393 if (g_value_transform (src_value
, &tmp_value
) &&
394 (!g_param_value_validate (pspec
, &tmp_value
) || !strict_validation
))
396 g_value_unset (dest_value
);
398 /* values are relocatable */
399 memcpy (dest_value
, &tmp_value
, sizeof (tmp_value
));
405 g_value_unset (&tmp_value
);
412 g_param_values_cmp (GParamSpec
*pspec
,
413 const GValue
*value1
,
414 const GValue
*value2
)
418 /* param_values_cmp() effectively does: value1 - value2
419 * so the return values are:
420 * -1) value1 < value2
421 * 0) value1 == value2
424 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec
), 0);
425 g_return_val_if_fail (G_IS_VALUE (value1
), 0);
426 g_return_val_if_fail (G_IS_VALUE (value2
), 0);
427 g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec
, value1
), 0);
428 g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec
, value2
), 0);
430 cmp
= G_PARAM_SPEC_GET_CLASS (pspec
)->values_cmp (pspec
, value1
, value2
);
432 return CLAMP (cmp
, -1, 1);
436 value_param_init (GValue
*value
)
438 value
->data
[0].v_pointer
= NULL
;
442 value_param_free_value (GValue
*value
)
444 if (value
->data
[0].v_pointer
)
445 g_param_spec_unref (value
->data
[0].v_pointer
);
449 value_param_copy_value (const GValue
*src_value
,
452 if (src_value
->data
[0].v_pointer
)
453 dest_value
->data
[0].v_pointer
= g_param_spec_ref (src_value
->data
[0].v_pointer
);
455 dest_value
->data
[0].v_pointer
= NULL
;
459 value_param_transform_value (const GValue
*src_value
,
462 if (src_value
->data
[0].v_pointer
&&
463 g_type_is_a (G_PARAM_SPEC_TYPE (dest_value
->data
[0].v_pointer
), G_VALUE_TYPE (dest_value
)))
464 dest_value
->data
[0].v_pointer
= g_param_spec_ref (src_value
->data
[0].v_pointer
);
466 dest_value
->data
[0].v_pointer
= NULL
;
470 value_param_peek_pointer (const GValue
*value
)
472 return value
->data
[0].v_pointer
;
476 value_param_collect_value (GValue
*value
,
477 guint n_collect_values
,
478 GTypeCValue
*collect_values
,
481 if (collect_values
[0].v_pointer
)
483 GParamSpec
*param
= collect_values
[0].v_pointer
;
485 if (param
->g_type_instance
.g_class
== NULL
)
486 return g_strconcat ("invalid unclassed param spec pointer for value type `",
487 G_VALUE_TYPE_NAME (value
),
490 else if (!g_value_type_compatible (G_PARAM_SPEC_TYPE (param
), G_VALUE_TYPE (value
)))
491 return g_strconcat ("invalid param spec type `",
492 G_PARAM_SPEC_TYPE_NAME (param
),
493 "' for value type `",
494 G_VALUE_TYPE_NAME (value
),
497 value
->data
[0].v_pointer
= g_param_spec_ref (param
);
500 value
->data
[0].v_pointer
= NULL
;
506 value_param_lcopy_value (const GValue
*value
,
507 guint n_collect_values
,
508 GTypeCValue
*collect_values
,
511 GParamSpec
**param_p
= collect_values
[0].v_pointer
;
514 return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value
));
516 if (!value
->data
[0].v_pointer
)
518 else if (collect_flags
& G_VALUE_NOCOPY_CONTENTS
)
519 *param_p
= value
->data
[0].v_pointer
;
521 *param_p
= g_param_spec_ref (value
->data
[0].v_pointer
);
527 /* --- param spec pool --- */
528 struct _GParamSpecPool
531 gboolean type_prefixing
;
532 GHashTable
*hash_table
;
536 param_spec_pool_hash (gconstpointer key_spec
)
538 const GParamSpec
*key
= key_spec
;
540 guint h
= key
->owner_type
;
542 for (p
= key
->name
; *p
; p
++)
543 h
= (h
<< 5) - h
+ *p
;
549 param_spec_pool_equals (gconstpointer key_spec_1
,
550 gconstpointer key_spec_2
)
552 const GParamSpec
*key1
= key_spec_1
;
553 const GParamSpec
*key2
= key_spec_2
;
555 return (key1
->owner_type
== key2
->owner_type
&&
556 strcmp (key1
->name
, key2
->name
) == 0);
560 g_param_spec_pool_new (gboolean type_prefixing
)
562 static GStaticMutex init_smutex
= G_STATIC_MUTEX_INIT
;
563 GParamSpecPool
*pool
= g_new (GParamSpecPool
, 1);
565 memcpy (&pool
->smutex
, &init_smutex
, sizeof (init_smutex
));
566 pool
->type_prefixing
= type_prefixing
!= FALSE
;
567 pool
->hash_table
= g_hash_table_new (param_spec_pool_hash
, param_spec_pool_equals
);
573 g_param_spec_pool_insert (GParamSpecPool
*pool
,
579 if (pool
&& pspec
&& owner_type
> 0 && pspec
->owner_type
== 0)
581 G_SLOCK (&pool
->smutex
);
582 for (p
= pspec
->name
; *p
; p
++)
584 if (!strchr (G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS
"-_", *p
))
586 g_warning (G_STRLOC
": pspec name \"%s\" contains invalid characters", pspec
->name
);
587 G_SUNLOCK (&pool
->smutex
);
592 pspec
->owner_type
= owner_type
;
593 g_param_spec_ref (pspec
);
594 g_hash_table_insert (pool
->hash_table
, pspec
, pspec
);
595 G_SUNLOCK (&pool
->smutex
);
599 g_return_if_fail (pool
!= NULL
);
600 g_return_if_fail (pspec
);
601 g_return_if_fail (owner_type
> 0);
602 g_return_if_fail (pspec
->owner_type
== 0);
607 g_param_spec_pool_remove (GParamSpecPool
*pool
,
612 G_SLOCK (&pool
->smutex
);
613 if (g_hash_table_remove (pool
->hash_table
, pspec
))
614 g_param_spec_unref (pspec
);
616 g_warning (G_STRLOC
": attempt to remove unknown pspec `%s' from pool", pspec
->name
);
617 G_SUNLOCK (&pool
->smutex
);
621 g_return_if_fail (pool
!= NULL
);
622 g_return_if_fail (pspec
);
626 static inline GParamSpec
*
627 param_spec_ht_lookup (GHashTable
*hash_table
,
628 const gchar
*param_name
,
630 gboolean walk_ancestors
)
632 GParamSpec key
, *pspec
;
634 key
.owner_type
= owner_type
;
635 key
.name
= (gchar
*) param_name
;
639 pspec
= g_hash_table_lookup (hash_table
, &key
);
642 key
.owner_type
= g_type_parent (key
.owner_type
);
644 while (key
.owner_type
);
646 pspec
= g_hash_table_lookup (hash_table
, &key
);
650 /* try canonicalized form */
651 key
.name
= g_strdup (param_name
);
652 key
.owner_type
= owner_type
;
654 g_strcanon (key
.name
, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS
"-", '-');
658 pspec
= g_hash_table_lookup (hash_table
, &key
);
664 key
.owner_type
= g_type_parent (key
.owner_type
);
666 while (key
.owner_type
);
668 pspec
= g_hash_table_lookup (hash_table
, &key
);
676 g_param_spec_pool_lookup (GParamSpecPool
*pool
,
677 const gchar
*param_name
,
679 gboolean walk_ancestors
)
684 if (!pool
|| !param_name
)
686 g_return_val_if_fail (pool
!= NULL
, NULL
);
687 g_return_val_if_fail (param_name
!= NULL
, NULL
);
690 G_SLOCK (&pool
->smutex
);
692 delim
= pool
->type_prefixing
? strchr (param_name
, ':') : NULL
;
694 /* try quick and away, i.e. without prefix */
697 pspec
= param_spec_ht_lookup (pool
->hash_table
, param_name
, owner_type
, walk_ancestors
);
698 G_SUNLOCK (&pool
->smutex
);
703 /* strip type prefix */
704 if (pool
->type_prefixing
&& delim
[1] == ':')
706 guint l
= delim
- param_name
;
707 gchar stack_buffer
[32], *buffer
= l
< 32 ? stack_buffer
: g_new (gchar
, l
+ 1);
710 strncpy (buffer
, param_name
, delim
- param_name
);
712 type
= g_type_from_name (buffer
);
715 if (type
) /* type==0 isn't a valid type pefix */
717 /* sanity check, these cases don't make a whole lot of sense */
718 if ((!walk_ancestors
&& type
!= owner_type
) || !g_type_is_a (owner_type
, type
))
720 G_SUNLOCK (&pool
->smutex
);
726 pspec
= param_spec_ht_lookup (pool
->hash_table
, param_name
, owner_type
, walk_ancestors
);
727 G_SUNLOCK (&pool
->smutex
);
732 /* malformed param_name */
734 G_SUNLOCK (&pool
->smutex
);
740 pool_list (gpointer key
,
744 GParamSpec
*pspec
= value
;
745 gpointer
*data
= user_data
;
746 GType owner_type
= GPOINTER_TO_UINT (data
[1]);
748 if (owner_type
== pspec
->owner_type
)
749 data
[0] = g_list_prepend (data
[0], pspec
);
753 g_param_spec_pool_list_owned (GParamSpecPool
*pool
,
758 g_return_val_if_fail (pool
!= NULL
, NULL
);
759 g_return_val_if_fail (owner_type
> 0, NULL
);
761 G_SLOCK (&pool
->smutex
);
763 data
[1] = GUINT_TO_POINTER (owner_type
);
764 g_hash_table_foreach (pool
->hash_table
, pool_list
, &data
);
765 G_SUNLOCK (&pool
->smutex
);
771 pspec_compare_id (gconstpointer a
,
774 const GParamSpec
*pspec1
= a
, *pspec2
= b
;
776 return pspec1
->param_id
< pspec2
->param_id
? -1 : pspec1
->param_id
> pspec2
->param_id
;
779 static inline GSList
*
780 pspec_list_remove_overridden (GSList
*plist
,
785 GSList
*rlist
= NULL
;
789 GSList
*tmp
= plist
->next
;
790 GParamSpec
*pspec
= plist
->data
;
792 if (param_spec_ht_lookup (ht
, pspec
->name
, owner_type
, TRUE
) != pspec
)
793 g_slist_free_1 (plist
);
806 pool_depth_list (gpointer key
,
810 GParamSpec
*pspec
= value
;
811 gpointer
*data
= user_data
;
812 GSList
**slists
= data
[0];
813 GType owner_type
= GPOINTER_TO_UINT (data
[1]);
815 if (g_type_is_a (owner_type
, pspec
->owner_type
))
817 guint d
= g_type_depth (pspec
->owner_type
);
819 slists
[d
- 1] = g_slist_prepend (slists
[d
- 1], pspec
);
823 GParamSpec
** /* free result */
824 g_param_spec_pool_list (GParamSpecPool
*pool
,
828 GParamSpec
**pspecs
, **p
;
829 GSList
**slists
, *node
;
833 g_return_val_if_fail (pool
!= NULL
, NULL
);
834 g_return_val_if_fail (owner_type
> 0, NULL
);
835 g_return_val_if_fail (n_pspecs_p
!= NULL
, NULL
);
837 G_SLOCK (&pool
->smutex
);
839 d
= g_type_depth (owner_type
);
840 slists
= g_new0 (GSList
*, d
);
842 data
[1] = GUINT_TO_POINTER (owner_type
);
843 g_hash_table_foreach (pool
->hash_table
, pool_depth_list
, &data
);
844 for (i
= 0; i
< d
- 1; i
++)
845 slists
[i
] = pspec_list_remove_overridden (slists
[i
], pool
->hash_table
, owner_type
, n_pspecs_p
);
846 *n_pspecs_p
+= g_slist_length (slists
[i
]);
847 pspecs
= g_new (GParamSpec
*, *n_pspecs_p
+ 1);
849 for (i
= 0; i
< d
; i
++)
851 slists
[i
] = g_slist_sort (slists
[i
], pspec_compare_id
);
852 for (node
= slists
[i
]; node
; node
= node
->next
)
854 g_slist_free (slists
[i
]);
858 G_SUNLOCK (&pool
->smutex
);
864 /* --- auxillary functions --- */
869 void (*finalize
) (GParamSpec
*pspec
);
870 void (*value_set_default
) (GParamSpec
*pspec
,
872 gboolean (*value_validate
) (GParamSpec
*pspec
,
874 gint (*values_cmp
) (GParamSpec
*pspec
,
875 const GValue
*value1
,
876 const GValue
*value2
);
877 } ParamSpecClassInfo
;
880 param_spec_generic_class_init (gpointer g_class
,
883 GParamSpecClass
*class = g_class
;
884 ParamSpecClassInfo
*info
= class_data
;
886 class->value_type
= info
->value_type
;
888 class->finalize
= info
->finalize
; /* optional */
889 class->value_set_default
= info
->value_set_default
;
890 if (info
->value_validate
)
891 class->value_validate
= info
->value_validate
; /* optional */
892 class->values_cmp
= info
->values_cmp
;
897 default_value_set_default (GParamSpec
*pspec
,
900 /* value is already zero initialized */
904 default_values_cmp (GParamSpec
*pspec
,
905 const GValue
*value1
,
906 const GValue
*value2
)
908 return memcmp (&value1
->data
, &value2
->data
, sizeof (value1
->data
));
912 g_param_type_register_static (const gchar
*name
,
913 const GParamSpecTypeInfo
*pspec_info
)
916 sizeof (GParamSpecClass
), /* class_size */
917 NULL
, /* base_init */
918 NULL
, /* base_destroy */
919 param_spec_generic_class_init
, /* class_init */
920 NULL
, /* class_destroy */
921 NULL
, /* class_data */
922 0, /* instance_size */
923 16, /* n_preallocs */
924 NULL
, /* instance_init */
926 ParamSpecClassInfo
*cinfo
;
928 g_return_val_if_fail (name
!= NULL
, 0);
929 g_return_val_if_fail (pspec_info
!= NULL
, 0);
930 g_return_val_if_fail (g_type_from_name (name
) == 0, 0);
931 g_return_val_if_fail (pspec_info
->instance_size
>= sizeof (GParamSpec
), 0);
932 g_return_val_if_fail (g_type_name (pspec_info
->value_type
) != NULL
, 0);
933 /* default: g_return_val_if_fail (pspec_info->value_set_default != NULL, 0); */
934 /* optional: g_return_val_if_fail (pspec_info->value_validate != NULL, 0); */
935 /* default: g_return_val_if_fail (pspec_info->values_cmp != NULL, 0); */
937 info
.instance_size
= pspec_info
->instance_size
;
938 info
.n_preallocs
= pspec_info
->n_preallocs
;
939 info
.instance_init
= (GInstanceInitFunc
) pspec_info
->instance_init
;
940 cinfo
= g_new (ParamSpecClassInfo
, 1);
941 cinfo
->value_type
= pspec_info
->value_type
;
942 cinfo
->finalize
= pspec_info
->finalize
;
943 cinfo
->value_set_default
= pspec_info
->value_set_default
? pspec_info
->value_set_default
: default_value_set_default
;
944 cinfo
->value_validate
= pspec_info
->value_validate
;
945 cinfo
->values_cmp
= pspec_info
->values_cmp
? pspec_info
->values_cmp
: default_values_cmp
;
946 info
.class_data
= cinfo
;
948 return g_type_register_static (G_TYPE_PARAM
, name
, &info
, 0);
952 g_value_set_param (GValue
*value
,
955 g_return_if_fail (G_VALUE_HOLDS_PARAM (value
));
957 g_return_if_fail (G_IS_PARAM_SPEC (param
));
959 if (value
->data
[0].v_pointer
)
960 g_param_spec_unref (value
->data
[0].v_pointer
);
961 value
->data
[0].v_pointer
= param
;
962 if (value
->data
[0].v_pointer
)
963 g_param_spec_ref (value
->data
[0].v_pointer
);
967 g_value_get_param (const GValue
*value
)
969 g_return_val_if_fail (G_VALUE_HOLDS_PARAM (value
), NULL
);
971 return value
->data
[0].v_pointer
;
975 g_value_dup_param (const GValue
*value
)
977 g_return_val_if_fail (G_VALUE_HOLDS_PARAM (value
), NULL
);
979 return value
->data
[0].v_pointer
? g_param_spec_ref (value
->data
[0].v_pointer
) : NULL
;