gparam.c revision 9a8c33db5cc37bc3c6bd4794a03f4b99a847ff4a
1/* GObject - GLib Type, Object, Parameter and Signal Library 2 * Copyright (C) 1997, 1998, 1999, 2000 Tim Janik and Red Hat, Inc. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General 15 * Public License along with this library; if not, write to the 16 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, 17 * Boston, MA 02111-1307, USA. 18 */ 19#include "gparam.h" 20 21 22#include "gvaluecollector.h" 23#include <string.h> 24 25 26 27/* --- defines --- */ 28#define G_PARAM_SPEC_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_PARAM, GParamSpecClass)) 29#define PSPEC_APPLIES_TO_VALUE(pspec, value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_PARAM_SPEC_VALUE_TYPE (pspec))) 30 31 32/* --- prototypes --- */ 33static void g_param_spec_class_base_init (GParamSpecClass *class); 34static void g_param_spec_class_base_finalize (GParamSpecClass *class); 35static void g_param_spec_class_init (GParamSpecClass *class, 36 gpointer class_data); 37static void g_param_spec_init (GParamSpec *pspec); 38static void g_param_spec_finalize (GParamSpec *pspec); 39static void value_param_init (GValue *value); 40static void value_param_free_value (GValue *value); 41static void value_param_copy_value (const GValue *src_value, 42 GValue *dest_value); 43static gpointer value_param_peek_pointer (const GValue *value); 44static gchar* value_param_collect_value (GValue *value, 45 guint nth_value, 46 GType *collect_type, 47 GTypeCValue *collect_value); 48static gchar* value_param_lcopy_value (const GValue *value, 49 guint nth_value, 50 GType *collect_type, 51 GTypeCValue *collect_value); 52 53 54/* --- variables --- */ 55static GQuark quark_floating = 0; 56 57 58/* --- functions --- */ 59void 60g_param_type_init (void) /* sync with gtype.c */ 61{ 62 static const GTypeFundamentalInfo finfo = { 63 (G_TYPE_FLAG_CLASSED | 64 G_TYPE_FLAG_INSTANTIATABLE | 65 G_TYPE_FLAG_DERIVABLE | 66 G_TYPE_FLAG_DEEP_DERIVABLE), 67 }; 68 static const GTypeValueTable param_value_table = { 69 value_param_init, /* value_init */ 70 value_param_free_value, /* value_free */ 71 value_param_copy_value, /* value_copy */ 72 value_param_peek_pointer, /* value_peek_pointer */ 73 G_VALUE_COLLECT_POINTER, /* collect_type */ 74 value_param_collect_value, /* collect_value */ 75 G_VALUE_COLLECT_POINTER, /* lcopy_type */ 76 value_param_lcopy_value, /* lcopy_value */ 77 }; 78 static const GTypeInfo param_spec_info = { 79 sizeof (GParamSpecClass), 80 81 (GBaseInitFunc) g_param_spec_class_base_init, 82 (GBaseFinalizeFunc) g_param_spec_class_base_finalize, 83 (GClassInitFunc) g_param_spec_class_init, 84 (GClassFinalizeFunc) NULL, 85 NULL, /* class_data */ 86 87 sizeof (GParamSpec), 88 0, /* n_preallocs */ 89 (GInstanceInitFunc) g_param_spec_init, 90 91 ¶m_value_table, 92 }; 93 GType type; 94 95 type = g_type_register_fundamental (G_TYPE_PARAM, "GParam", ¶m_spec_info, &finfo, G_TYPE_FLAG_ABSTRACT); 96 g_assert (type == G_TYPE_PARAM); 97} 98 99static void 100g_param_spec_class_base_init (GParamSpecClass *class) 101{ 102} 103 104static void 105g_param_spec_class_base_finalize (GParamSpecClass *class) 106{ 107} 108 109static void 110g_param_spec_class_init (GParamSpecClass *class, 111 gpointer class_data) 112{ 113 quark_floating = g_quark_from_static_string ("GParamSpec-floating"); 114 115 class->value_type = G_TYPE_NONE; 116 class->finalize = g_param_spec_finalize; 117 class->value_set_default = NULL; 118 class->value_validate = NULL; 119 class->values_cmp = NULL; 120} 121 122static void 123g_param_spec_init (GParamSpec *pspec) 124{ 125 pspec->name = NULL; 126 pspec->nick = NULL; 127 pspec->blurb = NULL; 128 pspec->flags = 0; 129 pspec->owner_type = 0; 130 pspec->qdata = NULL; 131 pspec->ref_count = 1; 132 g_datalist_id_set_data (&pspec->qdata, quark_floating, GUINT_TO_POINTER (TRUE)); 133} 134 135static void 136g_param_spec_finalize (GParamSpec *pspec) 137{ 138 g_datalist_clear (&pspec->qdata); 139 140 g_free (pspec->name); 141 g_free (pspec->nick); 142 g_free (pspec->blurb); 143 144 g_type_free_instance ((GTypeInstance*) pspec); 145} 146 147GParamSpec* 148g_param_spec_ref (GParamSpec *pspec) 149{ 150 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL); 151 g_return_val_if_fail (pspec->ref_count > 0, NULL); 152 153 pspec->ref_count += 1; 154 155 return pspec; 156} 157 158void 159g_param_spec_unref (GParamSpec *pspec) 160{ 161 g_return_if_fail (G_IS_PARAM_SPEC (pspec)); 162 g_return_if_fail (pspec->ref_count > 0); 163 164 /* sync with _sink */ 165 pspec->ref_count -= 1; 166 if (pspec->ref_count == 0) 167 G_PARAM_SPEC_GET_CLASS (pspec)->finalize (pspec); 168} 169 170void 171g_param_spec_sink (GParamSpec *pspec) 172{ 173 g_return_if_fail (G_IS_PARAM_SPEC (pspec)); 174 g_return_if_fail (pspec->ref_count > 0); 175 176 if (g_datalist_id_remove_no_notify (&pspec->qdata, quark_floating)) 177 { 178 /* sync with _unref */ 179 if (pspec->ref_count > 1) 180 pspec->ref_count -= 1; 181 else 182 g_param_spec_unref (pspec); 183 } 184} 185 186gpointer 187g_param_spec_internal (GType param_type, 188 const gchar *name, 189 const gchar *nick, 190 const gchar *blurb, 191 GParamFlags flags) 192{ 193 GParamSpec *pspec; 194 195 g_return_val_if_fail (G_TYPE_IS_PARAM (param_type) && param_type != G_TYPE_PARAM, NULL); 196 g_return_val_if_fail (name != NULL, NULL); 197 198 pspec = (gpointer) g_type_create_instance (param_type); 199 pspec->name = g_strdup (name); 200 g_strcanon (pspec->name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-'); 201 pspec->nick = g_strdup (nick ? nick : pspec->name); 202 pspec->blurb = g_strdup (blurb); 203 pspec->flags = (flags & G_PARAM_USER_MASK) | (flags & G_PARAM_MASK); 204 205 return pspec; 206} 207 208gpointer 209g_param_spec_get_qdata (GParamSpec *pspec, 210 GQuark quark) 211{ 212 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL); 213 214 return quark ? g_datalist_id_get_data (&pspec->qdata, quark) : NULL; 215} 216 217void 218g_param_spec_set_qdata (GParamSpec *pspec, 219 GQuark quark, 220 gpointer data) 221{ 222 g_return_if_fail (G_IS_PARAM_SPEC (pspec)); 223 g_return_if_fail (quark > 0); 224 225 g_datalist_id_set_data (&pspec->qdata, quark, data); 226} 227 228void 229g_param_spec_set_qdata_full (GParamSpec *pspec, 230 GQuark quark, 231 gpointer data, 232 GDestroyNotify destroy) 233{ 234 g_return_if_fail (G_IS_PARAM_SPEC (pspec)); 235 g_return_if_fail (quark > 0); 236 237 g_datalist_id_set_data_full (&pspec->qdata, quark, data, data ? destroy : (GDestroyNotify) NULL); 238} 239 240gpointer 241g_param_spec_steal_qdata (GParamSpec *pspec, 242 GQuark quark) 243{ 244 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL); 245 g_return_val_if_fail (quark > 0, NULL); 246 247 return g_datalist_id_remove_no_notify (&pspec->qdata, quark); 248} 249 250void 251g_param_value_set_default (GParamSpec *pspec, 252 GValue *value) 253{ 254 g_return_if_fail (G_IS_PARAM_SPEC (pspec)); 255 g_return_if_fail (G_IS_VALUE (value)); 256 g_return_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value)); 257 258 g_value_reset (value); 259 G_PARAM_SPEC_GET_CLASS (pspec)->value_set_default (pspec, value); 260} 261 262gboolean 263g_param_value_defaults (GParamSpec *pspec, 264 GValue *value) 265{ 266 GValue dflt_value = { 0, }; 267 gboolean defaults; 268 269 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE); 270 g_return_val_if_fail (G_IS_VALUE (value), FALSE); 271 g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value), FALSE); 272 273 g_value_init (&dflt_value, G_PARAM_SPEC_VALUE_TYPE (pspec)); 274 G_PARAM_SPEC_GET_CLASS (pspec)->value_set_default (pspec, &dflt_value); 275 defaults = G_PARAM_SPEC_GET_CLASS (pspec)->values_cmp (pspec, value, &dflt_value) == 0; 276 g_value_unset (&dflt_value); 277 278 return defaults; 279} 280 281gboolean 282g_param_value_validate (GParamSpec *pspec, 283 GValue *value) 284{ 285 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE); 286 g_return_val_if_fail (G_IS_VALUE (value), FALSE); 287 g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value), FALSE); 288 289 if (G_PARAM_SPEC_GET_CLASS (pspec)->value_validate) 290 { 291 GValue oval = *value; 292 293 if (G_PARAM_SPEC_GET_CLASS (pspec)->value_validate (pspec, value) || 294 memcmp (&oval.data, &value->data, sizeof (oval.data))) 295 return TRUE; 296 } 297 298 return FALSE; 299} 300 301gint 302g_param_values_cmp (GParamSpec *pspec, 303 const GValue *value1, 304 const GValue *value2) 305{ 306 gint cmp; 307 308 /* param_values_cmp() effectively does: value1 - value2 309 * so the return values are: 310 * -1) value1 < value2 311 * 0) value1 == value2 312 * 1) value1 > value2 313 */ 314 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), 0); 315 g_return_val_if_fail (G_IS_VALUE (value1), 0); 316 g_return_val_if_fail (G_IS_VALUE (value2), 0); 317 g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value1), 0); 318 g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value2), 0); 319 320 cmp = G_PARAM_SPEC_GET_CLASS (pspec)->values_cmp (pspec, value1, value2); 321 322 return CLAMP (cmp, -1, 1); 323} 324 325static void 326value_param_init (GValue *value) 327{ 328 value->data[0].v_pointer = NULL; 329} 330 331static void 332value_param_free_value (GValue *value) 333{ 334 if (value->data[0].v_pointer) 335 g_param_spec_unref (value->data[0].v_pointer); 336} 337 338static void 339value_param_copy_value (const GValue *src_value, 340 GValue *dest_value) 341{ 342 dest_value->data[0].v_pointer = (src_value->data[0].v_pointer 343 ? g_param_spec_ref (src_value->data[0].v_pointer) 344 : NULL); 345} 346 347static gpointer 348value_param_peek_pointer (const GValue *value) 349{ 350 return value->data[0].v_pointer; 351} 352 353static gchar* 354value_param_collect_value (GValue *value, 355 guint nth_value, 356 GType *collect_type, 357 GTypeCValue *collect_value) 358{ 359 if (collect_value->v_pointer) 360 { 361 GParamSpec *param = collect_value->v_pointer; 362 363 if (param->g_type_instance.g_class == NULL) 364 return g_strconcat ("invalid unclassed param spec pointer for value type `", 365 G_VALUE_TYPE_NAME (value), 366 "'", 367 NULL); 368 else if (!g_type_is_a (G_PARAM_SPEC_TYPE (param), G_VALUE_TYPE (value))) 369 return g_strconcat ("invalid param spec type `", 370 G_PARAM_SPEC_TYPE_NAME (param), 371 "' for value type `", 372 G_VALUE_TYPE_NAME (value), 373 "'", 374 NULL); 375 value->data[0].v_pointer = g_param_spec_ref (param); 376 } 377 else 378 value->data[0].v_pointer = NULL; 379 380 *collect_type = 0; 381 return NULL; 382} 383 384static gchar* 385value_param_lcopy_value (const GValue *value, 386 guint nth_value, 387 GType *collect_type, 388 GTypeCValue *collect_value) 389{ 390 GParamSpec **param_p = collect_value->v_pointer; 391 392 if (!param_p) 393 return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); 394 395 *param_p = value->data[0].v_pointer ? g_param_spec_ref (value->data[0].v_pointer) : NULL; 396 397 *collect_type = 0; 398 return NULL; 399} 400 401 402/* --- param spec pool --- */ 403struct _GParamSpecPool 404{ 405 gboolean type_prefixing; 406 GHashTable *hash_table; 407}; 408 409static guint 410param_spec_pool_hash (gconstpointer key_spec) 411{ 412 const GParamSpec *key = key_spec; 413 const gchar *p; 414 guint h = key->owner_type; 415 416 for (p = key->name; *p; p++) 417 h = (h << 5) - h + *p; 418 419 return h; 420} 421 422static gboolean 423param_spec_pool_equals (gconstpointer key_spec_1, 424 gconstpointer key_spec_2) 425{ 426 const GParamSpec *key1 = key_spec_1; 427 const GParamSpec *key2 = key_spec_2; 428 429 return (key1->owner_type == key2->owner_type && 430 strcmp (key1->name, key2->name) == 0); 431} 432 433GParamSpecPool* 434g_param_spec_pool_new (gboolean type_prefixing) 435{ 436 GParamSpecPool *pool = g_new (GParamSpecPool, 1); 437 438 pool->type_prefixing = type_prefixing != FALSE; 439 pool->hash_table = g_hash_table_new (param_spec_pool_hash, param_spec_pool_equals); 440 441 return pool; 442} 443 444void 445g_param_spec_pool_insert (GParamSpecPool *pool, 446 GParamSpec *pspec, 447 GType owner_type) 448{ 449 gchar *p; 450 451 g_return_if_fail (pool != NULL); 452 g_return_if_fail (pspec); 453 g_return_if_fail (owner_type > 0); 454 g_return_if_fail (pspec->owner_type == 0); 455 456 for (p = pspec->name; *p; p++) 457 { 458 if (!strchr (G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-_", *p)) 459 { 460 g_warning (G_STRLOC ": pspec name \"%s\" contains invalid characters", pspec->name); 461 return; 462 } 463 } 464 465 pspec->owner_type = owner_type; 466 g_param_spec_ref (pspec); 467 g_hash_table_insert (pool->hash_table, pspec, pspec); 468} 469 470void 471g_param_spec_pool_remove (GParamSpecPool *pool, 472 GParamSpec *pspec) 473{ 474 g_return_if_fail (pool != NULL); 475 g_return_if_fail (pspec); 476 477 if (g_hash_table_remove (pool->hash_table, pspec)) 478 g_param_spec_unref (pspec); 479 else 480 g_warning (G_STRLOC ": attempt to remove unknown pspec `%s' from pool", pspec->name); 481} 482 483static inline GParamSpec* 484param_spec_ht_lookup (GHashTable *hash_table, 485 const gchar *param_name, 486 GType owner_type, 487 gboolean walk_ancestors) 488{ 489 GParamSpec key, *pspec; 490 491 key.owner_type = owner_type; 492 key.name = (gchar*) param_name; 493 if (walk_ancestors) 494 do 495 { 496 pspec = g_hash_table_lookup (hash_table, &key); 497 if (pspec) 498 return pspec; 499 key.owner_type = g_type_parent (key.owner_type); 500 } 501 while (key.owner_type); 502 else 503 pspec = g_hash_table_lookup (hash_table, &key); 504 505 if (!pspec) 506 { 507 /* sigh, try canonicalization */ 508 key.name = g_strdup (param_name); 509 key.owner_type = owner_type; 510 511 g_strcanon (key.name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-'); 512 if (walk_ancestors) 513 do 514 { 515 pspec = g_hash_table_lookup (hash_table, &key); 516 if (pspec) 517 { 518 g_free (key.name); 519 return pspec; 520 } 521 key.owner_type = g_type_parent (key.owner_type); 522 } 523 while (key.owner_type); 524 else 525 pspec = g_hash_table_lookup (hash_table, &key); 526 g_free (key.name); 527 } 528 529 return pspec; 530} 531 532GParamSpec* 533g_param_spec_pool_lookup (GParamSpecPool *pool, 534 const gchar *param_name, 535 GType owner_type, 536 gboolean walk_ancestors, 537 const gchar **trailer_p) 538{ 539 GParamSpec *pspec; 540 gchar *delim; 541 542 g_return_val_if_fail (pool != NULL, NULL); 543 g_return_val_if_fail (param_name, NULL); 544 545 delim = strchr (param_name, ':'); 546 547 /* try quick and away, i.e. no prefix, no trailer */ 548 if (!delim) 549 { 550 if (trailer_p) 551 *trailer_p = NULL; 552 return param_spec_ht_lookup (pool->hash_table, param_name, owner_type, walk_ancestors); 553 } 554 555 /* strip type prefix */ 556 if (pool->type_prefixing && delim[1] == ':') 557 { 558 guint l = delim - param_name; 559 gchar stack_buffer[32], *buffer = l < 32 ? stack_buffer : g_new (gchar, l + 1); 560 GType type; 561 562 strncpy (buffer, param_name, delim - param_name); 563 buffer[l] = 0; 564 type = g_type_from_name (buffer); 565 if (l >= 32) 566 g_free (buffer); 567 if (type) /* type==0 isn't a valid type pefix */ 568 { 569 /* sanity check, these cases don't make a whole lot of sense */ 570 if ((!walk_ancestors && type != owner_type) || !g_type_is_a (owner_type, type)) 571 { 572 if (trailer_p) 573 *trailer_p = NULL; 574 return NULL; 575 } 576 owner_type = type; 577 param_name += l + 2; 578 delim = strchr (param_name, ':'); 579 if (!delim) /* good, can still forget about trailer */ 580 { 581 if (trailer_p) 582 *trailer_p = NULL; 583 return param_spec_ht_lookup (pool->hash_table, param_name, owner_type, walk_ancestors); 584 } 585 } 586 } 587 588 /* ok, no prefix, handle trailer */ 589 if (delim[1] == ':') 590 { 591 guint l = delim - param_name; 592 gchar stack_buffer[32], *buffer = l < 32 ? stack_buffer : g_new (gchar, l + 1); 593 594 strncpy (buffer, param_name, delim - param_name); 595 buffer[l] = 0; 596 pspec = param_spec_ht_lookup (pool->hash_table, buffer, owner_type, walk_ancestors); 597 if (l >= 32) 598 g_free (buffer); 599 if (trailer_p) 600 *trailer_p = pspec ? delim + 2 : NULL; 601 return pspec; 602 } 603 604 /* malformed param_name */ 605 if (trailer_p) 606 *trailer_p = NULL; 607 return NULL; 608} 609 610 611/* --- auxillary functions --- */ 612typedef struct 613{ 614 /* class portion */ 615 GType value_type; 616 void (*finalize) (GParamSpec *pspec); 617 void (*value_set_default) (GParamSpec *pspec, 618 GValue *value); 619 gboolean (*value_validate) (GParamSpec *pspec, 620 GValue *value); 621 gint (*values_cmp) (GParamSpec *pspec, 622 const GValue *value1, 623 const GValue *value2); 624} ParamSpecClassInfo; 625 626static void 627param_spec_generic_class_init (gpointer g_class, 628 gpointer class_data) 629{ 630 GParamSpecClass *class = g_class; 631 ParamSpecClassInfo *info = class_data; 632 633 class->value_type = info->value_type; 634 if (info->finalize) 635 class->finalize = info->finalize; /* optional */ 636 class->value_set_default = info->value_set_default; 637 if (info->value_validate) 638 class->value_validate = info->value_validate; /* optional */ 639 class->values_cmp = info->values_cmp; 640 g_free (class_data); 641} 642 643static void 644default_value_set_default (GParamSpec *pspec, 645 GValue *value) 646{ 647 /* value is already zero initialized */ 648} 649 650static gint 651default_values_cmp (GParamSpec *pspec, 652 const GValue *value1, 653 const GValue *value2) 654{ 655 return memcmp (&value1->data, &value2->data, sizeof (value1->data)); 656} 657 658GType 659g_param_type_register_static (const gchar *name, 660 const GParamSpecTypeInfo *pspec_info) 661{ 662 GTypeInfo info = { 663 sizeof (GParamSpecClass), /* class_size */ 664 NULL, /* base_init */ 665 NULL, /* base_destroy */ 666 param_spec_generic_class_init, /* class_init */ 667 NULL, /* class_destroy */ 668 NULL, /* class_data */ 669 0, /* instance_size */ 670 16, /* n_preallocs */ 671 NULL, /* instance_init */ 672 }; 673 ParamSpecClassInfo *cinfo; 674 675 g_return_val_if_fail (name != NULL, 0); 676 g_return_val_if_fail (pspec_info != NULL, 0); 677 g_return_val_if_fail (g_type_from_name (name) == 0, 0); 678 g_return_val_if_fail (pspec_info->instance_size >= sizeof (GParamSpec), 0); 679 g_return_val_if_fail (g_type_name (pspec_info->value_type) != NULL, 0); 680 /* default: g_return_val_if_fail (pspec_info->value_set_default != NULL, 0); */ 681 /* optional: g_return_val_if_fail (pspec_info->value_validate != NULL, 0); */ 682 /* default: g_return_val_if_fail (pspec_info->values_cmp != NULL, 0); */ 683 684 info.instance_size = pspec_info->instance_size; 685 info.n_preallocs = pspec_info->n_preallocs; 686 info.instance_init = (GInstanceInitFunc) pspec_info->instance_init; 687 cinfo = g_new (ParamSpecClassInfo, 1); 688 cinfo->value_type = pspec_info->value_type; 689 cinfo->finalize = pspec_info->finalize; 690 cinfo->value_set_default = pspec_info->value_set_default ? pspec_info->value_set_default : default_value_set_default; 691 cinfo->value_validate = pspec_info->value_validate; 692 cinfo->values_cmp = pspec_info->values_cmp ? pspec_info->values_cmp : default_values_cmp; 693 info.class_data = cinfo; 694 695 return g_type_register_static (G_TYPE_PARAM, name, &info, 0); 696} 697 698void 699g_value_set_param (GValue *value, 700 GParamSpec *param) 701{ 702 g_return_if_fail (G_IS_VALUE_PARAM (value)); 703 if (param) 704 g_return_if_fail (G_IS_PARAM_SPEC (param)); 705 706 if (value->data[0].v_pointer) 707 g_param_spec_unref (value->data[0].v_pointer); 708 value->data[0].v_pointer = param; 709 if (value->data[0].v_pointer) 710 g_param_spec_ref (value->data[0].v_pointer); 711} 712 713GParamSpec* 714g_value_get_param (const GValue *value) 715{ 716 g_return_val_if_fail (G_IS_VALUE_PARAM (value), NULL); 717 718 return value->data[0].v_pointer; 719} 720 721GParamSpec* 722g_value_dup_param (const GValue *value) 723{ 724 g_return_val_if_fail (G_IS_VALUE_PARAM (value), NULL); 725 726 return value->data[0].v_pointer ? g_param_spec_ref (value->data[0].v_pointer) : NULL; 727} 728