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