add reserved fundamental ids for gtk types (for transition time). added
authorTim Janik <timj@gtk.org>
Fri, 12 May 2000 15:22:31 +0000 (15:22 +0000)
committerTim Janik <timj@src.gnome.org>
Fri, 12 May 2000 15:22:31 +0000 (15:22 +0000)
Fri May  5 01:15:48 2000  Tim Janik  <timj@gtk.org>

* gtype.h: add reserved fundamental ids for gtk types (for transition
time). added G_TYPE_FUNDAMENTAL_MAX for gtk.

Mon Apr 17 20:45:50 2000  Tim Janik  <timj@gtk.org>

* glib-gobject.c (g_object_base_class_finalize): oops, don't unset
n_params prior to destructing them.

Tue Apr 11 04:28:10 2000  Tim Janik  <timj@gtk.org>

* fixed a couple of bugs in the initial parameter/object
implementations, after getting beast running on GObject and GValue.

Fri Apr  7 04:27:49 2000  Tim Janik  <timj@gtk.org>

* glib-gobject.[hc]: completed parameter set/get implementations,
along with asyncronous parameter changed notification queue.

Sun Apr  2 04:54:36 2000  Tim Janik  <timj@gtk.org>

* glib-gobject.[hc]: GObject implementation, that is facilities
for setting/getting quarked data and reference counting.

* glib-gparamspecs.[hc]: first actuall parameter implementations
for GLib, so far we have: char, uchar, bool, int, uint, long,
ulong, enum, flags, float, double, string and object. each of these
GParamSpecs is a new instantiatable type in its own respect,
so the .c file derives 13 new types from G_TYPE_PARAM and
defines over 50 (*2) conversion facilities.

* glib-gvaluecollector.h: generic varargs handling stubs for
GParamSpecs, private header file (does get installed for
inclusion into user code though).

* glib-gvalue.[hc]: GValue functionality implementation.

* glib-gparam.[hc]: basis GParamSpec implementation for
the virtual base type G_TYPE_PARAM.

        * glib-genums.[hc]: enum/flags type implementation, based on
bseenum.[hc].

* glib-extra.[hc]: GLib additions, including 1.3 compatibility
routines and various other functions, from string manipulation
over list manipulation up to a unix signal GSource.

* glib-gtype.[hc]: GLib Type System implementation, heavily
based on BSE's dynamic type system.

16 files changed:
gobject/ChangeLog [new file with mode: 0644]
gobject/Makefile.am [new file with mode: 0644]
gobject/genums.c [new file with mode: 0644]
gobject/genums.h [new file with mode: 0644]
gobject/gobject-query.c [new file with mode: 0644]
gobject/gobject.c [new file with mode: 0644]
gobject/gobject.h [new file with mode: 0644]
gobject/gparam.c [new file with mode: 0644]
gobject/gparam.h [new file with mode: 0644]
gobject/gparamspecs.c [new file with mode: 0644]
gobject/gparamspecs.h [new file with mode: 0644]
gobject/gtype.c [new file with mode: 0644]
gobject/gtype.h [new file with mode: 0644]
gobject/gvalue.c [new file with mode: 0644]
gobject/gvalue.h [new file with mode: 0644]
gobject/gvaluecollector.h [new file with mode: 0644]

diff --git a/gobject/ChangeLog b/gobject/ChangeLog
new file mode 100644 (file)
index 0000000..5f3717e
--- /dev/null
@@ -0,0 +1,50 @@
+Fri May  5 01:15:48 2000  Tim Janik  <timj@gtk.org>
+
+       * gtype.h: add reserved fundamental ids for gtk types (for transition
+       time). added G_TYPE_FUNDAMENTAL_MAX for gtk.
+
+Mon Apr 17 20:45:50 2000  Tim Janik  <timj@gtk.org>
+
+       * glib-gobject.c (g_object_base_class_finalize): oops, don't unset
+       n_params prior to destructing them.
+
+Tue Apr 11 04:28:10 2000  Tim Janik  <timj@gtk.org>
+
+       * fixed a couple of bugs in the initial parameter/object
+       implementations, after getting beast running on GObject and GValue.
+
+Fri Apr  7 04:27:49 2000  Tim Janik  <timj@gtk.org>
+
+       * glib-gobject.[hc]: completed parameter set/get implementations,
+       along with asyncronous parameter changed notification queue.
+
+Sun Apr  2 04:54:36 2000  Tim Janik  <timj@gtk.org>
+
+       * glib-gobject.[hc]: GObject implementation, that is facilities
+       for setting/getting quarked data and reference counting.
+
+       * glib-gparamspecs.[hc]: first actuall parameter implementations
+       for GLib, so far we have: char, uchar, bool, int, uint, long,
+       ulong, enum, flags, float, double, string and object. each of these
+       GParamSpecs is a new instantiatable type in its own respect,
+       so the .c file derives 13 new types from G_TYPE_PARAM and
+       defines over 50 (*2) conversion facilities.
+
+       * glib-gvaluecollector.h: generic varargs handling stubs for
+       GParamSpecs, private header file (does get installed for
+       inclusion into user code though).
+
+       * glib-gvalue.[hc]: GValue functionality implementation.
+
+       * glib-gparam.[hc]: basis GParamSpec implementation for
+       the virtual base type G_TYPE_PARAM.
+
+        * glib-genums.[hc]: enum/flags type implementation, based on
+       bseenum.[hc].
+
+       * glib-extra.[hc]: GLib additions, including 1.3 compatibility
+       routines and various other functions, from string manipulation
+       over list manipulation up to a unix signal GSource.
+
+       * glib-gtype.[hc]: GLib Type System implementation, heavily
+       based on BSE's dynamic type system.
diff --git a/gobject/Makefile.am b/gobject/Makefile.am
new file mode 100644 (file)
index 0000000..80ac2de
--- /dev/null
@@ -0,0 +1,83 @@
+# GObject - GLib Type, Object, Parameter and Signal Library
+# Copyright (C) 1997,98,99,2000 Tim Janik and Red Hat, Inc.
+#
+## Process this file with automake to produce Makefile.in
+
+SUBDIRS =
+
+INCLUDES = -I$(top_srcdir) @GLIB_DEBUG_FLAGS@
+
+# libraries to compile and install
+lib_LTLIBRARIES = libgobject.la
+
+# provide g_logv() domain
+DEFS += -DG_LOG_DOMAIN=g_log_domain_gobject
+
+# libtool stuff: set version and export symbols for resolving
+libgobjectincludedir = $(includedir)/gobject
+libgobject_la_LDFLAGS = @STRIP_BEGIN@ \
+       -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+       -release $(LT_RELEASE) \
+       -export-dynamic \
+@STRIP_END@
+libgobject_la_LIBADD = # $(libglib)
+
+#
+# setup source file variables
+#
+# GObject header files for public installation (non-generated)
+gobject_public_h_sources = @STRIP_BEGIN@ \
+       gvalue.h \
+       gparam.h \
+       gparamspecs.h \
+       genums.h \
+       gobject.h \
+       gtype.h \
+       gvaluecollector.h \
+@STRIP_END@
+# private GObject header files
+gobject_private_h_sources = @STRIP_BEGIN@ \
+@STRIP_END@
+
+# GObject C sources to build the library from
+gobject_c_sources = @STRIP_BEGIN@ \
+       gvalue.c \
+       gparam.c \
+       gparamspecs.c \
+       genums.c \
+       gobject.c \
+       gtype.c \
+@STRIP_END@
+
+# non-header sources (headers should be specified in the above variables)
+# that don't serve as direct make target sources, i.e. they don't have
+# their own .lo rules and don't get publically installed
+gobject_extra_sources = @STRIP_BEGIN@ \
+@STRIP_END@
+
+#
+# setup GObject sources and their dependancies
+#
+gobject_h_sources = $(gobject_private_h_sources) $(gobject_public_h_sources) # $(gobject_built_public_sources)
+libgobjectinclude_HEADERS = $(gobject_public_h_sources) # $(gobject_built_public_sources)
+libgobject_la_SOURCES = $(gobject_c_sources)
+MAINTAINERCLEANFILES += # $(gobject_built_public_sources) $(gobject_built_sources)
+EXTRA_HEADERS +=
+EXTRA_DIST += $(gobject_private_h_sources)
+EXTRA_DIST += $(gobject_extra_sources) # $(gobject_built_sources) $(gobject_built_public_sources)
+
+#
+# programs to compile and install
+#
+bin_PROGRAMS = gobject-query
+# source files
+gobject_query_SOURCES = gobject-query.c
+# link programs against libgobject
+progs_LDADD = ../libglib.la libgobject.la
+gobject_query_LDADD = $(progs_LDADD)
+
+#
+# auxillary files
+#
+EXTRA_DIST += \
+       TODO
diff --git a/gobject/genums.c b/gobject/genums.c
new file mode 100644 (file)
index 0000000..3fcadb5
--- /dev/null
@@ -0,0 +1,306 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 1998, 1999, 2000 Tim Janik and Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include       "genums.h"
+
+
+/* --- prototypes --- */
+extern void    g_enum_types_init               (void);
+static void    g_enum_class_init               (GEnumClass     *class,
+                                                gpointer        class_data);
+static void    g_flags_class_init              (GFlagsClass    *class,
+                                                gpointer        class_data);
+
+
+/* --- functions --- */
+void
+g_enum_types_init (void)       /* sync with glib-gtype.c */
+{
+  static gboolean initialized = FALSE;
+  static const GTypeFundamentalInfo finfo = {
+    G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_DERIVABLE,
+    0          /* n_collect_bytes */,
+    NULL       /* GTypeParamCollector */,
+  };
+  static GTypeInfo info = {
+    0  /* class_size */,
+    NULL       /* base_init */,
+    NULL       /* base_finalize */,
+    NULL       /* class_init */,
+    NULL       /* class_finalize */,
+    NULL       /* class_data */,
+  };
+  GType type;
+  
+  g_return_if_fail (initialized == FALSE);
+  initialized = TRUE;
+  
+  /* G_TYPE_ENUM
+   */
+  info.class_size = sizeof (GEnumClass);
+  type = g_type_register_fundamental (G_TYPE_ENUM, "GEnum", &finfo, &info);
+  g_assert (type == G_TYPE_ENUM);
+  
+  /* G_TYPE_FLAGS
+   */
+  info.class_size = sizeof (GFlagsClass);
+  type = g_type_register_fundamental (G_TYPE_FLAGS, "GFlags", &finfo, &info);
+  g_assert (type == G_TYPE_FLAGS);
+}
+
+GType
+g_enum_register_static (const gchar     *name,
+                       const GEnumValue *const_static_values)
+{
+  GTypeInfo enum_type_info = {
+    sizeof (GEnumClass),
+    NULL       /* base_init */,
+    NULL       /* base_finalize */,
+    (GClassInitFunc) g_enum_class_init,
+    NULL       /* class_finalize */,
+    NULL       /* class_data */,
+  };
+  GType type;
+  
+  g_return_val_if_fail (name != NULL, 0);
+  g_return_val_if_fail (const_static_values != NULL, 0);
+  
+  enum_type_info.class_data = const_static_values;
+  
+  type = g_type_register_static (G_TYPE_ENUM, name, &enum_type_info);
+  
+  return type;
+}
+
+GType
+g_flags_register_static (const gchar      *name,
+                        const GFlagsValue *const_static_values)
+{
+  GTypeInfo flags_type_info = {
+    sizeof (GFlagsClass),
+    NULL       /* base_init */,
+    NULL       /* base_finalize */,
+    (GClassInitFunc) g_flags_class_init,
+    NULL       /* class_finalize */,
+    NULL       /* class_data */,
+  };
+  GType type;
+  
+  g_return_val_if_fail (name != NULL, 0);
+  g_return_val_if_fail (const_static_values != NULL, 0);
+  
+  flags_type_info.class_data = const_static_values;
+  
+  type = g_type_register_static (G_TYPE_FLAGS, name, &flags_type_info);
+  
+  return type;
+}
+
+void
+g_enum_complete_type_info (GType            g_enum_type,
+                          GTypeInfo        *info,
+                          const GEnumValue *const_values)
+{
+  g_return_if_fail (G_TYPE_IS_ENUM (g_enum_type));
+  g_return_if_fail (info != NULL);
+  g_return_if_fail (const_values != NULL);
+  
+  info->class_size = sizeof (GEnumClass);
+  info->base_init = NULL;
+  info->base_finalize = NULL;
+  info->class_init = (GClassInitFunc) g_enum_class_init;
+  info->class_finalize = NULL;
+  info->class_data = const_values;
+}
+
+void
+g_flags_complete_type_info (GType             g_flags_type,
+                           GTypeInfo         *info,
+                           const GFlagsValue *const_values)
+{
+  g_return_if_fail (G_TYPE_IS_FLAGS (g_flags_type));
+  g_return_if_fail (info != NULL);
+  g_return_if_fail (const_values != NULL);
+  
+  info->class_size = sizeof (GFlagsClass);
+  info->base_init = NULL;
+  info->base_finalize = NULL;
+  info->class_init = (GClassInitFunc) g_flags_class_init;
+  info->class_finalize = NULL;
+  info->class_data = const_values;
+}
+
+static void
+g_enum_class_init (GEnumClass *class,
+                  gpointer    class_data)
+{
+  g_return_if_fail (G_IS_ENUM_CLASS (class));
+  
+  class->minimum = 0;
+  class->maximum = 0;
+  class->n_values = 0;
+  class->values = class_data;
+  
+  if (class->values)
+    {
+      GEnumValue *values;
+      
+      class->minimum = class->values->value;
+      class->maximum = class->values->value;
+      for (values = class->values; values->value_name; values++)
+       {
+         class->minimum = MIN (class->minimum, values->value);
+         class->maximum = MAX (class->maximum, values->value);
+         class->n_values++;
+       }
+    }
+}
+
+static void
+g_flags_class_init (GFlagsClass *class,
+                   gpointer     class_data)
+{
+  g_return_if_fail (G_IS_FLAGS_CLASS (class));
+  
+  class->mask = 0;
+  class->n_values = 0;
+  class->values = class_data;
+  
+  if (class->values)
+    {
+      GFlagsValue *values;
+      
+      for (values = class->values; values->value_name; values++)
+       {
+         class->mask |= values->value;
+         class->n_values++;
+       }
+    }
+}
+
+GEnumValue*
+g_enum_get_value_by_name (GEnumClass  *enum_class,
+                         const gchar *name)
+{
+  g_return_val_if_fail (G_IS_ENUM_CLASS (enum_class), NULL);
+  g_return_val_if_fail (name != NULL, NULL);
+  
+  if (enum_class->n_values)
+    {
+      GEnumValue *enum_value;
+      
+      for (enum_value = enum_class->values; enum_value->value_name; enum_value++)
+       if (strcmp (name, enum_value->value_name) == 0)
+         return enum_value;
+    }
+  
+  return NULL;
+}
+
+GFlagsValue*
+g_flags_get_value_by_name (GFlagsClass *flags_class,
+                          const gchar *name)
+{
+  g_return_val_if_fail (G_IS_FLAGS_CLASS (flags_class), NULL);
+  g_return_val_if_fail (name != NULL, NULL);
+  
+  if (flags_class->n_values)
+    {
+      GFlagsValue *flags_value;
+      
+      for (flags_value = flags_class->values; flags_value->value_name; flags_value++)
+       if (strcmp (name, flags_value->value_name) == 0)
+         return flags_value;
+    }
+  
+  return NULL;
+}
+
+GEnumValue*
+g_enum_get_value_by_nick (GEnumClass  *enum_class,
+                         const gchar *nick)
+{
+  g_return_val_if_fail (G_IS_ENUM_CLASS (enum_class), NULL);
+  g_return_val_if_fail (nick != NULL, NULL);
+  
+  if (enum_class->n_values)
+    {
+      GEnumValue *enum_value;
+      
+      for (enum_value = enum_class->values; enum_value->value_name; enum_value++)
+       if (enum_value->value_nick && strcmp (nick, enum_value->value_nick) == 0)
+         return enum_value;
+    }
+  
+  return NULL;
+}
+
+GFlagsValue*
+g_flags_get_value_by_nick (GFlagsClass *flags_class,
+                          const gchar *nick)
+{
+  g_return_val_if_fail (G_IS_FLAGS_CLASS (flags_class), NULL);
+  g_return_val_if_fail (nick != NULL, NULL);
+  
+  if (flags_class->n_values)
+    {
+      GFlagsValue *flags_value;
+      
+      for (flags_value = flags_class->values; flags_value->value_nick; flags_value++)
+       if (flags_value->value_nick && strcmp (nick, flags_value->value_nick) == 0)
+         return flags_value;
+    }
+  
+  return NULL;
+}
+
+GEnumValue*
+g_enum_get_value (GEnumClass *enum_class,
+                 gint        value)
+{
+  g_return_val_if_fail (G_IS_ENUM_CLASS (enum_class), NULL);
+  
+  if (enum_class->n_values)
+    {
+      GEnumValue *enum_value;
+      
+      for (enum_value = enum_class->values; enum_value->value_name; enum_value++)
+       if (enum_value->value == value)
+         return enum_value;
+    }
+  
+  return NULL;
+}
+
+GFlagsValue*
+g_flags_get_first_value (GFlagsClass *flags_class,
+                        guint        value)
+{
+  g_return_val_if_fail (G_IS_FLAGS_CLASS (flags_class), NULL);
+  
+  if (flags_class->n_values)
+    {
+      GFlagsValue *flags_value;
+      
+      for (flags_value = flags_class->values; flags_value->value_name; flags_value++)
+       if ((flags_value->value & value) > 0)
+         return flags_value;
+    }
+  
+  return NULL;
+}
diff --git a/gobject/genums.h b/gobject/genums.h
new file mode 100644 (file)
index 0000000..4e90c67
--- /dev/null
@@ -0,0 +1,118 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 1998, 1999, 2000 Tim Janik and Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __G_ENUMS_H__
+#define __G_ENUMS_H__
+
+#include       <gobject/gtype.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* --- type macros --- */
+#define G_TYPE_IS_ENUM(type)   (G_TYPE_FUNDAMENTAL (type) == G_TYPE_ENUM)
+#define G_ENUM_TYPE(class)     (G_TYPE_FROM_CLASS (class))
+#define G_ENUM_NAME(class)     (g_type_name (G_ENUM_TYPE (class)))
+#define G_ENUM_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_ENUM, GEnumClass))
+#define G_IS_ENUM_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_ENUM))
+#define G_TYPE_IS_FLAGS(type)  (G_TYPE_FUNDAMENTAL (type) == G_TYPE_FLAGS)
+#define G_FLAGS_TYPE(class)    (G_TYPE_FROM_CLASS (class))
+#define G_FLAGS_NAME(class)    (g_type_name (G_FLAGS_TYPE (class)))
+#define G_FLAGS_CLASS(class)   (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_FLAGS, GFlagsClass))
+#define G_IS_FLAGS_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_FLAGS))
+
+
+/* --- enum/flag values & classes --- */
+typedef struct _GEnumClass  GEnumClass;
+typedef struct _GFlagsClass GFlagsClass;
+typedef struct _GEnumValue  GEnumValue;
+typedef struct _GFlagsValue GFlagsValue;
+struct _GEnumClass
+{
+  GTypeClass  g_type_class;
+  
+  gint       minimum;
+  gint       maximum;
+  guint              n_values;
+  GEnumValue *values;
+};
+struct _GFlagsClass
+{
+  GTypeClass   g_type_class;
+  
+  guint               mask;
+  guint               n_values;
+  GFlagsValue *values;
+};
+struct _GEnumValue
+{
+  gint  value;
+  gchar *value_name;
+  gchar *value_nick;
+};
+struct _GFlagsValue
+{
+  guint         value;
+  gchar *value_name;
+  gchar *value_nick;
+};
+
+
+/* --- prototypes --- */
+GEnumValue*    g_enum_get_value                (GEnumClass     *enum_class,
+                                                gint            value);
+GEnumValue*    g_enum_get_value_by_name        (GEnumClass     *enum_class,
+                                                const gchar    *name);
+GEnumValue*    g_enum_get_value_by_nick        (GEnumClass     *enum_class,
+                                                const gchar    *nick);
+GFlagsValue*   g_flags_get_first_value         (GFlagsClass    *flags_class,
+                                                guint           value);
+GFlagsValue*   g_flags_get_value_by_name       (GFlagsClass    *flags_class,
+                                                const gchar    *name);
+GFlagsValue*   g_flags_get_value_by_nick       (GFlagsClass    *flags_class,
+                                                const gchar    *nick);
+
+
+/* --- registration functions --- */
+/* const_static_values is a NULL terminated array of enum/flags
+ * values that is taken over!
+ */
+GType  g_enum_register_static     (const gchar       *name,
+                                   const GEnumValue  *const_static_values);
+GType  g_flags_register_static    (const gchar       *name,
+                                   const GFlagsValue *const_static_values);
+/* functions to complete the type information
+ * for enums/flags implemented by plugins
+ */
+void   g_enum_complete_type_info  (GType              g_enum_type,
+                                   GTypeInfo         *info,
+                                   const GEnumValue  *const_values);
+void   g_flags_complete_type_info (GType              g_flags_type,
+                                   GTypeInfo         *info,
+                                   const GFlagsValue *const_values);
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __G_ENUMS_H__ */
diff --git a/gobject/gobject-query.c b/gobject/gobject-query.c
new file mode 100644 (file)
index 0000000..6ee1b49
--- /dev/null
@@ -0,0 +1,219 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 1998, 1999, 2000 Tim Janik and Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include        <glib-object.h>
+
+#include       <stdio.h>
+#include       <stdlib.h>
+#include       <unistd.h>
+#include       <sys/stat.h>
+#include       <fcntl.h>
+
+static gchar *indent_inc = NULL;
+static guint spacing = 1;
+static FILE *f_out = NULL;
+static GType root = 0;
+static gboolean recursion = TRUE;
+
+#if 0
+#  define      O_SPACE "\\as"
+#  define      O_ESPACE " "
+#  define      O_BRANCH "\\aE"
+#  define      O_VLINE "\\al"
+#  define      O_LLEAF "\\aL"
+#  define      O_KEY_FILL "_"
+#else
+#  define      O_SPACE " "
+#  define      O_ESPACE ""
+#  define      O_BRANCH "+"
+#  define      O_VLINE "|"
+#  define      O_LLEAF "`"
+#  define      O_KEY_FILL "_"
+#endif
+
+static void
+show_nodes (GType        type,
+           GType        sibling,
+           const gchar *indent)
+{
+  GType   *children;
+  guint i;
+  
+  if (!type)
+    return;
+  
+  children = g_type_children (type, NULL);
+  
+  if (type != root)
+    for (i = 0; i < spacing; i++)
+      fprintf (f_out, "%s%s\n", indent, O_VLINE);
+  
+  fprintf (f_out, "%s%s%s%s",
+          indent,
+          sibling ? O_BRANCH : (type != root ? O_LLEAF : O_SPACE),
+          O_ESPACE,
+          g_type_name (type));
+  
+  for (i = strlen (g_type_name (type)); i <= strlen (indent_inc); i++)
+    fputs (O_KEY_FILL, f_out);
+  
+  fputc ('\n', f_out);
+  
+  if (children && recursion)
+    {
+      gchar *new_indent;
+      GType   *child;
+      
+      if (sibling)
+       new_indent = g_strconcat (indent, O_VLINE, indent_inc, NULL);
+      else
+       new_indent = g_strconcat (indent, O_SPACE, indent_inc, NULL);
+      
+      for (child = children; *child; child++)
+       show_nodes (child[0], child[1], new_indent);
+      
+      g_free (new_indent);
+    }
+  
+  g_free (children);
+}
+
+static gint
+help (gchar *arg)
+{
+  fprintf (stderr, "usage: query <qualifier> [-r <type>] [-{i|b} \"\"] [-s #] [-{h|x|y}]\n");
+  fprintf (stderr, "       -r       specifiy root type\n");
+  fprintf (stderr, "       -n       don't descend type tree\n");
+  fprintf (stderr, "       -h       guess what ;)\n");
+  fprintf (stderr, "       -b       specifiy indent string\n");
+  fprintf (stderr, "       -i       specifiy incremental indent string\n");
+  fprintf (stderr, "       -s       specifiy line spacing\n");
+  fprintf (stderr, "qualifiers:\n");
+  fprintf (stderr, "       froots   iterate over fundamental roots\n");
+  fprintf (stderr, "       tree     print BSE type tree\n");
+  
+  return arg != NULL;
+}
+
+int
+main (gint   argc,
+      gchar *argv[])
+{
+  gboolean gen_froots = 0;
+  gboolean gen_tree = 0;
+  guint i;
+  gchar *iindent = "";
+  
+  f_out = stdout;
+  
+  g_type_init ();
+  
+  root = G_TYPE_OBJECT;
+  
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp ("-s", argv[i]) == 0)
+       {
+         i++;
+         if (i < argc)
+           spacing = atoi (argv[i]);
+       }
+      else if (strcmp ("-i", argv[i]) == 0)
+       {
+         i++;
+         if (i < argc)
+           {
+             char *p;
+             guint n;
+             
+             p = argv[i];
+             while (*p)
+               p++;
+             n = p - argv[i];
+             indent_inc = g_new (gchar, n * strlen (O_SPACE) + 1);
+             *indent_inc = 0;
+             while (n)
+               {
+                 n--;
+                 strcpy (indent_inc, O_SPACE);
+               }
+           }
+       }
+      else if (strcmp ("-b", argv[i]) == 0)
+       {
+         i++;
+         if (i < argc)
+           iindent = argv[i];
+       }
+      else if (strcmp ("-r", argv[i]) == 0)
+       {
+         i++;
+         if (i < argc)
+           root = g_type_from_name (argv[i]);
+       }
+      else if (strcmp ("-n", argv[i]) == 0)
+       {
+         recursion = FALSE;
+       }
+      else if (strcmp ("froots", argv[i]) == 0)
+       {
+         gen_froots = 1;
+       }
+      else if (strcmp ("tree", argv[i]) == 0)
+       {
+         gen_tree = 1;
+       }
+      else if (strcmp ("-h", argv[i]) == 0)
+       {
+         return help (NULL);
+       }
+      else if (strcmp ("--help", argv[i]) == 0)
+       {
+         return help (NULL);
+       }
+      else
+       return help (argv[i]);
+    }
+  if (!gen_froots && !gen_tree)
+    return help (argv[i-1]);
+  
+  if (!indent_inc)
+    {
+      indent_inc = g_new (gchar, strlen (O_SPACE) + 1);
+      *indent_inc = 0;
+      strcpy (indent_inc, O_SPACE);
+      strcpy (indent_inc, O_SPACE);
+      strcpy (indent_inc, O_SPACE);
+    }
+  
+  if (gen_tree)
+    show_nodes (root, 0, iindent);
+  if (gen_froots)
+    {
+      root = ~0;
+      for (i = 0; i < 256; i++)
+       {
+         gchar *name = g_type_name (i);
+         
+         if (name)
+           show_nodes (i, 0, iindent);
+       }
+    }
+  
+  return 0;
+}
diff --git a/gobject/gobject.c b/gobject/gobject.c
new file mode 100644 (file)
index 0000000..8d54b34
--- /dev/null
@@ -0,0 +1,751 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 1998, 1999, 2000 Tim Janik and Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include       "gobject.h"
+
+
+#include       "gvalue.h"
+#include       "gvaluecollector.h"
+
+
+#define        DEBUG_OBJECTS
+
+
+/* --- macros --- */
+#define PARAM_SPEC_PARAM_ID(pspec)     (GPOINTER_TO_UINT (g_param_spec_get_qdata ((pspec), quark_param_id)))
+
+
+/* --- prototypes --- */
+extern void    g_object_type_init                      (void);
+static void    g_object_base_class_init                (GObjectClass   *class);
+static void    g_object_base_class_finalize            (GObjectClass   *class);
+static void    g_object_do_class_init                  (GObjectClass   *class);
+static void    g_object_do_init                        (GObject        *object);
+static void    g_object_do_queue_param_changed         (GObject        *object,
+                                                        GParamSpec     *pspec);
+static void    g_object_do_dispatch_param_changed      (GObject        *object,
+                                                        GParamSpec     *pspec);
+static void    g_object_last_unref                     (GObject        *object);
+static void    g_object_do_shutdown                    (GObject        *object);
+static void    g_object_do_finalize                    (GObject        *object);
+
+
+/* --- variables --- */
+static GQuark           quark_param_id = 0;
+static GQuark           quark_param_changed_queue = 0;
+static GHashTable      *param_spec_hash_table = NULL;
+
+
+/* --- functions --- */
+#ifdef DEBUG_OBJECTS
+static guint             debug_objects_count = 0;
+static GHashTable       *debug_objects_ht = NULL;
+static void
+debug_objects_foreach (gpointer key,
+                      gpointer value,
+                      gpointer user_data)
+{
+  GObject *object = value;
+
+  g_message ("[%p] stale %s\tref_count=%u",
+            object,
+            G_OBJECT_TYPE_NAME (object),
+            object->ref_count);
+}
+static void
+debug_objects_atexit (void)
+{
+  if (debug_objects_ht)
+    {
+      g_message ("stale GObjects: %u", debug_objects_count);
+      g_hash_table_foreach (debug_objects_ht, debug_objects_foreach, NULL);
+    }
+}
+#endif DEBUG_OBJECTS
+
+void
+g_object_type_init (void)      /* sync with glib-gtype.c */
+{
+  static gboolean initialized = FALSE;
+  static const GTypeFundamentalInfo finfo = {
+    G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE,
+    0       /* n_collect_bytes */,
+    NULL    /* GTypeParamCollector */,
+  };
+  static GTypeInfo info = {
+    sizeof (GObjectClass),
+    (GBaseInitFunc) g_object_base_class_init,
+    (GBaseFinalizeFunc) g_object_base_class_finalize,
+    (GClassInitFunc) g_object_do_class_init,
+    NULL       /* class_destroy */,
+    NULL       /* class_data */,
+    sizeof (GObject),
+    0          /* n_preallocs */,
+    (GInstanceInitFunc) g_object_do_init,
+  };
+  GType type;
+  
+  g_return_if_fail (initialized == FALSE);
+  initialized = TRUE;
+  
+  /* G_TYPE_OBJECT
+   */
+  type = g_type_register_fundamental (G_TYPE_OBJECT, "GObject", &finfo, &info);
+  g_assert (type == G_TYPE_OBJECT);
+
+#ifdef  DEBUG_OBJECTS
+  g_atexit (debug_objects_atexit);
+#endif  DEBUG_OBJECTS
+}
+
+static void
+g_object_base_class_init (GObjectClass *class)
+{
+  /* reset instance specific fields and methods that don't get inherited */
+  class->n_param_specs = 0;
+  class->param_specs = NULL;
+  class->get_param = NULL;
+  class->set_param = NULL;
+}
+
+static void
+g_object_base_class_finalize (GObjectClass *class)
+{
+  guint i;
+
+  g_message ("finallizing base class of %s", G_OBJECT_CLASS_NAME (class));
+  
+  for (i = 0; i < class->n_param_specs; i++)
+    {
+      GParamSpec *pspec = class->param_specs[i];
+      
+      g_param_spec_hash_table_remove (param_spec_hash_table, pspec);
+      g_param_spec_set_qdata (pspec, quark_param_id, NULL);
+      g_param_spec_unref (pspec);
+    }
+  class->n_param_specs = 0;
+  g_free (class->param_specs);
+  class->param_specs = NULL;
+}
+
+static void
+g_object_do_class_init (GObjectClass *class)
+{
+  quark_param_id = g_quark_from_static_string ("glib-object-param-id");
+  quark_param_changed_queue = g_quark_from_static_string ("glib-object-param-changed-queue");
+  param_spec_hash_table = g_param_spec_hash_table_new ();
+  
+  class->queue_param_changed = g_object_do_queue_param_changed;
+  class->dispatch_param_changed = g_object_do_dispatch_param_changed;
+  class->shutdown = g_object_do_shutdown;
+  class->finalize = g_object_do_finalize;
+}
+
+void
+g_object_class_install_param (GObjectClass *class,
+                             guint         param_id,
+                             GParamSpec   *pspec /* 1 ref_count taken over */)
+{
+  guint i;
+
+  g_return_if_fail (G_IS_OBJECT_CLASS (class));
+  g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+  if (pspec->flags & G_PARAM_WRITABLE)
+    g_return_if_fail (class->set_param != NULL);
+  if (pspec->flags & G_PARAM_READABLE)
+    g_return_if_fail (class->get_param != NULL);
+  g_return_if_fail (param_id > 0);
+  g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */
+
+  /* expensive paranoia checks ;( */
+  for (i = 0; i < class->n_param_specs; i++)
+    if (PARAM_SPEC_PARAM_ID (class->param_specs[i]) == param_id)
+      {
+       g_warning (G_STRLOC ": class `%s' already contains a parameter `%s' with id %u, "
+                  "cannot install parameter `%s'",
+                  G_OBJECT_CLASS_NAME (class),
+                  class->param_specs[i]->name,
+                  param_id,
+                  pspec->name);
+       return;
+      }
+  if (g_object_class_find_param_spec (class, pspec->name))
+    {
+      g_warning (G_STRLOC ": class `%s' already contains a parameter named `%s'",
+                G_OBJECT_CLASS_NAME (class),
+                pspec->name);
+      return;
+    }
+
+  g_param_spec_set_qdata (pspec, quark_param_id, GUINT_TO_POINTER (param_id));
+  g_param_spec_hash_table_insert (param_spec_hash_table, pspec, G_OBJECT_CLASS_TYPE (class));
+  i = class->n_param_specs++;
+  class->param_specs = g_renew (GParamSpec*, class->param_specs, class->n_param_specs);
+  class->param_specs[i] = pspec;
+}
+
+GParamSpec*
+g_object_class_find_param_spec (GObjectClass *class,
+                               const gchar  *param_name)
+{
+  g_return_val_if_fail (G_IS_OBJECT_CLASS (class), NULL);
+  g_return_val_if_fail (param_name != NULL, NULL);
+
+  return g_param_spec_hash_table_lookup (param_spec_hash_table,
+                                        param_name,
+                                        G_OBJECT_CLASS_TYPE (class),
+                                        TRUE, NULL);
+}
+
+static void
+g_object_do_init (GObject *object)
+{
+  object->ref_count = 1;
+  object->qdata = NULL;
+
+#ifdef DEBUG_OBJECTS
+  if (!debug_objects_ht)
+    debug_objects_ht = g_hash_table_new (g_direct_hash, NULL);
+  debug_objects_count++;
+  g_hash_table_insert (debug_objects_ht, object, object);
+#endif DEBUG_OBJECTS
+}
+
+static void
+g_object_last_unref (GObject *object)
+{
+  g_return_if_fail (object->ref_count > 0);
+
+  if (object->ref_count == 1)  /* may have been re-referenced meanwhile */
+    G_OBJECT_GET_CLASS (object)->shutdown (object);
+
+  object->ref_count -= 1;
+
+  if (object->ref_count == 0)  /* may have been re-referenced meanwhile */
+    G_OBJECT_GET_CLASS (object)->finalize (object);
+}
+
+static void
+g_object_do_shutdown (GObject *object)
+{
+  /* this function needs to be always present for unconditional
+   * chaining, we also might add some code here later.
+   * beware though, subclasses may invoke shutdown() arbitrarily.
+   */
+}
+
+static void
+g_object_do_finalize (GObject *object)
+{
+  g_datalist_clear (&object->qdata);
+  
+#ifdef DEBUG_OBJECTS
+  g_assert (g_hash_table_lookup (debug_objects_ht, object) == object);
+  
+  g_hash_table_remove (debug_objects_ht, object);
+  debug_objects_count--;
+#endif DEBUG_OBJECTS
+  
+  g_type_free_instance ((GTypeInstance*) object);
+}
+
+gpointer
+g_object_new (GType        object_type,
+             const gchar *first_param_name,
+             ...)
+{
+  GObject *object;
+  va_list var_args;
+
+  g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL);
+
+  va_start (var_args, first_param_name);
+  object = g_object_new_valist (object_type, first_param_name, var_args);
+  va_end (var_args);
+
+  return object;
+}
+
+gpointer
+g_object_new_valist (GType        object_type,
+                    const gchar *first_param_name,
+                    va_list      var_args)
+{
+  GObject *object;
+
+  g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL);
+
+  object = (GObject*) g_type_create_instance (object_type);
+  if (first_param_name)
+    g_object_set_valist (object, first_param_name, var_args);
+  
+  return object;
+}
+
+static void
+g_object_do_dispatch_param_changed (GObject    *object,
+                                   GParamSpec *pspec)
+{
+  g_message ("NOTIFICATION: parameter `%s' changed on object `%s'",
+            pspec->name,
+            G_OBJECT_TYPE_NAME (object));
+}
+
+static gboolean
+notify_param_changed_handler (gpointer data)
+{
+  GObject *object;
+  GObjectClass *class;
+  GSList *slist;
+
+  /* FIXME: need GDK_THREADS lock */
+
+  object = G_OBJECT (data);
+  class = G_OBJECT_GET_CLASS (object);
+  slist = g_datalist_id_get_data (&object->qdata, quark_param_changed_queue);
+
+  /* a reference count is still being held */
+
+  for (; slist; slist = slist->next)
+    if (slist->data)
+      {
+       GParamSpec *pspec = slist->data;
+       
+       slist->data = NULL;
+       class->dispatch_param_changed (object, pspec);
+      }
+  
+  g_datalist_id_set_data (&object->qdata, quark_param_changed_queue, NULL);
+  
+  return FALSE;
+}
+
+static void
+g_object_do_queue_param_changed (GObject    *object,
+                                GParamSpec *pspec)
+{
+  GSList *slist, *last = NULL;
+  
+  /* if this is a recursive call on this object (i.e. pspecs are queued
+   * for notification, while param_changed notification is currently in
+   * progress), we simply add them to the queue that is currently being
+   * dispatched. otherwise, we later dispatch parameter changed notification
+   * asyncronously from an idle handler untill the queue is completely empty.
+   */
+  
+  slist = g_datalist_id_get_data (&object->qdata, quark_param_changed_queue);
+  for (; slist; last = slist, slist = last->next)
+    if (slist->data == pspec)
+      return;
+  
+  if (!last)
+    {
+      g_object_ref (object);
+      g_idle_add_full (G_NOTIFY_PRIORITY,
+                      notify_param_changed_handler,
+                      object,
+                      (GDestroyNotify) g_object_unref);
+      g_object_set_qdata_full (object,
+                              quark_param_changed_queue,
+                              g_slist_prepend (NULL, pspec),
+                              (GDestroyNotify) g_slist_free);
+    }
+  else
+    last->next = g_slist_prepend (NULL, pspec);
+}
+
+static inline void
+object_get_param (GObject     *object,
+                 GValue      *value,
+                 GParamSpec  *pspec,
+                 const gchar *trailer)
+{
+  GObjectClass *class;
+
+  g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (object), pspec->owner_type));  /* paranoid */
+
+  class = g_type_class_peek (pspec->owner_type);
+
+  class->get_param (object, PARAM_SPEC_PARAM_ID (pspec), value, pspec, trailer);
+}
+
+static inline void
+object_set_param (GObject     *object,
+                 GValue      *value,
+                 GParamSpec  *pspec,
+                 const gchar *trailer)
+{
+  GObjectClass *class;
+
+  g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (object), pspec->owner_type));  /* paranoid */
+
+  class = g_type_class_peek (pspec->owner_type);
+
+  class->set_param (object, PARAM_SPEC_PARAM_ID (pspec), value, pspec, trailer);
+
+  class->queue_param_changed (object, pspec);
+}
+
+void
+g_object_set_valist (GObject     *object,
+                    const gchar *first_param_name,
+                    va_list      var_args)
+{
+  const gchar *name;
+
+  g_return_if_fail (G_IS_OBJECT (object));
+
+  g_object_ref (object);
+
+  name = first_param_name;
+
+  while (name)
+    {
+      const gchar *trailer = NULL;
+      GValue value = { 0, };
+      GParamSpec *pspec;
+      gchar *error = NULL;
+
+      pspec = g_param_spec_hash_table_lookup (param_spec_hash_table,
+                                             name,
+                                             G_OBJECT_TYPE (object),
+                                             TRUE,
+                                             &trailer);
+      if (!pspec)
+       {
+         g_warning ("%s: object class `%s' has no parameter named `%s'",
+                    G_STRLOC,
+                    G_OBJECT_TYPE_NAME (object),
+                    name);
+         break;
+       }
+      if (!(pspec->flags & G_PARAM_WRITABLE))
+       {
+         g_warning ("%s: parameter `%s' of object class `%s' is not writable",
+                    G_STRLOC,
+                    pspec->name,
+                    G_OBJECT_TYPE_NAME (object));
+         break;
+       }
+
+      g_value_init (&value, G_PARAM_SPEC_TYPE (pspec));
+
+      G_PARAM_COLLECT_VALUE (&value, pspec, var_args, &error);
+      if (error)
+       {
+         g_warning ("%s: %s", G_STRLOC, error);
+         g_free (error);
+         
+         /* we purposely leak the value here, it might not be
+          * in a sane state if an error condition occoured
+          */
+         break;
+       }
+
+      object_set_param (object, &value, pspec, trailer);
+      
+      g_value_unset (&value);
+
+      name = va_arg (var_args, gchar*);
+    }
+
+  g_object_unref (object);
+}
+
+void
+g_object_get_valist (GObject     *object,
+                    const gchar *first_param_name,
+                    va_list      var_args)
+{
+  const gchar *name;
+
+  g_return_if_fail (G_IS_OBJECT (object));
+
+  g_object_ref (object);
+
+  name = first_param_name;
+
+  while (name)
+    {
+      const gchar *trailer = NULL;
+      GValue value = { 0, };
+      GParamSpec *pspec;
+      gchar *error = NULL;
+
+      pspec = g_param_spec_hash_table_lookup (param_spec_hash_table,
+                                             name,
+                                             G_OBJECT_TYPE (object),
+                                             TRUE,
+                                             &trailer);
+      if (!pspec)
+       {
+         g_warning ("%s: object class `%s' has no parameter named `%s'",
+                    G_STRLOC,
+                    G_OBJECT_TYPE_NAME (object),
+                    name);
+         break;
+       }
+      if (!(pspec->flags & G_PARAM_READABLE))
+       {
+         g_warning ("%s: parameter `%s' of object class `%s' is not readable",
+                    G_STRLOC,
+                    pspec->name,
+                    G_OBJECT_TYPE_NAME (object));
+         break;
+       }
+
+      g_value_init (&value, G_PARAM_SPEC_TYPE (pspec));
+
+      object_get_param (object, &value, pspec, trailer);
+
+      G_PARAM_LCOPY_VALUE (&value, pspec, var_args, &error);
+      if (error)
+       {
+         g_warning ("%s: %s", G_STRLOC, error);
+         g_free (error);
+         
+         /* we purposely leak the value here, it might not be
+          * in a sane state if an error condition occoured
+          */
+         break;
+       }
+      
+      g_value_unset (&value);
+
+      name = va_arg (var_args, gchar*);
+    }
+
+  g_object_unref (object);
+}
+
+void
+g_object_set (GObject     *object,
+             const gchar *first_param_name,
+             ...)
+{
+  va_list var_args;
+
+  g_return_if_fail (G_IS_OBJECT (object));
+
+  va_start (var_args, first_param_name);
+  g_object_set_valist (object, first_param_name, var_args);
+  va_end (var_args);
+}
+
+void
+g_object_get (GObject     *object,
+             const gchar *first_param_name,
+             ...)
+{
+  va_list var_args;
+
+  g_return_if_fail (G_IS_OBJECT (object));
+
+  va_start (var_args, first_param_name);
+  g_object_get_valist (object, first_param_name, var_args);
+  va_end (var_args);
+}
+
+void
+g_object_set_param (GObject      *object,
+                   const gchar  *param_name,
+                   const GValue *value)
+{
+  GParamSpec *pspec;
+  const gchar *trailer;
+
+  g_return_if_fail (G_IS_OBJECT (object));
+  g_return_if_fail (param_name != NULL);
+  g_return_if_fail (G_IS_VALUE (value));
+
+  g_object_ref (object);
+
+  pspec = g_param_spec_hash_table_lookup (param_spec_hash_table,
+                                         param_name,
+                                         G_OBJECT_TYPE (object),
+                                         TRUE,
+                                         &trailer);
+  if (!pspec)
+    g_warning ("%s: object class `%s' has no parameter named `%s'",
+              G_STRLOC,
+              G_OBJECT_TYPE_NAME (object),
+              param_name);
+  else
+    {
+      GValue tmp_value = { 0, };
+
+      /* provide a copy to work from and convert if necessary */
+      g_value_init (&tmp_value, G_PARAM_SPEC_TYPE (pspec));
+
+      if (!g_value_convert (value, &tmp_value) ||
+         g_value_validate (&tmp_value, pspec))
+       g_warning ("%s: can't convert `%s' value to parameter `%s' of type `%s'",
+                  G_STRLOC,
+                  G_VALUE_TYPE_NAME (value),
+                  pspec->name,
+                  G_PARAM_SPEC_TYPE_NAME (pspec));
+      else
+       object_set_param (object, &tmp_value, pspec, trailer);
+      
+      g_value_unset (&tmp_value);
+    }
+  
+  g_object_unref (object);
+}
+
+void
+g_object_get_param (GObject     *object,
+                   const gchar *param_name,
+                   GValue      *value)
+{
+  GParamSpec *pspec;
+  const gchar *trailer;
+  
+  g_return_if_fail (G_IS_OBJECT (object));
+  g_return_if_fail (param_name != NULL);
+  g_return_if_fail (G_IS_VALUE (value));
+  
+  g_object_ref (object);
+  
+  pspec = g_param_spec_hash_table_lookup (param_spec_hash_table,
+                                         param_name,
+                                         G_OBJECT_TYPE (object),
+                                         TRUE,
+                                         &trailer);
+  if (!pspec)
+    g_warning ("%s: object class `%s' has no parameter named `%s'",
+              G_STRLOC,
+              G_OBJECT_TYPE_NAME (object),
+              param_name);
+  else
+    {
+      GValue tmp_value = { 0, };
+      
+      /* provide a copy to work from and later convert if necessary, so
+       * _get_param() implementations need *not* care about freeing values
+       * that might be already set in the parameter to get.
+       * (though, at this point, GValue should exclusively be modified
+       * through the accessor functions anyways)
+       */
+      g_value_init (&tmp_value, G_PARAM_SPEC_TYPE (pspec));
+      
+      if (!g_value_types_exchangable (G_VALUE_TYPE (value), G_PARAM_SPEC_TYPE (pspec)))
+       g_warning ("%s: can't retrive parameter `%s' of type `%s' as value of type `%s'",
+                  G_STRLOC,
+                  pspec->name,
+                  G_PARAM_SPEC_TYPE_NAME (pspec),
+                  G_VALUE_TYPE_NAME (value));
+      else
+       {
+         object_get_param (object, &tmp_value, pspec, trailer);
+         g_value_convert (&tmp_value, value);
+         /* g_value_validate (value, pspec); */
+       }
+      
+      g_value_unset (&tmp_value);
+    }
+  
+  g_object_unref (object);
+}
+
+void
+g_object_queue_param_changed (GObject     *object,
+                             const gchar *param_name)
+{
+  GParamSpec *pspec;
+  
+  g_return_if_fail (G_IS_OBJECT (object));
+  g_return_if_fail (param_name != NULL);
+
+  pspec = g_param_spec_hash_table_lookup (param_spec_hash_table,
+                                         param_name,
+                                         G_OBJECT_TYPE (object),
+                                         TRUE, NULL);
+  if (!pspec)
+    g_warning ("%s: object class `%s' has no parameter named `%s'",
+              G_STRLOC,
+              G_OBJECT_TYPE_NAME (object),
+              param_name);
+  else
+    G_OBJECT_GET_CLASS (object)->queue_param_changed (object, pspec);
+}
+
+GObject*
+g_object_ref (GObject *object)
+{
+  g_return_val_if_fail (G_IS_OBJECT (object), NULL);
+  g_return_val_if_fail (object->ref_count > 0, NULL);
+
+  object->ref_count += 1;
+
+  return object;
+}
+
+void
+g_object_unref (GObject *object)
+{
+  g_return_if_fail (G_IS_OBJECT (object));
+  g_return_if_fail (object->ref_count > 0);
+
+  if (object->ref_count > 1)
+    object->ref_count -= 1;
+  else
+    g_object_last_unref (object);
+}
+
+gpointer
+g_object_get_qdata (GObject *object,
+                   GQuark   quark)
+{
+  g_return_val_if_fail (G_IS_OBJECT (object), NULL);
+
+  return quark ? g_datalist_id_get_data (&object->qdata, quark) : NULL;
+}
+
+void
+g_object_set_qdata (GObject *object,
+                   GQuark   quark,
+                   gpointer data)
+{
+  g_return_if_fail (G_IS_OBJECT (object));
+  g_return_if_fail (quark > 0);
+  
+  g_datalist_id_set_data (&object->qdata, quark, data);
+}
+
+void
+g_object_set_qdata_full (GObject       *object,
+                        GQuark         quark,
+                        gpointer       data,
+                        GDestroyNotify destroy)
+{
+  g_return_if_fail (G_IS_OBJECT (object));
+  g_return_if_fail (quark > 0);
+  
+  g_datalist_id_set_data_full (&object->qdata, quark, data, data ? destroy : NULL);
+}
+
+gpointer
+g_object_steal_qdata (GObject *object,
+                     GQuark   quark)
+{
+  g_return_val_if_fail (G_IS_OBJECT (object), NULL);
+  g_return_val_if_fail (quark > 0, NULL);
+  
+  return g_datalist_id_remove_no_notify (&object->qdata, quark);
+}
diff --git a/gobject/gobject.h b/gobject/gobject.h
new file mode 100644 (file)
index 0000000..69c718d
--- /dev/null
@@ -0,0 +1,165 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 1998, 1999, 2000 Tim Janik and Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __G_GOBJECT_H__
+#define __G_GOBJECT_H__
+
+#include       <gobject/gtype.h>
+#include       <gobject/gparam.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* --- type macros --- */
+#define G_TYPE_IS_OBJECT(type)    (G_TYPE_FUNDAMENTAL (type) == G_TYPE_OBJECT)
+#define G_OBJECT(object)          (G_IS_OBJECT (object) ? ((GObject*) (object)) : \
+                                   G_TYPE_CHECK_INSTANCE_CAST ((object), G_TYPE_OBJECT, GObject))
+#define G_OBJECT_CLASS(class)     (G_IS_OBJECT_CLASS (class) ? ((GObjectClass*) (class)) : \
+                                   G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_OBJECT, GObjectClass))
+#define G_IS_OBJECT(object)       (((GObject*) (object)) != NULL && \
+                                   G_IS_OBJECT_CLASS (((GTypeInstance*) (object))->g_class))
+#define G_IS_OBJECT_CLASS(class)   (((GTypeClass*) (class)) != NULL && \
+                                   G_TYPE_IS_OBJECT (((GTypeClass*) (class))->g_type))
+#define G_OBJECT_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), G_TYPE_OBJECT, GObjectClass))
+#define G_OBJECT_TYPE(object)     (G_TYPE_FROM_INSTANCE (object))
+#define G_OBJECT_TYPE_NAME(object) (g_type_name (G_OBJECT_TYPE (object)))
+#define G_OBJECT_CLASS_TYPE(class) (G_TYPE_FROM_CLASS (class))
+#define G_OBJECT_CLASS_NAME(class) (g_type_name (G_OBJECT_CLASS_TYPE (class)))
+
+#define        G_NOTIFY_PRIORITY          (G_PRIORITY_HIGH_IDLE + 20)
+
+
+/* --- typedefs & structures --- */
+typedef struct _GObject             GObject;
+typedef struct _GObjectClass GObjectClass;
+typedef void (*GObjectGetParamFunc)    (GObject     *object,
+                                        guint        param_id,
+                                        GValue      *value,
+                                        GParamSpec  *pspec,
+                                        const gchar *trailer);
+typedef void (*GObjectSetParamFunc)    (GObject     *object,
+                                        guint        param_id,
+                                        GValue      *value,
+                                        GParamSpec  *pspec,
+                                        const gchar *trailer);
+typedef void (*GObjectFinalizeFunc)    (GObject     *object);
+struct _GObject
+{
+  GTypeInstance g_type_instance;
+  
+  /*< private >*/
+  guint                ref_count;
+  GData               *qdata;
+};
+struct _GObjectClass
+{
+  GTypeClass   g_type_class;
+
+  guint               n_param_specs;
+  GParamSpec **param_specs;
+  
+  void      (*get_param)               (GObject        *object,
+                                        guint           param_id,
+                                        GValue         *value,
+                                        GParamSpec     *pspec,
+                                        const gchar    *trailer);
+  void      (*set_param)               (GObject        *object,
+                                        guint           param_id,
+                                        GValue         *value,
+                                        GParamSpec     *pspec,
+                                        const gchar    *trailer);
+  void      (*queue_param_changed)     (GObject        *object,
+                                        GParamSpec     *pspec);
+  void      (*dispatch_param_changed)  (GObject        *object,
+                                        GParamSpec     *pspec);
+  void      (*shutdown)                (GObject        *object);
+  void      (*finalize)                (GObject        *object);
+};
+
+
+/* --- prototypes --- */
+void       g_object_class_install_param   (GObjectClass   *oclass,
+                                           guint           param_id,
+                                           GParamSpec     *pspec /* +1 ref */);
+GParamSpec* g_object_class_find_param_spec (GObjectClass   *oclass,
+                                           const gchar    *param_name);
+gpointer    g_object_new                  (GType           object_type,
+                                           const gchar    *first_param_name,
+                                           ...);
+gpointer    g_object_new_valist                   (GType           object_type,
+                                           const gchar    *first_param_name,
+                                           va_list         var_args);
+void       g_object_set                   (GObject        *object,
+                                           const gchar    *first_param_name,
+                                           ...);
+void       g_object_get                   (GObject        *object,
+                                           const gchar    *first_param_name,
+                                           ...);
+void       g_object_set_valist            (GObject        *object,
+                                           const gchar    *first_param_name,
+                                           va_list         var_args);
+void       g_object_get_valist            (GObject        *object,
+                                           const gchar    *first_param_name,
+                                           va_list         var_args);
+void       g_object_set_param             (GObject        *object,
+                                           const gchar    *param_name,
+                                           const GValue   *value);
+void       g_object_get_param             (GObject        *object,
+                                           const gchar    *param_name,
+                                           GValue         *value);
+void       g_object_queue_param_changed   (GObject        *object,
+                                           const gchar    *param_name);
+GObject*    g_object_ref                  (GObject        *object);
+void       g_object_unref                 (GObject        *object);
+gpointer    g_object_get_qdata            (GObject        *object,
+                                           GQuark          quark);
+void       g_object_set_qdata             (GObject        *object,
+                                           GQuark          quark,
+                                           gpointer        data);
+void       g_object_set_qdata_full        (GObject        *object,
+                                           GQuark          quark,
+                                           gpointer        data,
+                                           GDestroyNotify  destroy);
+gpointer    g_object_steal_qdata          (GObject        *object,
+                                           GQuark          quark);
+
+
+/* --- implementation macros --- */
+#define G_WARN_INVALID_PARAM_ID(object, param_id, pspec) \
+G_STMT_START { \
+  GObject *_object = (GObject*) (object); \
+  GParamSpec *_pspec = (GParamSpec*) (pspec); \
+  guint _param_id = (param_id); \
+  g_warning ("%s: invalid parameter id %u for \"%s\" of type `%s' in `%s'", \
+            G_STRLOC, \
+            _param_id, \
+            _pspec->name, \
+            g_type_name (G_PARAM_SPEC_TYPE (_pspec)), \
+            BSE_OBJECT_TYPE_NAME (_object)); \
+} G_STMT_END
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __G_GOBJECT_H__ */
diff --git a/gobject/gparam.c b/gobject/gparam.c
new file mode 100644 (file)
index 0000000..e29b1a7
--- /dev/null
@@ -0,0 +1,318 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 1997, 1998, 1999, 2000 Tim Janik and Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include       "gparam.h"
+
+
+#include       <string.h>
+
+
+
+/* --- defines --- */
+#define G_PARAM_SPEC_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_PARAM, GParamSpecClass))
+
+
+/* --- prototypes --- */
+extern void    g_param_types_init               (void);
+extern void    g_param_spec_types_init          (void);        /* sync with glib-gparamspecs.c */
+static void    g_param_spec_class_base_init     (GParamSpecClass       *class);
+static void    g_param_spec_class_base_finalize (GParamSpecClass       *class);
+static void    g_param_spec_class_init          (GParamSpecClass       *class,
+                                                 gpointer               class_data);
+static void    g_param_spec_init                (GParamSpec            *pspec);
+static void    g_param_spec_finalize            (GParamSpec            *pspec);
+
+
+/* --- functions --- */
+void
+g_param_types_init (void)      /* sync with glib-gtype.c */
+{
+  static const GTypeFundamentalInfo finfo = {
+    (G_TYPE_FLAG_CLASSED |
+     G_TYPE_FLAG_INSTANTIATABLE |
+     G_TYPE_FLAG_DERIVABLE |
+     G_TYPE_FLAG_DEEP_DERIVABLE),
+    0           /* n_collect_bytes */,
+    NULL        /* GTypeParamCollector */,
+  };
+  static const GTypeInfo param_spec_info = {
+    sizeof (GParamSpecClass),
+
+    (GBaseInitFunc) g_param_spec_class_base_init,
+    (GBaseFinalizeFunc) g_param_spec_class_base_finalize,
+    (GClassInitFunc) g_param_spec_class_init,
+    (GClassFinalizeFunc) NULL,
+    NULL /* class_data */,
+
+    sizeof (GParamSpec),
+    0 /* n_preallocs */,
+    (GInstanceInitFunc) g_param_spec_init,
+  };
+  GType type;
+
+  type = g_type_register_fundamental (G_TYPE_PARAM, "GParam", &finfo, &param_spec_info);
+  g_assert (type == G_TYPE_PARAM);
+
+  /* derived param specs
+   */
+  g_param_spec_types_init ();
+}
+
+static void
+g_param_spec_class_base_init (GParamSpecClass *class)
+{
+}
+
+static void
+g_param_spec_class_base_finalize (GParamSpecClass *class)
+{
+}
+
+static void
+g_param_spec_class_init (GParamSpecClass *class,
+                        gpointer         class_data)
+{
+  class->finalize = g_param_spec_finalize;
+  class->param_init = NULL;
+  class->param_free_value = NULL;
+  class->param_validate = NULL;
+  class->param_values_cmp = NULL;
+  class->param_copy_value = NULL;
+  class->collect_type = 0;
+  class->param_collect_value = NULL;
+  class->lcopy_type = 0;
+  class->param_lcopy_value = NULL;
+}
+
+static void
+g_param_spec_init (GParamSpec *pspec)
+{
+  pspec->name = NULL;
+  pspec->nick = NULL;
+  pspec->blurb = NULL;
+  pspec->flags = 0;
+  pspec->owner_type = 0;
+  pspec->qdata = NULL;
+  pspec->ref_count = 1;
+}
+
+static void
+g_param_spec_finalize (GParamSpec *pspec)
+{
+  g_datalist_clear (&pspec->qdata);
+  
+  g_free (pspec->name);
+  g_free (pspec->nick);
+  g_free (pspec->blurb);
+
+  g_type_free_instance ((GTypeInstance*) pspec);
+}
+
+GParamSpec*
+g_param_spec_ref (GParamSpec *pspec)
+{
+  g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
+  g_return_val_if_fail (pspec->ref_count > 0, NULL);
+
+  pspec->ref_count += 1;
+
+  return pspec;
+}
+
+void
+g_param_spec_unref (GParamSpec *pspec)
+{
+  g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+  g_return_if_fail (pspec->ref_count > 0);
+
+  pspec->ref_count -= 1;
+  if (pspec->ref_count == 0)
+    G_PARAM_SPEC_GET_CLASS (pspec)->finalize (pspec);
+}
+
+gpointer
+g_param_spec_internal (GType        param_type,
+                      const gchar *name,
+                      const gchar *nick,
+                      const gchar *blurb,
+                      GParamFlags  flags)
+{
+  GParamSpec *pspec;
+
+  g_return_val_if_fail (G_TYPE_IS_PARAM (param_type) && param_type != G_TYPE_PARAM, NULL);
+  g_return_val_if_fail (name != NULL, NULL);
+
+  pspec = (gpointer) g_type_create_instance (param_type);
+  pspec->name = g_strdup (name);
+  g_strcanon (pspec->name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
+  pspec->nick = g_strdup (nick ? nick : pspec->name);
+  pspec->blurb = g_strdup (blurb);
+  pspec->flags = (flags & G_PARAM_USER_MASK) | (flags & G_PARAM_MASK);
+
+  return pspec;
+}
+
+gpointer
+g_param_spec_get_qdata (GParamSpec *pspec,
+                       GQuark      quark)
+{
+  g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
+  
+  return quark ? g_datalist_id_get_data (&pspec->qdata, quark) : NULL;
+}
+
+void
+g_param_spec_set_qdata (GParamSpec *pspec,
+                       GQuark      quark,
+                       gpointer    data)
+{
+  g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+  g_return_if_fail (quark > 0);
+
+  g_datalist_id_set_data (&pspec->qdata, quark, data);
+}
+
+void
+g_param_spec_set_qdata_full (GParamSpec    *pspec,
+                            GQuark         quark,
+                            gpointer       data,
+                            GDestroyNotify destroy)
+{
+  g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+  g_return_if_fail (quark > 0);
+
+  g_datalist_id_set_data_full (&pspec->qdata, quark, data, data ? destroy : NULL);
+}
+
+gpointer
+g_param_spec_steal_qdata (GParamSpec *pspec,
+                         GQuark      quark)
+{
+  g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
+  g_return_val_if_fail (quark > 0, NULL);
+  
+  return g_datalist_id_remove_no_notify (&pspec->qdata, quark);
+}
+
+static guint
+param_spec_hash (gconstpointer key_spec)
+{
+  const GParamSpec *key = key_spec;
+  const gchar *p;
+  guint h = key->owner_type;
+
+  for (p = key->name; *p; p++)
+    h = (h << 5) - h + *p;
+
+  return h;
+}
+
+static gint
+param_spec_equals (gconstpointer key_spec_1,
+                  gconstpointer key_spec_2)
+{
+  const GParamSpec *key1 = key_spec_1;
+  const GParamSpec *key2 = key_spec_2;
+
+  return (key1->owner_type == key2->owner_type &&
+         strcmp (key1->name, key2->name) == 0);
+}
+
+GHashTable*
+g_param_spec_hash_table_new (void)
+{
+  return g_hash_table_new (param_spec_hash, param_spec_equals);
+}
+
+void
+g_param_spec_hash_table_insert (GHashTable *hash_table,
+                               GParamSpec *pspec,
+                               GType       owner_type)
+{
+  g_return_if_fail (hash_table != NULL);
+  g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+  g_return_if_fail (pspec->name != NULL);
+  if (pspec->owner_type != owner_type)
+    g_return_if_fail (pspec->owner_type == 0);
+
+  if (strchr (pspec->name, ':'))
+    g_warning (G_STRLOC ": parameter name `%s' contains field-delimeter",
+              pspec->name);
+  else
+    {
+      pspec->owner_type = owner_type;
+      g_hash_table_insert (hash_table, pspec, pspec);
+    }
+}
+
+void
+g_param_spec_hash_table_remove (GHashTable *hash_table,
+                               GParamSpec *pspec)
+{
+  g_return_if_fail (hash_table != NULL);
+  g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+
+  g_assert (g_param_spec_hash_table_lookup (hash_table, pspec->name, pspec->owner_type, FALSE, NULL) != NULL); // FIXME: paranoid
+
+  g_hash_table_remove (hash_table, pspec);
+  g_assert (g_param_spec_hash_table_lookup (hash_table, pspec->name, pspec->owner_type, FALSE, NULL) == NULL); // FIXME: paranoid
+  pspec->owner_type = 0;
+}
+
+GParamSpec*
+g_param_spec_hash_table_lookup (GHashTable   *hash_table,
+                               const gchar  *param_name,
+                               GType         owner_type,
+                               gboolean      try_ancestors,
+                               const gchar **trailer)
+{
+  GParamSpec *pspec;
+  GParamSpec key;
+  gchar *delim;
+  
+  g_return_val_if_fail (hash_table != NULL, NULL);
+  g_return_val_if_fail (param_name != NULL, NULL);
+  
+  key.owner_type = owner_type;
+  delim = strchr (param_name, ':');
+  if (delim)
+    key.name = g_strndup (param_name, delim - param_name);
+  else
+    key.name = g_strdup (param_name);
+  g_strcanon (key.name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
+
+  if (trailer)
+    *trailer = delim;
+  
+  pspec = g_hash_table_lookup (hash_table, &key);
+  if (!pspec && try_ancestors)
+    {
+      key.owner_type = g_type_parent (key.owner_type);
+      while (key.owner_type)
+       {
+         pspec = g_hash_table_lookup (hash_table, &key);
+         if (pspec)
+           break;
+         key.owner_type = g_type_parent (key.owner_type);
+       }
+    }
+  
+  g_free (key.name);
+  
+  return pspec;
+}
diff --git a/gobject/gparam.h b/gobject/gparam.h
new file mode 100644 (file)
index 0000000..fb6ef1e
--- /dev/null
@@ -0,0 +1,186 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 1997, 1998, 1999, 2000 Tim Janik and Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * gparam.h: GParamSpec base class implementation
+ */
+#ifndef __G_PARAM_H__
+#define __G_PARAM_H__
+
+
+#include       <gobject/gtype.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* --- type macros --- */
+#define G_TYPE_IS_PARAM(type)          (G_TYPE_FUNDAMENTAL (type) == G_TYPE_PARAM)
+#define G_PARAM_SPEC_TYPE(pspec)       (G_TYPE_FROM_INSTANCE (pspec))
+#define G_PARAM_SPEC_TYPE_NAME(pspec)  (g_type_name (G_PARAM_SPEC_TYPE (pspec)))
+#define G_PARAM_SPEC(pspec)            (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM, GParamSpec))
+#define G_IS_PARAM_SPEC(pspec)         (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM))
+#define G_PARAM_SPEC_GET_CLASS(pspec)  (G_TYPE_INSTANCE_GET_CLASS ((pspec), G_TYPE_PARAM, GParamSpecClass))
+#define        G_IS_VALUE(value)               (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_PARAM))
+
+
+/* --- flags --- */
+typedef enum
+{
+  G_PARAM_READABLE            = 1 << 0,
+  G_PARAM_WRITABLE            = 1 << 1,
+  G_PARAM_MASK                = 0x000f,
+  /* bits in the range 0xfff0 are reserved for 3rd party usage */
+  G_PARAM_USER_MASK           = 0xfff0
+} GParamFlags;
+
+
+/* --- typedefs & structures --- */
+typedef struct _GParamSpecClass GParamSpecClass;
+typedef struct _GParamSpec      GParamSpec;
+typedef struct _GValue          GValue;
+typedef union  _GParamCValue   GParamCValue;
+typedef void  (*GValueExchange) (GValue*, GValue*);
+struct _GParamSpecClass
+{
+  GTypeClass      g_type_class;
+
+  void         (*finalize)             (GParamSpec   *pspec);
+
+  /* GParam methods */
+  void          (*param_init)           (GValue       *value,
+                                        GParamSpec   *pspec);
+  void          (*param_free_value)     (GValue       *value);
+  gboolean      (*param_validate)       (GValue       *value,
+                                        GParamSpec   *pspec);
+  gint          (*param_values_cmp)     (const GValue *value1,
+                                        const GValue *value2,
+                                        GParamSpec   *pspec);
+  void          (*param_copy_value)     (const GValue *src_value,
+                                        GValue       *dest_value);
+  /* varargs functionality (optional) */
+  guint                  collect_type;
+  gchar*        (*param_collect_value) (GValue       *value,
+                                        GParamSpec   *pspec,
+                                        guint         nth_value,
+                                        GType        *collect_type,
+                                        GParamCValue *collect_value);
+  guint                  lcopy_type;
+  gchar*        (*param_lcopy_value)   (const GValue *value,
+                                        GParamSpec   *pspec,
+                                        guint         nth_value,
+                                        GType        *collect_type,
+                                        GParamCValue *collect_value);
+};
+struct _GParamSpec
+{
+  GTypeInstance  g_instance;
+
+  gchar         *name;
+  gchar         *nick;
+  gchar         *blurb;
+  GParamFlags    flags;
+
+  /*< private >*/
+  GType                 owner_type;
+  GData                *qdata;
+  guint          ref_count;
+};
+
+
+/* --- prototypes --- */
+GParamSpec*    g_param_spec_ref                (GParamSpec    *pspec);
+void           g_param_spec_unref              (GParamSpec    *pspec);
+gpointer        g_param_spec_get_qdata         (GParamSpec    *pspec,
+                                                GQuark         quark);
+void            g_param_spec_set_qdata         (GParamSpec    *pspec,
+                                                GQuark         quark,
+                                                gpointer       data);
+void            g_param_spec_set_qdata_full    (GParamSpec    *pspec,
+                                                GQuark         quark,
+                                                gpointer       data,
+                                                GDestroyNotify destroy);
+gpointer        g_param_spec_steal_qdata       (GParamSpec    *pspec,
+                                                GQuark         quark);
+
+
+/* --- private --- */
+gpointer       g_param_spec_internal           (GType          param_type,
+                                                const gchar   *name,
+                                                const gchar   *nick,
+                                                const gchar   *blurb,
+                                                GParamFlags    flags);
+GHashTable*    g_param_spec_hash_table_new     (void);
+void           g_param_spec_hash_table_insert  (GHashTable    *hash_table,
+                                                GParamSpec    *pspec,
+                                                GType          owner_type);
+void           g_param_spec_hash_table_remove  (GHashTable    *hash_table,
+                                                GParamSpec    *pspec);
+GParamSpec*    g_param_spec_hash_table_lookup  (GHashTable    *hash_table,
+                                                const gchar   *param_name,
+                                                GType          owner_type,
+                                                gboolean       try_ancestors,
+                                                const gchar  **trailer);
+
+
+/* contracts:
+ *
+ * class functions may not evaluate param->pspec directly,
+ * instead, pspec will be passed as argument if required.
+ *
+ * void        param_init (GParam *param, GParamSpec *pspec):
+ *     initialize param's value to default if pspec is given,
+ *     and to zero-equivalent (a value that doesn't need to be
+ *     free()ed later on) otherwise.
+ *
+ * void param_free_value (GParam *param):
+ *     free param's value if required, zero-reinitialization
+ *     of the value is not required. (this class function
+ *     may be NULL for param types that don't need to free
+ *     values, such as ints or floats).
+ *
+ * gboolean param_validate (GParam *param, GParamSpec *pspec):
+ *     modify param's value in the least destructive way, so
+ *     that it complies with pspec's requirements (i.e.
+ *     according to minimum/maximum ranges etc...). return
+ *     whether modification was necessary.
+ *
+ * gint param_values_cmp (GParam *param1, GParam *param2, GParamSpec*):
+ *     return param1 - param2, i.e. <0 if param1 < param2,
+ *     >0 if param1 > param2, and 0 if they are equal
+ *     (passing pspec is optional, but recommended)
+ *
+ * void param_copy_value (GParam *param_src, GParam *param_dest):
+ *     copy value from param_src to param_dest, param_dest is
+ *     already free()d and zero-initialized, so its value can
+ *     simply be overwritten. (may be NULL for memcpy)
+ *
+ * gchar* param_collect_value ():
+ *     class function may be NULL.
+ *
+ * gchar* param_lcopy_value ():
+ *     class function may be NULL.
+ *
+ */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __G_PARAM_H__ */
diff --git a/gobject/gparamspecs.c b/gobject/gparamspecs.c
new file mode 100644 (file)
index 0000000..628d134
--- /dev/null
@@ -0,0 +1,2004 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 1997, 1998, 1999, 2000 Tim Janik and Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include       "gparamspecs.h"
+
+#include       "gvaluecollector.h"
+#include       <string.h>
+#include       "../config.h"   /* for SIZEOF_LONG */
+
+#define        G_FLOAT_EPSILON         (1e-30)
+#define        G_DOUBLE_EPSILON        (1e-90)
+
+
+/* --- prototypes --- */
+extern void    g_param_spec_types_init (void);
+
+
+/* --- param spec functions --- */
+static void
+param_spec_char_init (GParamSpec *pspec)
+{
+  GParamSpecChar *cspec = G_PARAM_SPEC_CHAR (pspec);
+  
+  cspec->minimum = 0x7f;
+  cspec->maximum = 0x80;
+  cspec->default_value = 0;
+}
+
+static void
+param_char_init (GValue            *value,
+                GParamSpec *pspec)
+{
+  if (pspec)
+    value->data[0].v_int = G_PARAM_SPEC_CHAR (pspec)->default_value;
+}
+
+static gboolean
+param_char_validate (GValue    *value,
+                    GParamSpec *pspec)
+{
+  GParamSpecChar *cspec = G_PARAM_SPEC_CHAR (pspec);
+  gint oval = value->data[0].v_int;
+  
+  value->data[0].v_int = CLAMP (value->data[0].v_int, cspec->minimum, cspec->maximum);
+  
+  return value->data[0].v_int != oval;
+}
+
+static gchar*
+param_char_lcopy_value (const GValue *value,
+                       GParamSpec   *pspec,
+                       guint         nth_value,
+                       GType        *collect_type,
+                       GParamCValue *collect_value)
+{
+  gint8 *int8_p = collect_value->v_pointer;
+  
+  if (!int8_p)
+    return g_strdup_printf ("value location for `%s' passed as NULL",
+                           g_type_name (pspec ? G_PARAM_SPEC_TYPE (pspec) : G_VALUE_TYPE (value)));
+  
+  *int8_p = value->data[0].v_int;
+  
+  *collect_type = 0;
+  return NULL;
+}
+
+static void
+param_spec_uchar_init (GParamSpec *pspec)
+{
+  GParamSpecUChar *uspec = G_PARAM_SPEC_UCHAR (pspec);
+  
+  uspec->minimum = 0;
+  uspec->maximum = 0xff;
+  uspec->default_value = 0;
+}
+
+static void
+param_uchar_init (GValue     *value,
+                 GParamSpec *pspec)
+{
+  if (pspec)
+    value->data[0].v_uint = G_PARAM_SPEC_UCHAR (pspec)->default_value;
+}
+
+static gboolean
+param_uchar_validate (GValue    *value,
+                     GParamSpec *pspec)
+{
+  GParamSpecUChar *uspec = G_PARAM_SPEC_UCHAR (pspec);
+  guint oval = value->data[0].v_uint;
+  
+  value->data[0].v_uint = CLAMP (value->data[0].v_uint, uspec->minimum, uspec->maximum);
+  
+  return value->data[0].v_uint != oval;
+}
+
+static void
+param_bool_init (GValue            *value,
+                GParamSpec *pspec)
+{
+  if (pspec)
+    value->data[0].v_int = G_PARAM_SPEC_BOOL (pspec)->default_value;
+}
+
+static gboolean
+param_bool_validate (GValue    *value,
+                    GParamSpec *pspec)
+{
+  gint oval = value->data[0].v_int;
+  
+  value->data[0].v_int = value->data[0].v_int != FALSE;
+  
+  return value->data[0].v_int != oval;
+}
+
+static gchar*
+param_bool_lcopy_value (const GValue *value,
+                       GParamSpec   *pspec,
+                       guint         nth_value,
+                       GType        *collect_type,
+                       GParamCValue *collect_value)
+{
+  gboolean *bool_p = collect_value->v_pointer;
+  
+  if (!bool_p)
+    return g_strdup_printf ("value location for `%s' passed as NULL",
+                           g_type_name (pspec ? G_PARAM_SPEC_TYPE (pspec) : G_VALUE_TYPE (value)));
+  
+  *bool_p = value->data[0].v_int;
+  
+  *collect_type = 0;
+  return NULL;
+}
+
+static void
+param_spec_int_init (GParamSpec *pspec)
+{
+  GParamSpecInt *ispec = G_PARAM_SPEC_INT (pspec);
+  
+  ispec->minimum = 0x7fffffff;
+  ispec->maximum = 0x80000000;
+  ispec->default_value = 0;
+}
+
+static void
+param_int_init (GValue    *value,
+               GParamSpec *pspec)
+{
+  if (pspec)
+    value->data[0].v_int = G_PARAM_SPEC_INT (pspec)->default_value;
+}
+
+static gboolean
+param_int_validate (GValue     *value,
+                   GParamSpec *pspec)
+{
+  GParamSpecInt *ispec = G_PARAM_SPEC_INT (pspec);
+  gint oval = value->data[0].v_int;
+  
+  value->data[0].v_int = CLAMP (value->data[0].v_int, ispec->minimum, ispec->maximum);
+  
+  return value->data[0].v_int != oval;
+}
+
+static gint
+param_int_values_cmp (const GValue *value1,
+                     const GValue *value2,
+                     GParamSpec   *pspec)
+{
+  if (value1->data[0].v_int < value2->data[0].v_int)
+    return -1;
+  else
+    return value1->data[0].v_int - value2->data[0].v_int;
+}
+
+static gchar*
+param_int_collect_value (GValue              *value,
+                        GParamSpec   *pspec,
+                        guint         nth_value,
+                        GType        *collect_type,
+                        GParamCValue *collect_value)
+{
+  value->data[0].v_int = collect_value->v_int;
+  
+  *collect_type = 0;
+  return NULL;
+}
+
+static gchar*
+param_int_lcopy_value (const GValue *value,
+                      GParamSpec   *pspec,
+                      guint         nth_value,
+                      GType        *collect_type,
+                      GParamCValue *collect_value)
+{
+  gint *int_p = collect_value->v_pointer;
+  
+  if (!int_p)
+    return g_strdup_printf ("value location for `%s' passed as NULL",
+                           g_type_name (pspec ? G_PARAM_SPEC_TYPE (pspec) : G_VALUE_TYPE (value)));
+  
+  *int_p = value->data[0].v_int;
+  
+  *collect_type = 0;
+  return NULL;
+}
+
+static void
+param_spec_uint_init (GParamSpec *pspec)
+{
+  GParamSpecUInt *uspec = G_PARAM_SPEC_UINT (pspec);
+  
+  uspec->minimum = 0;
+  uspec->maximum = 0xffffffff;
+  uspec->default_value = 0;
+}
+
+static void
+param_uint_init (GValue            *value,
+                GParamSpec *pspec)
+{
+  if (pspec)
+    value->data[0].v_uint = G_PARAM_SPEC_UINT (pspec)->default_value;
+}
+
+static gboolean
+param_uint_validate (GValue    *value,
+                    GParamSpec *pspec)
+{
+  GParamSpecUInt *uspec = G_PARAM_SPEC_UINT (pspec);
+  guint oval = value->data[0].v_uint;
+  
+  value->data[0].v_uint = CLAMP (value->data[0].v_uint, uspec->minimum, uspec->maximum);
+  
+  return value->data[0].v_uint != oval;
+}
+
+static gint
+param_uint_values_cmp (const GValue *value1,
+                      const GValue *value2,
+                      GParamSpec   *pspec)
+{
+  if (value1->data[0].v_uint < value2->data[0].v_uint)
+    return -1;
+  else
+    return value1->data[0].v_uint - value2->data[0].v_uint;
+}
+
+static void
+param_spec_long_init (GParamSpec *pspec)
+{
+  GParamSpecLong *lspec = G_PARAM_SPEC_LONG (pspec);
+  
+#if SIZEOF_LONG == 4
+  lspec->minimum = 0x7fffffff;
+  lspec->maximum = 0x80000000;
+#else /* SIZEOF_LONG != 4 (8) */
+  lspec->minimum = 0x7fffffffffffffff;
+  lspec->maximum = 0x8000000000000000;
+#endif
+  lspec->default_value = 0;
+}
+
+static void
+param_long_init (GValue            *value,
+                GParamSpec *pspec)
+{
+  if (pspec)
+    value->data[0].v_long = G_PARAM_SPEC_LONG (pspec)->default_value;
+}
+
+static gboolean
+param_long_validate (GValue    *value,
+                    GParamSpec *pspec)
+{
+  GParamSpecLong *lspec = G_PARAM_SPEC_LONG (pspec);
+  glong oval = value->data[0].v_long;
+  
+  value->data[0].v_long = CLAMP (value->data[0].v_long, lspec->minimum, lspec->maximum);
+  
+  return value->data[0].v_long != oval;
+}
+
+static gint
+param_long_values_cmp (const GValue *value1,
+                      const GValue *value2,
+                      GParamSpec   *pspec)
+{
+  if (value1->data[0].v_long < value2->data[0].v_long)
+    return -1;
+  else
+    return value1->data[0].v_long - value2->data[0].v_long;
+}
+
+static gchar*
+param_long_collect_value (GValue       *value,
+                         GParamSpec   *pspec,
+                         guint         nth_value,
+                         GType        *collect_type,
+                         GParamCValue *collect_value)
+{
+  value->data[0].v_long = collect_value->v_long;
+  
+  *collect_type = 0;
+  return NULL;
+}
+
+static gchar*
+param_long_lcopy_value (const GValue *value,
+                       GParamSpec   *pspec,
+                       guint         nth_value,
+                       GType        *collect_type,
+                       GParamCValue *collect_value)
+{
+  glong *long_p = collect_value->v_pointer;
+  
+  if (!long_p)
+    return g_strdup_printf ("value location for `%s' passed as NULL",
+                           g_type_name (pspec ? G_PARAM_SPEC_TYPE (pspec) : G_VALUE_TYPE (value)));
+  
+  *long_p = value->data[0].v_long;
+  
+  *collect_type = 0;
+  return NULL;
+}
+
+static void
+param_spec_ulong_init (GParamSpec *pspec)
+{
+  GParamSpecULong *uspec = G_PARAM_SPEC_ULONG (pspec);
+  
+  uspec->minimum = 0;
+#if SIZEOF_LONG == 4
+  uspec->maximum = 0xffffffff;
+#else /* SIZEOF_LONG != 4 (8) */
+  uspec->maximum = 0xffffffffffffffff;
+#endif
+  uspec->default_value = 0;
+}
+
+static void
+param_ulong_init (GValue     *value,
+                 GParamSpec *pspec)
+{
+  if (pspec)
+    value->data[0].v_ulong = G_PARAM_SPEC_ULONG (pspec)->default_value;
+}
+
+static gboolean
+param_ulong_validate (GValue    *value,
+                     GParamSpec *pspec)
+{
+  GParamSpecULong *uspec = G_PARAM_SPEC_ULONG (pspec);
+  gulong oval = value->data[0].v_ulong;
+  
+  value->data[0].v_ulong = CLAMP (value->data[0].v_ulong, uspec->minimum, uspec->maximum);
+  
+  return value->data[0].v_ulong != oval;
+}
+
+static gint
+param_ulong_values_cmp (const GValue *value1,
+                       const GValue *value2,
+                       GParamSpec   *pspec)
+{
+  if (value1->data[0].v_ulong < value2->data[0].v_ulong)
+    return -1;
+  else
+    return value1->data[0].v_ulong - value2->data[0].v_ulong;
+}
+
+static void
+param_spec_enum_init (GParamSpec *pspec)
+{
+  GParamSpecEnum *espec = G_PARAM_SPEC_ENUM (pspec);
+  
+  espec->enum_class = NULL;
+  espec->default_value = 0;
+}
+
+static void
+param_spec_enum_finalize (GParamSpec *pspec)
+{
+  GParamSpecEnum *espec = G_PARAM_SPEC_ENUM (pspec);
+  GParamSpecClass *parent_class = g_type_class_peek (g_type_parent (G_TYPE_PARAM_ENUM));
+  
+  if (espec->enum_class)
+    {
+      g_type_class_unref (espec->enum_class);
+      espec->enum_class = NULL;
+    }
+  
+  parent_class->finalize (pspec);
+}
+
+static void
+param_enum_init (GValue            *value,
+                GParamSpec *pspec)
+{
+  if (pspec)
+    value->data[0].v_long = G_PARAM_SPEC_ENUM (pspec)->default_value;
+}
+
+static gboolean
+param_enum_validate (GValue    *value,
+                    GParamSpec *pspec)
+{
+  GParamSpecEnum *espec = G_PARAM_SPEC_ENUM (pspec);
+  glong oval = value->data[0].v_long;
+  
+  if (!espec->enum_class ||
+      !g_enum_get_value (espec->enum_class, value->data[0].v_long))
+    value->data[0].v_long = espec->default_value;
+  
+  return value->data[0].v_long != oval;
+}
+
+static gchar*
+param_enum_collect_value (GValue       *value,
+                         GParamSpec   *pspec,
+                         guint         nth_value,
+                         GType        *collect_type,
+                         GParamCValue *collect_value)
+{
+  value->data[0].v_long = collect_value->v_int;
+  
+  *collect_type = 0;
+  return NULL;
+}
+
+static gchar*
+param_enum_lcopy_value (const GValue *value,
+                       GParamSpec   *pspec,
+                       guint         nth_value,
+                       GType        *collect_type,
+                       GParamCValue *collect_value)
+{
+  gint *int_p = collect_value->v_pointer;
+  
+  if (!int_p)
+    return g_strdup_printf ("value location for `%s' passed as NULL",
+                           g_type_name (pspec ? G_PARAM_SPEC_TYPE (pspec) : G_VALUE_TYPE (value)));
+  
+  *int_p = value->data[0].v_long;
+  
+  *collect_type = 0;
+  return NULL;
+}
+
+static void
+param_spec_flags_init (GParamSpec *pspec)
+{
+  GParamSpecFlags *fspec = G_PARAM_SPEC_FLAGS (pspec);
+  
+  fspec->flags_class = NULL;
+  fspec->default_value = 0;
+}
+
+static void
+param_spec_flags_finalize (GParamSpec *pspec)
+{
+  GParamSpecFlags *fspec = G_PARAM_SPEC_FLAGS (pspec);
+  GParamSpecClass *parent_class = g_type_class_peek (g_type_parent (G_TYPE_PARAM_FLAGS));
+  
+  if (fspec->flags_class)
+    {
+      g_type_class_unref (fspec->flags_class);
+      fspec->flags_class = NULL;
+    }
+  
+  parent_class->finalize (pspec);
+}
+
+static void
+param_flags_init (GValue     *value,
+                 GParamSpec *pspec)
+{
+  if (pspec)
+    value->data[0].v_ulong = G_PARAM_SPEC_FLAGS (pspec)->default_value;
+}
+
+static gboolean
+param_flags_validate (GValue    *value,
+                     GParamSpec *pspec)
+{
+  GParamSpecFlags *fspec = G_PARAM_SPEC_FLAGS (pspec);
+  gulong oval = value->data[0].v_ulong;
+  
+  if (fspec->flags_class)
+    value->data[0].v_ulong &= fspec->flags_class->mask;
+  else
+    value->data[0].v_ulong = fspec->default_value;
+  
+  return value->data[0].v_ulong != oval;
+}
+
+static void
+param_spec_float_init (GParamSpec *pspec)
+{
+  GParamSpecFloat *fspec = G_PARAM_SPEC_FLOAT (pspec);
+  
+  fspec->minimum = G_MINFLOAT;
+  fspec->maximum = G_MAXFLOAT;
+  fspec->default_value = 0;
+  fspec->epsilon = G_FLOAT_EPSILON;
+}
+
+static void
+param_float_init (GValue     *value,
+                 GParamSpec *pspec)
+{
+  if (pspec)
+    value->data[0].v_float = G_PARAM_SPEC_FLOAT (pspec)->default_value;
+}
+
+static gboolean
+param_float_validate (GValue    *value,
+                     GParamSpec *pspec)
+{
+  GParamSpecFloat *fspec = G_PARAM_SPEC_FLOAT (pspec);
+  gfloat oval = value->data[0].v_float;
+  
+  value->data[0].v_float = CLAMP (value->data[0].v_float, fspec->minimum, fspec->maximum);
+  
+  return value->data[0].v_float != oval;
+}
+
+static gint
+param_float_values_cmp (const GValue *value1,
+                       const GValue *value2,
+                       GParamSpec   *pspec)
+{
+  gfloat epsilon = pspec ? G_PARAM_SPEC_FLOAT (pspec)->epsilon : G_FLOAT_EPSILON;
+  
+  if (value1->data[0].v_float < value2->data[0].v_float)
+    return - (value2->data[0].v_float - value1->data[0].v_float > epsilon);
+  else
+    return value1->data[0].v_float - value2->data[0].v_float > epsilon;
+}
+
+static gchar*
+param_float_collect_value (GValue      *value,
+                          GParamSpec   *pspec,
+                          guint         nth_value,
+                          GType        *collect_type,
+                          GParamCValue *collect_value)
+{
+  value->data[0].v_float = collect_value->v_double;
+  
+  *collect_type = 0;
+  return NULL;
+}
+
+static gchar*
+param_float_lcopy_value (const GValue *value,
+                        GParamSpec   *pspec,
+                        guint         nth_value,
+                        GType        *collect_type,
+                        GParamCValue *collect_value)
+{
+  gfloat *float_p = collect_value->v_pointer;
+  
+  if (!float_p)
+    return g_strdup_printf ("value location for `%s' passed as NULL",
+                           g_type_name (pspec ? G_PARAM_SPEC_TYPE (pspec) : G_VALUE_TYPE (value)));
+  
+  *float_p = value->data[0].v_float;
+  
+  *collect_type = 0;
+  return NULL;
+}
+
+static void
+param_spec_double_init (GParamSpec *pspec)
+{
+  GParamSpecDouble *dspec = G_PARAM_SPEC_DOUBLE (pspec);
+  
+  dspec->minimum = G_MINDOUBLE;
+  dspec->maximum = G_MAXDOUBLE;
+  dspec->default_value = 0;
+  dspec->epsilon = G_DOUBLE_EPSILON;
+}
+
+static void
+param_double_init (GValue     *value,
+                  GParamSpec *pspec)
+{
+  if (pspec)
+    value->data[0].v_double = G_PARAM_SPEC_DOUBLE (pspec)->default_value;
+}
+
+static gboolean
+param_double_validate (GValue    *value,
+                      GParamSpec *pspec)
+{
+  GParamSpecDouble *dspec = G_PARAM_SPEC_DOUBLE (pspec);
+  gdouble oval = value->data[0].v_double;
+  
+  value->data[0].v_double = CLAMP (value->data[0].v_double, dspec->minimum, dspec->maximum);
+  
+  return value->data[0].v_double != oval;
+}
+
+static gint
+param_double_values_cmp (const GValue *value1,
+                        const GValue *value2,
+                        GParamSpec   *pspec)
+{
+  gdouble epsilon = pspec ? G_PARAM_SPEC_DOUBLE (pspec)->epsilon : G_DOUBLE_EPSILON;
+  
+  if (value1->data[0].v_double < value2->data[0].v_double)
+    return - (value2->data[0].v_double - value1->data[0].v_double > epsilon);
+  else
+    return value1->data[0].v_double - value2->data[0].v_double > epsilon;
+}
+
+static gchar*
+param_double_collect_value (GValue      *value,
+                           GParamSpec   *pspec,
+                           guint         nth_value,
+                           GType        *collect_type,
+                           GParamCValue *collect_value)
+{
+  value->data[0].v_double = collect_value->v_double;
+  
+  *collect_type = 0;
+  return NULL;
+}
+
+static gchar*
+param_double_lcopy_value (const GValue *value,
+                         GParamSpec   *pspec,
+                         guint         nth_value,
+                         GType        *collect_type,
+                         GParamCValue *collect_value)
+{
+  gdouble *double_p = collect_value->v_pointer;
+  
+  if (!double_p)
+    return g_strdup_printf ("value location for `%s' passed as NULL",
+                           g_type_name (pspec ? G_PARAM_SPEC_TYPE (pspec) : G_VALUE_TYPE (value)));
+  
+  *double_p = value->data[0].v_double;
+  
+  *collect_type = 0;
+  return NULL;
+}
+
+static void
+param_spec_string_init (GParamSpec *pspec)
+{
+  GParamSpecString *sspec = G_PARAM_SPEC_STRING (pspec);
+  
+  sspec->default_value = NULL;
+  sspec->cset_first = NULL;
+  sspec->cset_nth = NULL;
+  sspec->substitutor = '_';
+  sspec->null_fold_if_empty = FALSE;
+  sspec->ensure_non_null = FALSE;
+}
+
+static void
+param_spec_string_finalize (GParamSpec *pspec)
+{
+  GParamSpecString *sspec = G_PARAM_SPEC_STRING (pspec);
+  GParamSpecClass *parent_class = g_type_class_peek (g_type_parent (G_TYPE_PARAM_STRING));
+  
+  g_free (sspec->default_value);
+  g_free (sspec->cset_first);
+  g_free (sspec->cset_nth);
+  sspec->default_value = NULL;
+  sspec->cset_first = NULL;
+  sspec->cset_nth = NULL;
+  
+  parent_class->finalize (pspec);
+}
+
+static void
+param_string_init (GValue     *value,
+                  GParamSpec *pspec)
+{
+  if (pspec)
+    value->data[0].v_pointer = g_strdup (G_PARAM_SPEC_STRING (pspec)->default_value);
+}
+
+static void
+param_string_free_value (GValue *value)
+{
+  g_free (value->data[0].v_pointer);
+}
+
+static gboolean
+param_string_validate (GValue    *value,
+                      GParamSpec *pspec)
+{
+  GParamSpecString *sspec = G_PARAM_SPEC_STRING (pspec);
+  gchar *string = value->data[0].v_pointer;
+  guint changed = 0;
+  
+  if (string && string[0])
+    {
+      gchar *s;
+      
+      if (sspec->cset_first && !strchr (sspec->cset_first, string[0]))
+       {
+         string[0] = sspec->substitutor;
+         changed++;
+       }
+      if (sspec->cset_nth)
+       for (s = string + 1; *s; s++)
+         if (!strchr (sspec->cset_nth, *s))
+           {
+             *s = sspec->substitutor;
+             changed++;
+           }
+    }
+  if (sspec->null_fold_if_empty && string && string[0] == 0)
+    {
+      g_free (value->data[0].v_pointer);
+      value->data[0].v_pointer = NULL;
+      changed++;
+      string = value->data[0].v_pointer;
+    }
+  if (sspec->ensure_non_null && !string)
+    {
+      value->data[0].v_pointer = g_strdup ("");
+      changed++;
+      string = value->data[0].v_pointer;
+    }
+  
+  return changed;
+}
+
+static gint
+param_string_values_cmp (const GValue *value1,
+                        const GValue *value2,
+                        GParamSpec   *pspec)
+{
+  if (!value1->data[0].v_pointer)
+    return value2->data[0].v_pointer != NULL ? -1 : 0;
+  else if (!value2->data[0].v_pointer)
+    return value1->data[0].v_pointer != NULL;
+  else
+    return strcmp (value1->data[0].v_pointer, value2->data[0].v_pointer);
+}
+
+static void
+param_string_copy_value (const GValue *src_value,
+                        GValue       *dest_value)
+{
+  dest_value->data[0].v_pointer = g_strdup (src_value->data[0].v_pointer);
+}
+
+static gchar*
+param_string_collect_value (GValue      *value,
+                           GParamSpec   *pspec,
+                           guint         nth_value,
+                           GType        *collect_type,
+                           GParamCValue *collect_value)
+{
+  value->data[0].v_pointer = g_strdup (collect_value->v_pointer);
+  
+  *collect_type = 0;
+  return NULL;
+}
+
+static gchar*
+param_string_lcopy_value (const GValue *value,
+                         GParamSpec   *pspec,
+                         guint         nth_value,
+                         GType        *collect_type,
+                         GParamCValue *collect_value)
+{
+  gchar **string_p = collect_value->v_pointer;
+  
+  if (!string_p)
+    return g_strdup_printf ("value location for `%s' passed as NULL",
+                           g_type_name (pspec ? G_PARAM_SPEC_TYPE (pspec) : G_VALUE_TYPE (value)));
+  
+  *string_p = g_strdup (value->data[0].v_pointer);
+  
+  *collect_type = 0;
+  return NULL;
+}
+
+static void
+param_spec_object_init (GParamSpec *pspec)
+{
+  GParamSpecObject *ospec = G_PARAM_SPEC_OBJECT (pspec);
+  
+  ospec->object_type = G_TYPE_OBJECT;
+}
+
+static void
+param_object_init (GValue     *value,
+                  GParamSpec *pspec)
+{
+  value->data[0].v_pointer = NULL;
+}
+
+static void
+param_object_free_value (GValue *value)
+{
+  if (value->data[0].v_pointer)
+    g_object_unref (value->data[0].v_pointer);
+}
+
+static gboolean
+param_object_validate (GValue    *value,
+                      GParamSpec *pspec)
+{
+  GParamSpecObject *ospec = G_PARAM_SPEC_OBJECT (pspec);
+  GObject *object = value->data[0].v_pointer;
+  guint changed = 0;
+  
+  if (object && !g_type_is_a (G_OBJECT_TYPE (object), ospec->object_type))
+    {
+      g_object_unref (object);
+      value->data[0].v_pointer = NULL;
+      changed++;
+    }
+  
+  return changed;
+}
+
+static gint
+param_object_values_cmp (const GValue *value1,
+                        const GValue *value2,
+                        GParamSpec   *pspec)
+{
+  return value1->data[0].v_pointer != value2->data[0].v_pointer;
+}
+
+static void
+param_object_copy_value (const GValue *src_value,
+                        GValue       *dest_value)
+{
+  if (src_value->data[0].v_pointer)
+    dest_value->data[0].v_pointer = g_object_ref (src_value->data[0].v_pointer);
+  else
+    dest_value->data[0].v_pointer = NULL;
+}
+
+static gchar*
+param_object_collect_value (GValue      *value,
+                           GParamSpec   *pspec,
+                           guint         nth_value,
+                           GType        *collect_type,
+                           GParamCValue *collect_value)
+{
+  if (collect_value->v_pointer)
+    {
+      GObject *object = collect_value->v_pointer;
+      
+      if (object->g_type_instance.g_class == NULL)
+       return g_strconcat ("invalid unclassed object pointer for param type `",
+                           g_type_name (pspec ? G_PARAM_SPEC_TYPE (pspec) : G_VALUE_TYPE (value)),
+                           "'",
+                           NULL);
+      else if (pspec && !g_type_is_a (G_OBJECT_TYPE (object), G_PARAM_SPEC_OBJECT (pspec)->object_type))
+       return g_strconcat ("invalid object `",
+                           G_OBJECT_TYPE_NAME (object),
+                           "' for param type `",
+                           g_type_name (G_PARAM_SPEC_TYPE (pspec)),
+                           "' which requires `",
+                           g_type_name (G_PARAM_SPEC_OBJECT (pspec)->object_type),
+                           "'",
+                           NULL);
+      value->data[0].v_pointer = g_object_ref (object);
+    }
+  else
+    value->data[0].v_pointer = NULL;
+  
+  *collect_type = 0;
+  return NULL;
+}
+
+static gchar*
+param_object_lcopy_value (const GValue *value,
+                         GParamSpec   *pspec,
+                         guint         nth_value,
+                         GType        *collect_type,
+                         GParamCValue *collect_value)
+{
+  GObject **object_p = collect_value->v_pointer;
+  
+  if (!object_p)
+    return g_strdup_printf ("value location for `%s' passed as NULL",
+                           g_type_name (pspec ? G_PARAM_SPEC_TYPE (pspec) : G_VALUE_TYPE (value)));
+  
+  *object_p = value->data[0].v_pointer ? g_object_ref (value->data[0].v_pointer) : NULL;
+  
+  *collect_type = 0;
+  return NULL;
+}
+
+static void
+value_exch_memcpy (GValue *value1,
+                  GValue *value2)
+{
+  GValue tmp_value;
+  memcpy (&tmp_value.data, &value1->data, sizeof (value1->data));
+  memcpy (&value1->data, &value2->data, sizeof (value1->data));
+  memcpy (&value2->data, &tmp_value.data, sizeof (value2->data));
+}
+
+static void
+value_exch_long_int (GValue *value1,
+                    GValue *value2)
+{
+  glong tmp = value1->data[0].v_long;
+  value1->data[0].v_long = value2->data[0].v_int;
+  value2->data[0].v_int = tmp;
+}
+
+static void
+value_exch_long_uint (GValue *value1,
+                     GValue *value2)
+{
+  glong tmp = value1->data[0].v_long;
+  value1->data[0].v_long = value2->data[0].v_uint;
+  value2->data[0].v_uint = tmp;
+}
+
+static void
+value_exch_ulong_int (GValue *value1,
+                     GValue *value2)
+{
+  gulong tmp = value1->data[0].v_ulong;
+  value1->data[0].v_ulong = value2->data[0].v_int;
+  value2->data[0].v_int = tmp;
+}
+
+static void
+value_exch_ulong_uint (GValue *value1,
+                      GValue *value2)
+{
+  gulong tmp = value1->data[0].v_ulong;
+  value1->data[0].v_ulong = value2->data[0].v_uint;
+  value2->data[0].v_uint = tmp;
+}
+
+static void
+value_exch_float_int (GValue *value1,
+                     GValue *value2)
+{
+  gfloat tmp = value1->data[0].v_float;
+  value1->data[0].v_float = value2->data[0].v_int;
+  value2->data[0].v_int = 0.5 + tmp;
+}
+
+static void
+value_exch_float_uint (GValue *value1,
+                      GValue *value2)
+{
+  gfloat tmp = value1->data[0].v_float;
+  value1->data[0].v_float = value2->data[0].v_uint;
+  value2->data[0].v_uint = 0.5 + tmp;
+}
+
+static void
+value_exch_float_long (GValue *value1,
+                      GValue *value2)
+{
+  gfloat tmp = value1->data[0].v_float;
+  value1->data[0].v_float = value2->data[0].v_long;
+  value2->data[0].v_long = 0.5 + tmp;
+}
+
+static void
+value_exch_float_ulong (GValue *value1,
+                       GValue *value2)
+{
+  gfloat tmp = value1->data[0].v_float;
+  value1->data[0].v_float = value2->data[0].v_ulong;
+  value2->data[0].v_ulong = 0.5 + tmp;
+}
+
+static void
+value_exch_double_int (GValue *value1,
+                      GValue *value2)
+{
+  gdouble tmp = value1->data[0].v_double;
+  value1->data[0].v_double = value2->data[0].v_int;
+  value2->data[0].v_int = 0.5 + tmp;
+}
+
+static void
+value_exch_double_uint (GValue *value1,
+                       GValue *value2)
+{
+  gdouble tmp = value1->data[0].v_double;
+  value1->data[0].v_double = value2->data[0].v_uint;
+  value2->data[0].v_uint = 0.5 + tmp;
+}
+
+static void
+value_exch_double_long (GValue *value1,
+                       GValue *value2)
+{
+  gdouble tmp = value1->data[0].v_double;
+  value1->data[0].v_double = value2->data[0].v_long;
+  value2->data[0].v_long = 0.5 + tmp;
+}
+
+static void
+value_exch_double_ulong (GValue *value1,
+                        GValue *value2)
+{
+  gdouble tmp = value1->data[0].v_double;
+  value1->data[0].v_double = value2->data[0].v_ulong;
+  value2->data[0].v_ulong = 0.5 + tmp;
+}
+
+static void
+value_exch_double_float (GValue *value1,
+                        GValue *value2)
+{
+  gdouble tmp = value1->data[0].v_double;
+  value1->data[0].v_double = value2->data[0].v_float;
+  value2->data[0].v_float = tmp;
+}
+
+
+/* --- type initialization --- */
+typedef struct {
+  void         (*finalize)             (GParamSpec   *pspec);
+  void         (*param_init)           (GValue       *value,
+                                        GParamSpec   *pspec);
+  void         (*param_free_value)     (GValue       *value);
+  gboolean     (*param_validate)       (GValue       *value,
+                                        GParamSpec   *pspec);
+  gint         (*param_values_cmp)     (const GValue *value1,
+                                        const GValue *value2,
+                                        GParamSpec   *pspec);
+  void         (*param_copy_value)     (const GValue *src_value,
+                                        GValue       *dest_value);
+  guint                  collect_type;
+  gchar*       (*param_collect_value)  (GValue       *value,
+                                        GParamSpec   *pspec,
+                                        guint         nth_value,
+                                        GType        *collect_type,
+                                        GParamCValue *collect_value);
+  guint                  lcopy_type;
+  gchar*       (*param_lcopy_value)    (const GValue *value,
+                                        GParamSpec   *pspec,
+                                        guint         nth_value,
+                                        GType        *collect_type,
+                                        GParamCValue *collect_value);
+} ParamSpecClassInfo;
+
+static void
+param_spec_class_init (gpointer g_class,
+                      gpointer class_data)
+{
+  GParamSpecClass *class = g_class;
+  ParamSpecClassInfo *info = class_data;
+  
+  if (info->finalize)
+    class->finalize = info->finalize;
+  if (info->param_init)
+    class->param_init = info->param_init;
+  if (info->param_free_value)
+    class->param_free_value = info->param_free_value;
+  if (info->param_validate)
+    class->param_validate = info->param_validate;
+  if (info->param_values_cmp)
+    class->param_values_cmp = info->param_values_cmp;
+  if (info->param_copy_value)
+    class->param_copy_value = info->param_copy_value;
+  class->collect_type = info->collect_type;
+  class->param_collect_value = info->param_collect_value;
+  class->lcopy_type = info->lcopy_type;
+  class->param_lcopy_value = info->param_lcopy_value;
+}
+
+void
+g_param_spec_types_init (void) /* sync with glib-gparam.c */
+{
+  GTypeInfo info = {
+    sizeof (GParamSpecClass),  /* class_size */
+    NULL,                      /* base_init */
+    NULL,                      /* base_destroy */
+    param_spec_class_init,     /* class_init */
+    NULL,                      /* class_destroy */
+    NULL,                      /* class_data */
+    0,                         /* instance_size */
+    16,                                /* n_preallocs */
+    NULL,                      /* instance_init */
+  };
+  GType type;
+  
+  /* G_TYPE_PARAM_CHAR
+   */
+  {
+    static const ParamSpecClassInfo class_info = {
+      NULL,                    /* finalize */
+      param_char_init,         /* param_init */
+      NULL,                    /* param_free_value */
+      param_char_validate,     /* param_validate */
+      param_int_values_cmp,    /* param_values_cmp */
+      NULL,                    /* param_copy_value */
+      G_VALUE_COLLECT_INT,     /* collect_type */
+      param_int_collect_value, /* param_collect_value */
+      G_VALUE_COLLECT_POINTER, /* lcopy_type */
+      param_char_lcopy_value,  /* param_lcopy_value */
+    };
+    info.class_data = &class_info;
+    info.instance_size = sizeof (GParamSpecChar);
+    info.instance_init = (GInstanceInitFunc) param_spec_char_init;
+    type = g_type_register_static (G_TYPE_PARAM, "GParamChar", &info);
+    g_assert (type == G_TYPE_PARAM_CHAR);
+  }
+  
+  /* G_TYPE_PARAM_UCHAR
+   */
+  {
+    static const ParamSpecClassInfo class_info = {
+      NULL,                    /* finalize */
+      param_uchar_init,                /* param_init */
+      NULL,                    /* param_free_value */
+      param_uchar_validate,    /* param_validate */
+      param_uint_values_cmp,   /* param_values_cmp */
+      NULL,                    /* param_copy_value */
+      G_VALUE_COLLECT_INT,     /* collect_type */
+      param_int_collect_value, /* param_collect_value */
+      G_VALUE_COLLECT_POINTER, /* lcopy_type */
+      param_char_lcopy_value,  /* param_lcopy_value */
+    };
+    info.class_data = &class_info;
+    info.instance_size = sizeof (GParamSpecUChar);
+    info.instance_init = (GInstanceInitFunc) param_spec_uchar_init;
+    type = g_type_register_static (G_TYPE_PARAM, "GParamUChar", &info);
+    g_assert (type == G_TYPE_PARAM_UCHAR);
+  }
+  
+  /* G_TYPE_PARAM_BOOL
+   */
+  {
+    static const ParamSpecClassInfo class_info = {
+      NULL,                    /* finalize */
+      param_bool_init,         /* param_init */
+      NULL,                    /* param_free_value */
+      param_bool_validate,     /* param_validate */
+      param_int_values_cmp,    /* param_values_cmp */
+      NULL,                    /* param_copy_value */
+      G_VALUE_COLLECT_INT,     /* collect_type */
+      param_int_collect_value, /* param_collect_value */
+      G_VALUE_COLLECT_POINTER, /* lcopy_type */
+      param_bool_lcopy_value,  /* param_lcopy_value */
+    };
+    info.class_data = &class_info;
+    info.instance_size = sizeof (GParamSpecBool);
+    info.instance_init = (GInstanceInitFunc) NULL;
+    type = g_type_register_static (G_TYPE_PARAM, "GParamBool", &info);
+    g_assert (type == G_TYPE_PARAM_BOOL);
+  }
+  
+  /* G_TYPE_PARAM_INT
+   */
+  {
+    static const ParamSpecClassInfo class_info = {
+      NULL,                    /* finalize */
+      param_int_init,          /* param_init */
+      NULL,                    /* param_free_value */
+      param_int_validate,      /* param_validate */
+      param_int_values_cmp,    /* param_values_cmp */
+      NULL,                    /* param_copy_value */
+      G_VALUE_COLLECT_INT,     /* collect_type */
+      param_int_collect_value, /* param_collect_value */
+      G_VALUE_COLLECT_POINTER, /* lcopy_type */
+      param_int_lcopy_value,   /* param_lcopy_value */
+    };
+    info.class_data = &class_info;
+    info.instance_size = sizeof (GParamSpecInt);
+    info.instance_init = (GInstanceInitFunc) param_spec_int_init;
+    type = g_type_register_static (G_TYPE_PARAM, "GParamInt", &info);
+    g_assert (type == G_TYPE_PARAM_INT);
+  }
+  
+  /* G_TYPE_PARAM_UINT
+   */
+  {
+    static const ParamSpecClassInfo class_info = {
+      NULL,                    /* finalize */
+      param_uint_init,         /* param_init */
+      NULL,                    /* param_free_value */
+      param_uint_validate,     /* param_validate */
+      param_uint_values_cmp,   /* param_values_cmp */
+      NULL,                    /* param_copy_value */
+      G_VALUE_COLLECT_INT,     /* collect_type */
+      param_int_collect_value, /* param_collect_value */
+      G_VALUE_COLLECT_POINTER, /* lcopy_type */
+      param_int_lcopy_value,   /* param_lcopy_value */
+    };
+    info.class_data = &class_info;
+    info.instance_size = sizeof (GParamSpecUInt);
+    info.instance_init = (GInstanceInitFunc) param_spec_uint_init;
+    type = g_type_register_static (G_TYPE_PARAM, "GParamUInt", &info);
+    g_assert (type == G_TYPE_PARAM_UINT);
+  }
+  
+  /* G_TYPE_PARAM_LONG
+   */
+  {
+    static const ParamSpecClassInfo class_info = {
+      NULL,                    /* finalize */
+      param_long_init,         /* param_init */
+      NULL,                    /* param_free_value */
+      param_long_validate,     /* param_validate */
+      param_long_values_cmp,   /* param_values_cmp */
+      NULL,                    /* param_copy_value */
+      G_VALUE_COLLECT_LONG,    /* collect_type */
+      param_long_collect_value,        /* param_collect_value */
+      G_VALUE_COLLECT_POINTER, /* lcopy_type */
+      param_long_lcopy_value,  /* param_lcopy_value */
+    };
+    info.class_data = &class_info;
+    info.instance_size = sizeof (GParamSpecLong);
+    info.instance_init = (GInstanceInitFunc) param_spec_long_init;
+    type = g_type_register_static (G_TYPE_PARAM, "GParamLong", &info);
+    g_assert (type == G_TYPE_PARAM_LONG);
+  }
+  
+  /* G_TYPE_PARAM_ULONG
+   */
+  {
+    static const ParamSpecClassInfo class_info = {
+      NULL,                    /* finalize */
+      param_ulong_init,                /* param_init */
+      NULL,                    /* param_free_value */
+      param_ulong_validate,    /* param_validate */
+      param_ulong_values_cmp,  /* param_values_cmp */
+      NULL,                    /* param_copy_value */
+      G_VALUE_COLLECT_LONG,    /* collect_type */
+      param_long_collect_value,        /* param_collect_value */
+      G_VALUE_COLLECT_POINTER, /* lcopy_type */
+      param_long_lcopy_value,  /* param_lcopy_value */
+    };
+    info.class_data = &class_info;
+    info.instance_size = sizeof (GParamSpecULong);
+    info.instance_init = (GInstanceInitFunc) param_spec_ulong_init;
+    type = g_type_register_static (G_TYPE_PARAM, "GParamULong", &info);
+    g_assert (type == G_TYPE_PARAM_ULONG);
+  }
+  
+  /* G_TYPE_PARAM_ENUM
+   */
+  {
+    static const ParamSpecClassInfo class_info = {
+      param_spec_enum_finalize,        /* finalize */
+      param_enum_init,         /* param_init */
+      NULL,                    /* param_free_value */
+      param_enum_validate,     /* param_validate */
+      param_long_values_cmp,   /* param_values_cmp */
+      NULL,                    /* param_copy_value */
+      G_VALUE_COLLECT_INT,     /* collect_type */
+      param_enum_collect_value,        /* param_collect_value */
+      G_VALUE_COLLECT_POINTER, /* lcopy_type */
+      param_enum_lcopy_value,  /* param_lcopy_value */
+    };
+    info.class_data = &class_info;
+    info.instance_size = sizeof (GParamSpecEnum);
+    info.instance_init = (GInstanceInitFunc) param_spec_enum_init;
+    type = g_type_register_static (G_TYPE_PARAM, "GParamEnum", &info);
+    g_assert (type == G_TYPE_PARAM_ENUM);
+  }
+  
+  /* G_TYPE_PARAM_FLAGS
+   */
+  {
+    static const ParamSpecClassInfo class_info = {
+      param_spec_flags_finalize,/* finalize */
+      param_flags_init,                /* param_init */
+      NULL,                    /* param_free_value */
+      param_flags_validate,    /* param_validate */
+      param_ulong_values_cmp,  /* param_values_cmp */
+      NULL,                    /* param_copy_value */
+      G_VALUE_COLLECT_INT,     /* collect_type */
+      param_enum_collect_value,        /* param_collect_value */
+      G_VALUE_COLLECT_POINTER, /* lcopy_type */
+      param_enum_lcopy_value,  /* param_lcopy_value */
+    };
+    info.class_data = &class_info;
+    info.instance_size = sizeof (GParamSpecFlags);
+    info.instance_init = (GInstanceInitFunc) param_spec_flags_init;
+    type = g_type_register_static (G_TYPE_PARAM, "GParamFlags", &info);
+    g_assert (type == G_TYPE_PARAM_FLAGS);
+  }
+  
+  /* G_TYPE_PARAM_FLOAT
+   */
+  {
+    static const ParamSpecClassInfo class_info = {
+      NULL,                    /* finalize */
+      param_float_init,                /* param_init */
+      NULL,                    /* param_free_value */
+      param_float_validate,    /* param_validate */
+      param_float_values_cmp,  /* param_values_cmp */
+      NULL,                    /* param_copy_value */
+      G_VALUE_COLLECT_DOUBLE,  /* collect_type */
+      param_float_collect_value,/* param_collect_value */
+      G_VALUE_COLLECT_POINTER, /* lcopy_type */
+      param_float_lcopy_value, /* param_lcopy_value */
+    };
+    info.class_data = &class_info;
+    info.instance_size = sizeof (GParamSpecFloat);
+    info.instance_init = (GInstanceInitFunc) param_spec_float_init;
+    type = g_type_register_static (G_TYPE_PARAM, "GParamFloat", &info);
+    g_assert (type == G_TYPE_PARAM_FLOAT);
+  }
+  
+  /* G_TYPE_PARAM_DOUBLE
+   */
+  {
+    static const ParamSpecClassInfo class_info = {
+      NULL,                      /* finalize */
+      param_double_init,         /* param_init */
+      NULL,                      /* param_free_value */
+      param_double_validate,     /* param_validate */
+      param_double_values_cmp,   /* param_values_cmp */
+      NULL,                      /* param_copy_value */
+      G_VALUE_COLLECT_DOUBLE,    /* collect_type */
+      param_double_collect_value, /* param_collect_value */
+      G_VALUE_COLLECT_POINTER,   /* lcopy_type */
+      param_double_lcopy_value,          /* param_lcopy_value */
+    };
+    info.class_data = &class_info;
+    info.instance_size = sizeof (GParamSpecDouble);
+    info.instance_init = (GInstanceInitFunc) param_spec_double_init;
+    type = g_type_register_static (G_TYPE_PARAM, "GParamDouble", &info);
+    g_assert (type == G_TYPE_PARAM_DOUBLE);
+  }
+  
+  /* G_TYPE_PARAM_STRING
+   */
+  {
+    static const ParamSpecClassInfo class_info = {
+      param_spec_string_finalize, /* finalize */
+      param_string_init,         /* param_init */
+      param_string_free_value,   /* param_free_value */
+      param_string_validate,     /* param_validate */
+      param_string_values_cmp,   /* param_values_cmp */
+      param_string_copy_value,   /* param_copy_value */
+      G_VALUE_COLLECT_POINTER,   /* collect_type */
+      param_string_collect_value, /* param_collect_value */
+      G_VALUE_COLLECT_POINTER,   /* lcopy_type */
+      param_string_lcopy_value,          /* param_lcopy_value */
+    };
+    info.class_data = &class_info;
+    info.instance_size = sizeof (GParamSpecString);
+    info.instance_init = (GInstanceInitFunc) param_spec_string_init;
+    type = g_type_register_static (G_TYPE_PARAM, "GParamString", &info);
+    g_assert (type == G_TYPE_PARAM_STRING);
+  }
+  
+  /* G_TYPE_PARAM_OBJECT
+   */
+  {
+    static const ParamSpecClassInfo class_info = {
+      NULL,                      /* finalize */
+      param_object_init,         /* param_init */
+      param_object_free_value,   /* param_free_value */
+      param_object_validate,     /* param_validate */
+      param_object_values_cmp,   /* param_values_cmp */
+      param_object_copy_value,   /* param_copy_value */
+      G_VALUE_COLLECT_POINTER,   /* collect_type */
+      param_object_collect_value, /* param_collect_value */
+      G_VALUE_COLLECT_POINTER,   /* lcopy_type */
+      param_object_lcopy_value,          /* param_lcopy_value */
+    };
+    info.class_data = &class_info;
+    info.instance_size = sizeof (GParamSpecObject);
+    info.instance_init = (GInstanceInitFunc) param_spec_object_init;
+    type = g_type_register_static (G_TYPE_PARAM, "GParamObject", &info);
+    g_assert (type == G_TYPE_PARAM_OBJECT);
+  }
+  
+  g_value_register_exchange_func (G_TYPE_PARAM_CHAR,   G_TYPE_PARAM_UCHAR,  value_exch_memcpy);
+  g_value_register_exchange_func (G_TYPE_PARAM_CHAR,   G_TYPE_PARAM_BOOL,   value_exch_memcpy);
+  g_value_register_exchange_func (G_TYPE_PARAM_CHAR,   G_TYPE_PARAM_INT,    value_exch_memcpy);
+  g_value_register_exchange_func (G_TYPE_PARAM_CHAR,   G_TYPE_PARAM_UINT,   value_exch_memcpy);
+  g_value_register_exchange_func (G_TYPE_PARAM_CHAR,   G_TYPE_PARAM_ENUM,   value_exch_memcpy);
+  g_value_register_exchange_func (G_TYPE_PARAM_CHAR,   G_TYPE_PARAM_FLAGS,  value_exch_memcpy); 
+  g_value_register_exchange_func (G_TYPE_PARAM_UCHAR,  G_TYPE_PARAM_BOOL,   value_exch_memcpy);
+  g_value_register_exchange_func (G_TYPE_PARAM_UCHAR,  G_TYPE_PARAM_INT,    value_exch_memcpy);
+  g_value_register_exchange_func (G_TYPE_PARAM_UCHAR,  G_TYPE_PARAM_UINT,   value_exch_memcpy);
+  g_value_register_exchange_func (G_TYPE_PARAM_UCHAR,  G_TYPE_PARAM_ENUM,   value_exch_memcpy);
+  g_value_register_exchange_func (G_TYPE_PARAM_UCHAR,  G_TYPE_PARAM_FLAGS,  value_exch_memcpy); 
+  g_value_register_exchange_func (G_TYPE_PARAM_BOOL,   G_TYPE_PARAM_INT,    value_exch_memcpy);
+  g_value_register_exchange_func (G_TYPE_PARAM_BOOL,   G_TYPE_PARAM_UINT,   value_exch_memcpy);
+  g_value_register_exchange_func (G_TYPE_PARAM_BOOL,   G_TYPE_PARAM_ENUM,   value_exch_memcpy);
+  g_value_register_exchange_func (G_TYPE_PARAM_BOOL,   G_TYPE_PARAM_FLAGS,  value_exch_memcpy); 
+  g_value_register_exchange_func (G_TYPE_PARAM_INT,    G_TYPE_PARAM_UINT,   value_exch_memcpy); 
+  g_value_register_exchange_func (G_TYPE_PARAM_INT,    G_TYPE_PARAM_ENUM,   value_exch_memcpy); 
+  g_value_register_exchange_func (G_TYPE_PARAM_INT,    G_TYPE_PARAM_FLAGS,  value_exch_memcpy); 
+  g_value_register_exchange_func (G_TYPE_PARAM_UINT,   G_TYPE_PARAM_ENUM,   value_exch_memcpy); 
+  g_value_register_exchange_func (G_TYPE_PARAM_UINT,   G_TYPE_PARAM_FLAGS,  value_exch_memcpy); 
+  g_value_register_exchange_func (G_TYPE_PARAM_LONG,   G_TYPE_PARAM_CHAR,   value_exch_long_int); 
+  g_value_register_exchange_func (G_TYPE_PARAM_LONG,   G_TYPE_PARAM_UCHAR,  value_exch_long_uint); 
+  g_value_register_exchange_func (G_TYPE_PARAM_LONG,   G_TYPE_PARAM_BOOL,   value_exch_long_int); 
+  g_value_register_exchange_func (G_TYPE_PARAM_LONG,   G_TYPE_PARAM_INT,    value_exch_long_int); 
+  g_value_register_exchange_func (G_TYPE_PARAM_LONG,   G_TYPE_PARAM_UINT,   value_exch_long_uint); 
+  g_value_register_exchange_func (G_TYPE_PARAM_LONG,   G_TYPE_PARAM_ULONG,  value_exch_memcpy); 
+  g_value_register_exchange_func (G_TYPE_PARAM_LONG,   G_TYPE_PARAM_ENUM,   value_exch_long_int); 
+  g_value_register_exchange_func (G_TYPE_PARAM_LONG,   G_TYPE_PARAM_FLAGS,  value_exch_long_uint); 
+  g_value_register_exchange_func (G_TYPE_PARAM_ULONG,  G_TYPE_PARAM_CHAR,   value_exch_ulong_int); 
+  g_value_register_exchange_func (G_TYPE_PARAM_ULONG,  G_TYPE_PARAM_UCHAR,  value_exch_ulong_uint); 
+  g_value_register_exchange_func (G_TYPE_PARAM_ULONG,  G_TYPE_PARAM_BOOL,   value_exch_ulong_int); 
+  g_value_register_exchange_func (G_TYPE_PARAM_ULONG,  G_TYPE_PARAM_INT,    value_exch_ulong_int); 
+  g_value_register_exchange_func (G_TYPE_PARAM_ULONG,  G_TYPE_PARAM_UINT,   value_exch_ulong_uint); 
+  g_value_register_exchange_func (G_TYPE_PARAM_ULONG,  G_TYPE_PARAM_ENUM,   value_exch_ulong_int); 
+  g_value_register_exchange_func (G_TYPE_PARAM_ULONG,  G_TYPE_PARAM_FLAGS,  value_exch_ulong_uint); 
+  g_value_register_exchange_func (G_TYPE_PARAM_ENUM,   G_TYPE_PARAM_FLAGS,  value_exch_memcpy); 
+  g_value_register_exchange_func (G_TYPE_PARAM_FLOAT,  G_TYPE_PARAM_CHAR,   value_exch_float_int); 
+  g_value_register_exchange_func (G_TYPE_PARAM_FLOAT,  G_TYPE_PARAM_UCHAR,  value_exch_float_uint); 
+  g_value_register_exchange_func (G_TYPE_PARAM_FLOAT,  G_TYPE_PARAM_BOOL,   value_exch_float_int); 
+  g_value_register_exchange_func (G_TYPE_PARAM_FLOAT,  G_TYPE_PARAM_INT,    value_exch_float_int); 
+  g_value_register_exchange_func (G_TYPE_PARAM_FLOAT,  G_TYPE_PARAM_UINT,   value_exch_float_uint); 
+  g_value_register_exchange_func (G_TYPE_PARAM_FLOAT,  G_TYPE_PARAM_LONG,   value_exch_float_long); 
+  g_value_register_exchange_func (G_TYPE_PARAM_FLOAT,  G_TYPE_PARAM_ULONG,  value_exch_float_ulong);
+  g_value_register_exchange_func (G_TYPE_PARAM_FLOAT,  G_TYPE_PARAM_ENUM,   value_exch_float_int); 
+  g_value_register_exchange_func (G_TYPE_PARAM_FLOAT,  G_TYPE_PARAM_FLAGS,  value_exch_float_uint); 
+  g_value_register_exchange_func (G_TYPE_PARAM_DOUBLE, G_TYPE_PARAM_CHAR,   value_exch_double_int); 
+  g_value_register_exchange_func (G_TYPE_PARAM_DOUBLE, G_TYPE_PARAM_UCHAR,  value_exch_double_uint); 
+  g_value_register_exchange_func (G_TYPE_PARAM_DOUBLE, G_TYPE_PARAM_BOOL,   value_exch_double_int); 
+  g_value_register_exchange_func (G_TYPE_PARAM_DOUBLE, G_TYPE_PARAM_INT,    value_exch_double_int); 
+  g_value_register_exchange_func (G_TYPE_PARAM_DOUBLE, G_TYPE_PARAM_UINT,   value_exch_double_uint); 
+  g_value_register_exchange_func (G_TYPE_PARAM_DOUBLE, G_TYPE_PARAM_LONG,   value_exch_double_long);
+  g_value_register_exchange_func (G_TYPE_PARAM_DOUBLE, G_TYPE_PARAM_ULONG,  value_exch_double_ulong);
+  g_value_register_exchange_func (G_TYPE_PARAM_DOUBLE, G_TYPE_PARAM_ENUM,   value_exch_double_int); 
+  g_value_register_exchange_func (G_TYPE_PARAM_DOUBLE, G_TYPE_PARAM_FLAGS,  value_exch_double_uint);
+  g_value_register_exchange_func (G_TYPE_PARAM_DOUBLE, G_TYPE_PARAM_FLOAT,  value_exch_double_float); 
+}
+
+
+/* --- GValue functions --- */
+void
+g_value_set_char (GValue *value,
+                 gint8   v_char)
+{
+  g_return_if_fail (G_IS_VALUE_CHAR (value));
+  
+  value->data[0].v_int = v_char;
+}
+
+gint8
+g_value_get_char (GValue *value)
+{
+  g_return_val_if_fail (G_IS_VALUE_CHAR (value), 0);
+  
+  return value->data[0].v_int;
+}
+
+void
+g_value_set_uchar (GValue *value,
+                  guint8  v_uchar)
+{
+  g_return_if_fail (G_IS_VALUE_UCHAR (value));
+  
+  value->data[0].v_uint = v_uchar;
+}
+
+guint8
+g_value_get_uchar (GValue *value)
+{
+  g_return_val_if_fail (G_IS_VALUE_UCHAR (value), 0);
+  
+  return value->data[0].v_uint;
+}
+
+void
+g_value_set_bool (GValue  *value,
+                 gboolean v_bool)
+{
+  g_return_if_fail (G_IS_VALUE_BOOL (value));
+  
+  value->data[0].v_int = v_bool;
+}
+
+gboolean
+g_value_get_bool (GValue *value)
+{
+  g_return_val_if_fail (G_IS_VALUE_BOOL (value), 0);
+  
+  return value->data[0].v_int;
+}
+
+void
+g_value_set_int (GValue *value,
+                gint    v_int)
+{
+  g_return_if_fail (G_IS_VALUE_INT (value));
+  
+  value->data[0].v_int = v_int;
+}
+
+gint
+g_value_get_int (GValue *value)
+{
+  g_return_val_if_fail (G_IS_VALUE_INT (value), 0);
+  
+  return value->data[0].v_int;
+}
+
+void
+g_value_set_uint (GValue *value,
+                 guint   v_uint)
+{
+  g_return_if_fail (G_IS_VALUE_UINT (value));
+  
+  value->data[0].v_uint = v_uint;
+}
+
+guint
+g_value_get_uint (GValue *value)
+{
+  g_return_val_if_fail (G_IS_VALUE_UINT (value), 0);
+  
+  return value->data[0].v_uint;
+}
+
+void
+g_value_set_long (GValue *value,
+                 glong   v_long)
+{
+  g_return_if_fail (G_IS_VALUE_LONG (value));
+  
+  value->data[0].v_long = v_long;
+}
+
+glong
+g_value_get_long (GValue *value)
+{
+  g_return_val_if_fail (G_IS_VALUE_LONG (value), 0);
+  
+  return value->data[0].v_long;
+}
+
+void
+g_value_set_ulong (GValue *value,
+                  gulong  v_ulong)
+{
+  g_return_if_fail (G_IS_VALUE_ULONG (value));
+  
+  value->data[0].v_ulong = v_ulong;
+}
+
+gulong
+g_value_get_ulong (GValue *value)
+{
+  g_return_val_if_fail (G_IS_VALUE_ULONG (value), 0);
+  
+  return value->data[0].v_ulong;
+}
+
+void
+g_value_set_enum (GValue *value,
+                 gint    v_enum)
+{
+  g_return_if_fail (G_IS_VALUE_ENUM (value));
+  
+  value->data[0].v_long = v_enum;
+}
+
+gint
+g_value_get_enum (GValue *value)
+{
+  g_return_val_if_fail (G_IS_VALUE_ENUM (value), 0);
+  
+  return value->data[0].v_long;
+}
+
+void
+g_value_set_flags (GValue *value,
+                  guint   v_flags)
+{
+  g_return_if_fail (G_IS_VALUE_FLAGS (value));
+  
+  value->data[0].v_ulong = v_flags;
+}
+
+guint
+g_value_get_flags (GValue *value)
+{
+  g_return_val_if_fail (G_IS_VALUE_FLAGS (value), 0);
+  
+  return value->data[0].v_ulong;
+}
+
+void
+g_value_set_float (GValue *value,
+                  gfloat  v_float)
+{
+  g_return_if_fail (G_IS_VALUE_FLOAT (value));
+  
+  value->data[0].v_float = v_float;
+}
+
+gfloat
+g_value_get_float (GValue *value)
+{
+  g_return_val_if_fail (G_IS_VALUE_FLOAT (value), 0);
+  
+  return value->data[0].v_float;
+}
+
+void
+g_value_set_double (GValue *value,
+                   gdouble v_double)
+{
+  g_return_if_fail (G_IS_VALUE_DOUBLE (value));
+  
+  value->data[0].v_double = v_double;
+}
+
+gdouble
+g_value_get_double (GValue *value)
+{
+  g_return_val_if_fail (G_IS_VALUE_DOUBLE (value), 0);
+  
+  return value->data[0].v_double;
+}
+
+void
+g_value_set_string (GValue     *value,
+                   const gchar *v_string)
+{
+  g_return_if_fail (G_IS_VALUE_STRING (value));
+  
+  g_free (value->data[0].v_pointer);
+  value->data[0].v_pointer = g_strdup (v_string);
+}
+
+gchar*
+g_value_get_string (GValue *value)
+{
+  g_return_val_if_fail (G_IS_VALUE_STRING (value), NULL);
+  
+  return value->data[0].v_pointer;
+}
+
+gchar*
+g_value_dup_string (GValue *value)
+{
+  g_return_val_if_fail (G_IS_VALUE_STRING (value), NULL);
+  
+  return g_strdup (value->data[0].v_pointer);
+}
+
+void
+g_value_set_object (GValue  *value,
+                   GObject *v_object)
+{
+  g_return_if_fail (G_IS_VALUE_OBJECT (value));
+  if (v_object)
+    g_return_if_fail (G_IS_OBJECT (v_object));
+  
+  if (value->data[0].v_pointer)
+    g_object_unref (value->data[0].v_pointer);
+  value->data[0].v_pointer = v_object;
+  if (value->data[0].v_pointer)
+    g_object_ref (value->data[0].v_pointer);
+}
+
+GObject*
+g_value_get_object (GValue *value)
+{
+  g_return_val_if_fail (G_IS_VALUE_OBJECT (value), NULL);
+  
+  return value->data[0].v_pointer;
+}
+
+GObject*
+g_value_dup_object (GValue *value)
+{
+  g_return_val_if_fail (G_IS_VALUE_OBJECT (value), NULL);
+  
+  return value->data[0].v_pointer ? g_object_ref (value->data[0].v_pointer) : NULL;
+}
+
+
+/* --- GParamSpec initialization --- */
+GParamSpec*
+g_param_spec_char (const gchar *name,
+                  const gchar *nick,
+                  const gchar *blurb,
+                  gint8        minimum,
+                  gint8        maximum,
+                  gint8        default_value,
+                  GParamFlags  flags)
+{
+  GParamSpecChar *cspec = g_param_spec_internal (G_TYPE_PARAM_CHAR,
+                                                name,
+                                                nick,
+                                                blurb,
+                                                flags);
+  
+  cspec->minimum = minimum;
+  cspec->maximum = maximum;
+  cspec->default_value = default_value;
+  
+  return G_PARAM_SPEC (cspec);
+}
+
+GParamSpec*
+g_param_spec_uchar (const gchar *name,
+                   const gchar *nick,
+                   const gchar *blurb,
+                   guint8       minimum,
+                   guint8       maximum,
+                   guint8       default_value,
+                   GParamFlags  flags)
+{
+  GParamSpecUChar *uspec = g_param_spec_internal (G_TYPE_PARAM_UCHAR,
+                                                 name,
+                                                 nick,
+                                                 blurb,
+                                                 flags);
+  
+  uspec->minimum = minimum;
+  uspec->maximum = maximum;
+  uspec->default_value = default_value;
+  
+  return G_PARAM_SPEC (uspec);
+}
+
+GParamSpec*
+g_param_spec_bool (const gchar *name,
+                  const gchar *nick,
+                  const gchar *blurb,
+                  gboolean     default_value,
+                  GParamFlags  flags)
+{
+  GParamSpecBool *bspec = g_param_spec_internal (G_TYPE_PARAM_BOOL,
+                                                name,
+                                                nick,
+                                                blurb,
+                                                flags);
+  
+  bspec->default_value = default_value;
+  
+  return G_PARAM_SPEC (bspec);
+}
+
+GParamSpec*
+g_param_spec_int (const gchar *name,
+                 const gchar *nick,
+                 const gchar *blurb,
+                 gint         minimum,
+                 gint         maximum,
+                 gint         default_value,
+                 GParamFlags  flags)
+{
+  GParamSpecInt *ispec = g_param_spec_internal (G_TYPE_PARAM_INT,
+                                               name,
+                                               nick,
+                                               blurb,
+                                               flags);
+  
+  ispec->minimum = minimum;
+  ispec->maximum = maximum;
+  ispec->default_value = default_value;
+  
+  return G_PARAM_SPEC (ispec);
+}
+
+GParamSpec*
+g_param_spec_uint (const gchar *name,
+                  const gchar *nick,
+                  const gchar *blurb,
+                  guint        minimum,
+                  guint        maximum,
+                  guint        default_value,
+                  GParamFlags  flags)
+{
+  GParamSpecUInt *uspec = g_param_spec_internal (G_TYPE_PARAM_UINT,
+                                                name,
+                                                nick,
+                                                blurb,
+                                                flags);
+  
+  uspec->minimum = minimum;
+  uspec->maximum = maximum;
+  uspec->default_value = default_value;
+  
+  return G_PARAM_SPEC (uspec);
+}
+
+GParamSpec*
+g_param_spec_long (const gchar *name,
+                  const gchar *nick,
+                  const gchar *blurb,
+                  glong        minimum,
+                  glong        maximum,
+                  glong        default_value,
+                  GParamFlags  flags)
+{
+  GParamSpecLong *lspec = g_param_spec_internal (G_TYPE_PARAM_LONG,
+                                                name,
+                                                nick,
+                                                blurb,
+                                                flags);
+  
+  lspec->minimum = minimum;
+  lspec->maximum = maximum;
+  lspec->default_value = default_value;
+  
+  return G_PARAM_SPEC (lspec);
+}
+
+GParamSpec*
+g_param_spec_ulong (const gchar *name,
+                   const gchar *nick,
+                   const gchar *blurb,
+                   gulong       minimum,
+                   gulong       maximum,
+                   gulong       default_value,
+                   GParamFlags  flags)
+{
+  GParamSpecULong *uspec = g_param_spec_internal (G_TYPE_PARAM_ULONG,
+                                                 name,
+                                                 nick,
+                                                 blurb,
+                                                 flags);
+  
+  uspec->minimum = minimum;
+  uspec->maximum = maximum;
+  uspec->default_value = default_value;
+  
+  return G_PARAM_SPEC (uspec);
+}
+
+GParamSpec*
+g_param_spec_enum (const gchar *name,
+                  const gchar *nick,
+                  const gchar *blurb,
+                  GType        enum_type,
+                  gint         default_value,
+                  GParamFlags  flags)
+{
+  GParamSpecEnum *espec;
+  
+  g_return_val_if_fail (G_TYPE_IS_ENUM (enum_type), NULL);
+  
+  espec = g_param_spec_internal (G_TYPE_PARAM_ENUM,
+                                name,
+                                nick,
+                                blurb,
+                                flags);
+  
+  espec->enum_class = g_type_class_ref (enum_type);
+  espec->default_value = default_value;
+  
+  return G_PARAM_SPEC (espec);
+}
+
+GParamSpec*
+g_param_spec_flags (const gchar *name,
+                   const gchar *nick,
+                   const gchar *blurb,
+                   GType        flags_type,
+                   guint        default_value,
+                   GParamFlags  flags)
+{
+  GParamSpecFlags *fspec;
+  
+  g_return_val_if_fail (G_TYPE_IS_FLAGS (flags_type), NULL);
+  
+  fspec = g_param_spec_internal (G_TYPE_PARAM_FLAGS,
+                                name,
+                                nick,
+                                blurb,
+                                flags);
+  
+  fspec->flags_class = g_type_class_ref (flags_type);
+  fspec->default_value = default_value;
+  
+  return G_PARAM_SPEC (fspec);
+}
+
+GParamSpec*
+g_param_spec_float (const gchar *name,
+                   const gchar *nick,
+                   const gchar *blurb,
+                   gfloat       minimum,
+                   gfloat       maximum,
+                   gfloat       default_value,
+                   GParamFlags  flags)
+{
+  GParamSpecFloat *fspec = g_param_spec_internal (G_TYPE_PARAM_FLOAT,
+                                                 name,
+                                                 nick,
+                                                 blurb,
+                                                 flags);
+  
+  fspec->minimum = minimum;
+  fspec->maximum = maximum;
+  fspec->default_value = default_value;
+  
+  return G_PARAM_SPEC (fspec);
+}
+
+GParamSpec*
+g_param_spec_double (const gchar *name,
+                    const gchar *nick,
+                    const gchar *blurb,
+                    gdouble      minimum,
+                    gdouble      maximum,
+                    gdouble      default_value,
+                    GParamFlags  flags)
+{
+  GParamSpecDouble *dspec = g_param_spec_internal (G_TYPE_PARAM_DOUBLE,
+                                                  name,
+                                                  nick,
+                                                  blurb,
+                                                  flags);
+  
+  dspec->minimum = minimum;
+  dspec->maximum = maximum;
+  dspec->default_value = default_value;
+  
+  return G_PARAM_SPEC (dspec);
+}
+
+GParamSpec*
+g_param_spec_string (const gchar *name,
+                    const gchar *nick,
+                    const gchar *blurb,
+                    const gchar *default_value,
+                    GParamFlags  flags)
+{
+  GParamSpecString *sspec = g_param_spec_internal (G_TYPE_PARAM_STRING,
+                                                  name,
+                                                  nick,
+                                                  blurb,
+                                                  flags);
+  g_free (sspec->default_value);
+  sspec->default_value = g_strdup (default_value);
+  
+  return G_PARAM_SPEC (sspec);
+}
+
+GParamSpec*
+g_param_spec_string_c (const gchar *name,
+                      const gchar *nick,
+                      const gchar *blurb,
+                      const gchar *default_value,
+                      GParamFlags  flags)
+{
+  GParamSpecString *sspec = g_param_spec_internal (G_TYPE_PARAM_STRING,
+                                                  name,
+                                                  nick,
+                                                  blurb,
+                                                  flags);
+  g_free (sspec->default_value);
+  sspec->default_value = g_strdup (default_value);
+  g_free (sspec->cset_first);
+  sspec->cset_first = g_strdup (G_CSET_a_2_z "_" G_CSET_A_2_Z);
+  g_free (sspec->cset_nth);
+  sspec->cset_nth = g_strdup (G_CSET_a_2_z
+                             "_0123456789"
+                             /* G_CSET_LATINS G_CSET_LATINC */
+                             G_CSET_A_2_Z);
+  
+  return G_PARAM_SPEC (sspec);
+}
+
+GParamSpec*
+g_param_spec_object (const gchar *name,
+                    const gchar *nick,
+                    const gchar *blurb,
+                    GType        object_type,
+                    GParamFlags  flags)
+{
+  GParamSpecObject *ospec;
+  
+  g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL);
+  
+  ospec = g_param_spec_internal (G_TYPE_PARAM_OBJECT,
+                                name,
+                                nick,
+                                blurb,
+                                flags);
+  ospec->object_type = object_type;
+  
+  return G_PARAM_SPEC (ospec);
+}
diff --git a/gobject/gparamspecs.h b/gobject/gparamspecs.h
new file mode 100644 (file)
index 0000000..1becdef
--- /dev/null
@@ -0,0 +1,335 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 1997, 1998, 1999, 2000 Tim Janik and Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * gparamspecs.h: GLib default param specs
+ */
+#ifndef __G_PARAMSPECS_H__
+#define __G_PARAMSPECS_H__
+
+
+#include        <gobject/gvalue.h>
+#include        <gobject/genums.h>
+#include        <gobject/gobject.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* --- type macros --- */
+#define G_IS_VALUE_CHAR(value)          (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_PARAM_CHAR))
+#define G_IS_PARAM_SPEC_CHAR(pspec)     (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_CHAR))
+#define G_PARAM_SPEC_CHAR(pspec)        (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_CHAR, GParamSpecChar))
+#define G_IS_VALUE_UCHAR(value)         (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_PARAM_UCHAR))
+#define G_IS_PARAM_SPEC_UCHAR(pspec)    (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_UCHAR))
+#define G_PARAM_SPEC_UCHAR(pspec)       (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_UCHAR, GParamSpecUChar))
+#define G_IS_VALUE_BOOL(value)          (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_PARAM_BOOL))
+#define G_IS_PARAM_SPEC_BOOL(pspec)     (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_BOOL))
+#define G_PARAM_SPEC_BOOL(pspec)        (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_BOOL, GParamSpecBool))
+#define G_IS_VALUE_INT(value)           (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_PARAM_INT))
+#define G_IS_PARAM_SPEC_INT(pspec)      (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_INT))
+#define G_PARAM_SPEC_INT(pspec)         (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_INT, GParamSpecInt))
+#define G_IS_VALUE_UINT(value)          (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_PARAM_UINT))
+#define G_IS_PARAM_SPEC_UINT(pspec)     (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_UINT))
+#define G_PARAM_SPEC_UINT(pspec)        (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_UINT, GParamSpecUInt))
+#define G_IS_VALUE_LONG(value)          (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_PARAM_LONG))
+#define G_IS_PARAM_SPEC_LONG(pspec)     (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_LONG))
+#define G_PARAM_SPEC_LONG(pspec)        (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_LONG, GParamSpecLong))
+#define G_IS_VALUE_ULONG(value)         (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_PARAM_ULONG))
+#define G_IS_PARAM_SPEC_ULONG(pspec)    (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_ULONG))
+#define G_PARAM_SPEC_ULONG(pspec)       (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_ULONG, GParamSpecULong))
+#define G_IS_VALUE_ENUM(value)          (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_PARAM_ENUM))
+#define G_IS_PARAM_SPEC_ENUM(pspec)     (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_ENUM))
+#define G_PARAM_SPEC_ENUM(pspec)        (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_ENUM, GParamSpecEnum))
+#define G_IS_VALUE_FLAGS(value)         (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_PARAM_FLAGS))
+#define G_IS_PARAM_SPEC_FLAGS(pspec)    (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_FLAGS))
+#define G_PARAM_SPEC_FLAGS(pspec)       (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_FLAGS, GParamSpecFlags))
+#define G_IS_VALUE_FLOAT(value)         (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_PARAM_FLOAT))
+#define G_IS_PARAM_SPEC_FLOAT(pspec)    (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_FLOAT))
+#define G_PARAM_SPEC_FLOAT(pspec)       (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_FLOAT, GParamSpecFloat))
+#define G_IS_VALUE_DOUBLE(value)        (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_PARAM_DOUBLE))
+#define G_IS_PARAM_SPEC_DOUBLE(pspec)   (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_DOUBLE))
+#define G_PARAM_SPEC_DOUBLE(pspec)      (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_DOUBLE, GParamSpecDouble))
+#define G_IS_VALUE_STRING(value)        (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_PARAM_STRING))
+#define G_IS_PARAM_SPEC_STRING(pspec)   (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_STRING))
+#define G_PARAM_SPEC_STRING(pspec)      (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_STRING, GParamSpecString))
+#define G_IS_VALUE_OBJECT(value)        (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_PARAM_OBJECT))
+#define G_IS_PARAM_SPEC_OBJECT(pspec)   (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_OBJECT))
+#define G_PARAM_SPEC_OBJECT(pspec)      (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_OBJECT, GParamSpecObject))
+
+
+/* --- typedefs & structures --- */
+typedef struct _GParamSpecChar   GParamSpecChar;
+typedef struct _GParamSpecUChar  GParamSpecUChar;
+typedef struct _GParamSpecBool   GParamSpecBool;
+typedef struct _GParamSpecInt    GParamSpecInt;
+typedef struct _GParamSpecUInt   GParamSpecUInt;
+typedef struct _GParamSpecLong   GParamSpecLong;
+typedef struct _GParamSpecULong  GParamSpecULong;
+typedef struct _GParamSpecEnum   GParamSpecEnum;
+typedef struct _GParamSpecFlags  GParamSpecFlags;
+typedef struct _GParamSpecFloat  GParamSpecFloat;
+typedef struct _GParamSpecDouble GParamSpecDouble;
+typedef struct _GParamSpecString GParamSpecString;
+typedef struct _GParamSpecObject GParamSpecObject;
+struct _GParamSpecChar
+{
+  GParamSpec    parent_instance;
+  
+  gint8         minimum;
+  gint8         maximum;
+  gint8         default_value;
+};
+struct _GParamSpecUChar
+{
+  GParamSpec    parent_instance;
+  
+  guint8        minimum;
+  guint8        maximum;
+  guint8        default_value;
+};
+struct _GParamSpecBool
+{
+  GParamSpec    parent_instance;
+  
+  gboolean      default_value;
+};
+struct _GParamSpecInt
+{
+  GParamSpec    parent_instance;
+  
+  gint          minimum;
+  gint          maximum;
+  gint          default_value;
+};
+struct _GParamSpecUInt
+{
+  GParamSpec    parent_instance;
+  
+  guint         minimum;
+  guint         maximum;
+  guint         default_value;
+};
+struct _GParamSpecLong
+{
+  GParamSpec    parent_instance;
+  
+  glong         minimum;
+  glong         maximum;
+  glong         default_value;
+};
+struct _GParamSpecULong
+{
+  GParamSpec    parent_instance;
+  
+  gulong        minimum;
+  gulong        maximum;
+  gulong        default_value;
+};
+struct _GParamSpecEnum
+{
+  GParamSpec    parent_instance;
+  
+  GEnumClass   *enum_class;
+  glong         default_value;
+};
+struct _GParamSpecFlags
+{
+  GParamSpec    parent_instance;
+  
+  GFlagsClass  *flags_class;
+  gulong        default_value;
+};
+struct _GParamSpecFloat
+{
+  GParamSpec    parent_instance;
+  
+  gfloat        minimum;
+  gfloat        maximum;
+  gfloat        default_value;
+  gfloat        epsilon;
+};
+struct _GParamSpecDouble
+{
+  GParamSpec    parent_instance;
+  
+  gdouble       minimum;
+  gdouble       maximum;
+  gdouble       default_value;
+  gdouble       epsilon;
+};
+struct _GParamSpecString
+{
+  GParamSpec    parent_instance;
+  
+  gchar        *default_value;
+  gchar        *cset_first;
+  gchar        *cset_nth;
+  gchar         substitutor;
+  guint         null_fold_if_empty : 1;
+  guint         ensure_non_null : 1;
+};
+struct _GParamSpecObject
+{
+  GParamSpec    parent_instance;
+  
+  GType         object_type;
+};
+
+
+/* --- GValue prototypes --- */
+void            g_value_set_char        (GValue         *value,
+                                         gint8           v_char);
+gint8           g_value_get_char        (GValue         *value);
+void            g_value_set_uchar       (GValue         *value,
+                                         guint8          v_uchar);
+guint8          g_value_get_uchar       (GValue         *value);
+void            g_value_set_bool        (GValue         *value,
+                                         gboolean        v_bool);
+gboolean        g_value_get_bool        (GValue         *value);
+void            g_value_set_int         (GValue         *value,
+                                         gint            v_int);
+gint            g_value_get_int         (GValue         *value);
+void            g_value_set_uint        (GValue         *value,
+                                         guint           v_uint);
+guint           g_value_get_uint        (GValue         *value);
+void            g_value_set_long        (GValue         *value,
+                                         glong           v_long);
+glong           g_value_get_long        (GValue         *value);
+void            g_value_set_ulong       (GValue         *value,
+                                         gulong          v_ulong);
+gulong          g_value_get_ulong       (GValue         *value);
+void            g_value_set_enum        (GValue         *value,
+                                         gint            v_enum);
+gint            g_value_get_enum        (GValue         *value);
+void            g_value_set_flags       (GValue         *value,
+                                         guint           v_flags);
+guint           g_value_get_flags       (GValue         *value);
+void            g_value_set_float       (GValue         *value,
+                                         gfloat          v_float);
+gfloat          g_value_get_float       (GValue         *value);
+void            g_value_set_double      (GValue         *value,
+                                         gdouble         v_double);
+gdouble         g_value_get_double      (GValue         *value);
+void            g_value_set_string      (GValue         *value,
+                                         const gchar    *v_string);
+gchar*          g_value_get_string      (GValue         *value);
+gchar*          g_value_dup_string      (GValue         *value);
+void            g_value_set_object      (GValue         *value,
+                                         GObject        *v_object);
+GObject*        g_value_get_object      (GValue         *value);
+GObject*        g_value_dup_object      (GValue         *value);
+
+
+/* --- GParamSpec prototypes --- */
+GParamSpec*     g_param_spec_char       (const gchar    *name,
+                                         const gchar    *nick,
+                                         const gchar    *blurb,
+                                         gint8           minimum,
+                                         gint8           maximum,
+                                         gint8           default_value,
+                                         GParamFlags     flags);
+GParamSpec*     g_param_spec_uchar      (const gchar    *name,
+                                         const gchar    *nick,
+                                         const gchar    *blurb,
+                                         guint8          minimum,
+                                         guint8          maximum,
+                                         guint8          default_value,
+                                         GParamFlags     flags);
+GParamSpec*     g_param_spec_bool       (const gchar    *name,
+                                         const gchar    *nick,
+                                         const gchar    *blurb,
+                                         gboolean        default_value,
+                                         GParamFlags     flags);
+GParamSpec*     g_param_spec_int        (const gchar    *name,
+                                         const gchar    *nick,
+                                         const gchar    *blurb,
+                                         gint            minimum,
+                                         gint            maximum,
+                                         gint            default_value,
+                                         GParamFlags     flags);
+GParamSpec*     g_param_spec_uint       (const gchar    *name,
+                                         const gchar    *nick,
+                                         const gchar    *blurb,
+                                         guint           minimum,
+                                         guint           maximum,
+                                         guint           default_value,
+                                         GParamFlags     flags);
+GParamSpec*     g_param_spec_long       (const gchar    *name,
+                                         const gchar    *nick,
+                                         const gchar    *blurb,
+                                         glong           minimum,
+                                         glong           maximum,
+                                         glong           default_value,
+                                         GParamFlags     flags);
+GParamSpec*     g_param_spec_ulong      (const gchar    *name,
+                                         const gchar    *nick,
+                                         const gchar    *blurb,
+                                         gulong          minimum,
+                                         gulong          maximum,
+                                         gulong          default_value,
+                                         GParamFlags     flags);
+GParamSpec*     g_param_spec_enum       (const gchar    *name,
+                                         const gchar    *nick,
+                                         const gchar    *blurb,
+                                         GType           enum_type,
+                                         gint            default_value,
+                                         GParamFlags     flags);
+GParamSpec*     g_param_spec_flags      (const gchar    *name,
+                                         const gchar    *nick,
+                                         const gchar    *blurb,
+                                         GType           flags_type,
+                                         guint           default_value,
+                                         GParamFlags     flags);
+GParamSpec*     g_param_spec_float      (const gchar    *name,
+                                         const gchar    *nick,
+                                         const gchar    *blurb,
+                                         gfloat          minimum,
+                                         gfloat          maximum,
+                                         gfloat          default_value,
+                                         GParamFlags     flags);
+GParamSpec*     g_param_spec_double     (const gchar    *name,
+                                         const gchar    *nick,
+                                         const gchar    *blurb,
+                                         gdouble         minimum,
+                                         gdouble         maximum,
+                                         gdouble         default_value,
+                                         GParamFlags     flags);
+GParamSpec*     g_param_spec_string     (const gchar    *name,
+                                         const gchar    *nick,
+                                         const gchar    *blurb,
+                                         const gchar    *default_value,
+                                         GParamFlags     flags);
+GParamSpec*     g_param_spec_string_c   (const gchar    *name,
+                                         const gchar    *nick,
+                                         const gchar    *blurb,
+                                         const gchar    *default_value,
+                                         GParamFlags     flags);
+GParamSpec*     g_param_spec_object     (const gchar    *name,
+                                         const gchar    *nick,
+                                         const gchar    *blurb,
+                                         GType           object_type,
+                                         GParamFlags     flags);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __G_PARAMSPECS_H__ */
diff --git a/gobject/gtype.c b/gobject/gtype.c
new file mode 100644 (file)
index 0000000..1b6a313
--- /dev/null
@@ -0,0 +1,1825 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 1998, 1999, 2000 Tim Janik and Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include       "gtype.h"
+
+#include       "genums.h"
+#include       "gobject.h"
+#include       <string.h>
+
+#define FIXME_DISABLE_PREALLOCATIONS
+
+/* NOTE: some functions (some internal variants and exported ones)
+ * invalidate data portions of the TypeNodes. if external functions/callbacks
+ * are called, pointers to memory maintained by TypeNodes have to be looked up
+ * again. this affects most of the struct TypeNode fields, e.g. ->children or
+ * ->iface_entries (not ->supers[] as of recently), as all those memory portions can
+ * get realloc()ed during callback invocation.
+ *
+ * TODO:
+ * - g_type_from_name() should do an ordered array lookup after fetching the
+ *   the quark, instead of a second hashtable lookup.
+ *
+ * FIXME:
+ * - force interface initialization for already existing classes
+ */
+
+#define G_TYPE_FLAG_MASK       (G_TYPE_FLAG_CLASSED | \
+                                G_TYPE_FLAG_INSTANTIATABLE | \
+                                G_TYPE_FLAG_DERIVABLE | \
+                                G_TYPE_FLAG_DEEP_DERIVABLE)
+#define        g_type_plugin_ref(p)                            ((p)->vtable->plugin_ref (p))
+#define g_type_plugin_unref(p)                         ((p)->vtable->plugin_unref (p))
+#define        g_type_plugin_complete_type_info(p,t,i)         ((p)->vtable->complete_type_info ((p), (t), (i)))
+#define        g_type_plugin_complete_interface_info(p,f,t,i)  ((p)->vtable->complete_interface_info ((p), (f), (t), (i)))
+
+typedef struct _TypeNode        TypeNode;
+typedef struct _CommonData      CommonData;
+typedef struct _IFaceData       IFaceData;
+typedef struct _ClassData       ClassData;
+typedef struct _InstanceData    InstanceData;
+typedef union  _TypeData        TypeData;
+typedef struct _IFaceEntry      IFaceEntry;
+typedef struct _IFaceHolder    IFaceHolder;
+
+
+/* --- prototypes --- */
+static inline GTypeFundamentalInfo*    type_node_fundamental_info      (TypeNode               *node);
+static       void                      type_data_make                  (TypeNode               *node,
+                                                                        const GTypeInfo        *info);
+static inline void                     type_data_ref                   (TypeNode               *node);
+static inline void                     type_data_unref                 (TypeNode               *node);
+static       void                      type_data_last_unref            (GType                   type);
+
+
+/* --- structures --- */
+struct _TypeNode
+{
+  GTypePlugin *plugin;
+  guint        n_children : 12;
+  guint        n_supers : 8;
+  guint        n_ifaces : 9;
+  guint        is_classed : 1;
+  guint        is_instantiatable : 1;
+  guint        is_iface : 1;
+  GType       *children;
+  TypeData    *data;
+  GQuark       qname;
+  GData       *static_gdata;
+  union {
+    IFaceEntry  *iface_entries;
+    IFaceHolder *iholders;
+  } private;
+  GType        supers[1]; /* flexible array */
+};
+#define SIZEOF_BASE_TYPE_NODE()        (G_STRUCT_OFFSET (TypeNode, supers))
+#define MAX_N_SUPERS    (255)
+#define MAX_N_CHILDREN  (4095)
+#define MAX_N_IFACES    (511)
+
+struct _IFaceHolder
+{
+  GType           instance_type;
+  GInterfaceInfo *info;
+  GTypePlugin    *plugin;
+  IFaceHolder    *next;
+};
+struct _CommonData
+{
+  guint                    ref_count;
+};
+struct _IFaceData
+{
+  CommonData         common;
+  guint              vtable_size;
+  GBaseInitFunc      vtable_init_base;
+  GBaseFinalizeFunc  vtable_finalize_base;
+};
+struct _ClassData
+{
+  CommonData         common;
+  guint              class_size;
+  GBaseInitFunc      class_init_base;
+  GBaseFinalizeFunc  class_finalize_base;
+  GClassInitFunc     class_init;
+  GClassFinalizeFunc class_finalize;
+  gconstpointer      class_data;
+  gpointer           class;
+};
+struct _InstanceData
+{
+  CommonData         common;
+  guint              class_size;
+  GBaseInitFunc      class_init_base;
+  GBaseFinalizeFunc  class_finalize_base;
+  GClassInitFunc     class_init;
+  GClassFinalizeFunc class_finalize;
+  gconstpointer      class_data;
+  gpointer           class;
+  guint16            instance_size;
+  guint16            n_preallocs;
+  GInstanceInitFunc  instance_init;
+  GMemChunk        *mem_chunk;
+};
+union _TypeData
+{
+  CommonData         common;
+  IFaceData          iface;
+  ClassData          class;
+  InstanceData       instance;
+};
+struct _IFaceEntry
+{
+  GType           iface_type;
+  GTypeInterface *vtable;
+};
+
+
+/* --- externs --- */
+const char *g_log_domain_gobject = "GLib-Object";
+GType       _g_type_fundamental_last = 0;
+
+
+/* --- type nodes --- */
+static GHashTable       *g_type_nodes_ht = NULL;
+static GType            *g_branch_seqnos = NULL;
+static TypeNode       ***g_type_nodes = NULL;
+
+static inline TypeNode*
+LOOKUP_TYPE_NODE (register GType utype)
+{
+  register GType ftype = G_TYPE_FUNDAMENTAL (utype);
+  register GType b_seqno = G_TYPE_BRANCH_SEQNO (utype);
+
+  if (ftype < G_TYPE_FUNDAMENTAL_LAST && b_seqno < g_branch_seqnos[ftype])
+    return g_type_nodes[ftype][b_seqno];
+  else
+    return NULL;
+}
+#define NODE_TYPE(node)         (node->supers[0])
+#define NODE_PARENT_TYPE(node)  (node->supers[1])
+#define NODE_NAME(node)         (g_quark_to_string (node->qname))
+
+static TypeNode*
+type_node_any_new (TypeNode    *pnode,
+                  GType        ftype,
+                  const gchar *name,
+                  GTypePlugin *plugin,
+                  GTypeFlags   type_flags)
+{
+  guint branch_last, n_supers = pnode ? pnode->n_supers + 1 : 0;
+  GType type;
+  TypeNode *node;
+  guint i, node_size = 0;
+
+  branch_last = g_branch_seqnos[ftype]++;
+  type = G_TYPE_DERIVE_ID (ftype, branch_last);
+  if (!branch_last || g_bit_storage (branch_last - 1) < g_bit_storage (g_branch_seqnos[ftype] - 1))
+    g_type_nodes[ftype] = g_renew (TypeNode*, g_type_nodes[ftype], 1 << g_bit_storage (g_branch_seqnos[ftype] - 1));
+
+  if (!pnode)
+    node_size += sizeof (GTypeFundamentalInfo);         /* fundamental type */
+  node_size += SIZEOF_BASE_TYPE_NODE ();        /* TypeNode structure */
+  node_size += sizeof (GType[1 + n_supers + 1]); /* self + anchestors + 0 for ->supers[] */
+  node = g_malloc0 (node_size);
+  if (!pnode)                                   /* fundamental type */
+    node = G_STRUCT_MEMBER_P (node, sizeof (GTypeFundamentalInfo));
+  g_type_nodes[ftype][branch_last] = node;
+
+  node->n_supers = n_supers;
+  if (!pnode)
+    {
+      node->supers[0] = type;
+      node->supers[1] = 0;
+
+      node->is_classed = (type_flags & G_TYPE_FLAG_CLASSED) != 0;
+      node->is_instantiatable = (type_flags & G_TYPE_FLAG_INSTANTIATABLE) != 0;
+      node->is_iface = G_TYPE_IS_INTERFACE (type);
+
+      node->n_ifaces = 0;
+      if (node->is_iface)
+       node->private.iholders = NULL;
+      else
+       node->private.iface_entries = NULL;
+    }
+  else
+    {
+      node->supers[0] = type;
+      memcpy (node->supers + 1, pnode->supers, sizeof (GType[1 + pnode->n_supers + 1]));
+
+      node->is_classed = pnode->is_classed;
+      node->is_instantiatable = pnode->is_instantiatable;
+      node->is_iface = pnode->is_iface;
+
+      if (node->is_iface)
+       {
+         node->n_ifaces = 0;
+         node->private.iholders = NULL;
+       }
+      else
+       {
+         node->n_ifaces = pnode->n_ifaces;
+         node->private.iface_entries = g_memdup (pnode->private.iface_entries,
+                                                 sizeof (pnode->private.iface_entries[0]) * node->n_ifaces);
+       }
+      
+      i = pnode->n_children++;
+      pnode->children = g_renew (GType, pnode->children, pnode->n_children);
+      pnode->children[i] = type;
+    }
+
+  node->plugin = plugin;
+  node->n_children = 0;
+  node->children = NULL;
+  node->data = NULL;
+  node->qname = g_quark_from_string (name);
+  node->static_gdata = NULL;
+
+  g_hash_table_insert (g_type_nodes_ht,
+                      GUINT_TO_POINTER (node->qname),
+                      GUINT_TO_POINTER (type));
+
+  return node;
+}
+
+static inline GTypeFundamentalInfo*
+type_node_fundamental_info (TypeNode *node)
+{
+  GType ftype = G_TYPE_FUNDAMENTAL (NODE_TYPE (node));
+  
+  if (ftype != NODE_TYPE (node))
+    node = LOOKUP_TYPE_NODE (ftype);
+  
+  return node ? G_STRUCT_MEMBER_P (node, - sizeof (GTypeFundamentalInfo)) : NULL;
+}
+
+static TypeNode*
+type_node_fundamental_new (GType        ftype,
+                          const gchar *name,
+                          GTypeFlags   type_flags)
+{
+  GTypeFundamentalInfo *finfo;
+  TypeNode *node;
+  guint i, flast = G_TYPE_FUNDAMENTAL_LAST;
+  
+  g_assert (ftype == G_TYPE_FUNDAMENTAL (ftype));
+  
+  type_flags &= G_TYPE_FLAG_MASK;
+
+  _g_type_fundamental_last = MAX (_g_type_fundamental_last, ftype + 1);
+  if (G_TYPE_FUNDAMENTAL_LAST > flast)
+    {
+      g_type_nodes = g_renew (TypeNode**, g_type_nodes, G_TYPE_FUNDAMENTAL_LAST);
+      g_branch_seqnos = g_renew (GType, g_branch_seqnos, G_TYPE_FUNDAMENTAL_LAST);
+      for (i = flast; i < G_TYPE_FUNDAMENTAL_LAST; i++)
+       {
+         g_type_nodes[i] = NULL;
+         g_branch_seqnos[i] = 0;
+       }
+    }
+  g_assert (g_branch_seqnos[ftype] == 0);
+
+  node = type_node_any_new (NULL, ftype, name, NULL, type_flags);
+  finfo = type_node_fundamental_info (node);
+  finfo->type_flags = type_flags;
+
+  return node;
+}
+
+static TypeNode*
+type_node_new (TypeNode    *pnode,
+              const gchar *name,
+              GTypePlugin *plugin)
+
+{
+  g_assert (pnode);
+  g_assert (pnode->n_supers < MAX_N_SUPERS);
+  g_assert (pnode->n_children < MAX_N_CHILDREN);
+
+  return type_node_any_new (pnode, G_TYPE_FUNDAMENTAL (NODE_TYPE (pnode)), name, plugin, 0);
+}
+
+static inline IFaceEntry*
+type_lookup_iface_entry (TypeNode       *node,
+                        TypeNode       *iface)
+{
+  if (iface->is_iface && node->n_ifaces)
+    {
+      IFaceEntry *ifaces = node->private.iface_entries - 1;
+      guint n_ifaces = node->n_ifaces;
+      GType iface_type = NODE_TYPE (iface);
+
+      do               /* FIXME: should optimize iface lookups for <= 4 */
+       {
+         guint i;
+         IFaceEntry *check;
+
+         i = (n_ifaces + 1) / 2;
+         check = ifaces + i;
+         if (iface_type == check->iface_type)
+           return check;
+         else if (iface_type > check->iface_type)
+           {
+             n_ifaces -= i;
+             ifaces = check;
+           }
+         else /* if (iface_type < check->iface_type) */
+           n_ifaces = i - 1;
+       }
+      while (n_ifaces);
+    }
+
+  return NULL;
+}
+
+static inline gchar*
+type_descriptive_name (GType type)
+{
+  if (type)
+    {
+      gchar *name = g_type_name (type);
+
+      return name ? name : "<unknown>";
+    }
+  else
+    return "<invalid>";
+}
+
+
+/* --- type consistency checks --- */
+static gboolean
+check_plugin (GTypePlugin *plugin,
+             gboolean     need_complete_type_info,
+             gboolean     need_complete_interface_info,
+             const gchar *type_name)
+{
+  if (!plugin)
+    {
+      g_warning ("plugin handle for type `%s' is NULL",
+                type_name);
+      return FALSE;
+    }
+  if (!plugin->vtable)
+    {
+      g_warning ("plugin for type `%s' has no function table",
+                type_name);
+      return FALSE;
+    }
+  if (!plugin->vtable->plugin_ref)
+    {
+      g_warning ("plugin for type `%s' has no plugin_ref() implementation",
+                type_name);
+      return FALSE;
+    }
+  if (!plugin->vtable->plugin_unref)
+    {
+      g_warning ("plugin for type `%s' has no plugin_unref() implementation",
+                type_name);
+      return FALSE;
+    }
+  if (need_complete_type_info && !plugin->vtable->complete_type_info)
+    {
+      g_warning ("plugin for type `%s' has no complete_type_info() implementation",
+                type_name);
+      return FALSE;
+    }
+  if (need_complete_interface_info && !plugin->vtable->complete_interface_info)
+    {
+      g_warning ("plugin for type `%s' has no complete_interface_info() implementation",
+                type_name);
+      return FALSE;
+    }
+  return TRUE;
+}
+
+static gboolean
+check_type_name (const gchar *type_name)
+{
+  static const gchar *extra_chars = "-_+";
+  const gchar *p = type_name;
+  gboolean name_valid;
+
+  if (!type_name[0] || !type_name[1] || !type_name[2])
+    {
+      g_warning ("type name `%s' is too short", type_name);
+      return FALSE;
+    }
+  /* check the first letter */
+  name_valid = (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z') || p[0] == '_';
+  for (p = type_name + 1; *p; p++)
+    name_valid &= ((p[0] >= 'A' && p[0] <= 'Z') ||
+                  (p[0] >= 'a' && p[0] <= 'z') ||
+                  (p[0] >= '0' && p[0] <= '9') ||
+                  strchr (extra_chars, p[0]));
+  if (!name_valid)
+    {
+      g_warning ("type name `%s' contains invalid characters", type_name);
+      return FALSE;
+    }
+  if (g_type_from_name (type_name))
+    {
+      g_warning ("cannot register existing type `%s'", type_name);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static gboolean
+check_derivation (GType        parent_type,
+                 const gchar *type_name)
+{
+  TypeNode *pnode = LOOKUP_TYPE_NODE (parent_type);
+  GTypeFundamentalInfo* finfo = type_node_fundamental_info (pnode);
+  
+  if (!pnode)
+    {
+      g_warning ("cannot derive type `%s' from invalid parent type `%s'",
+                type_name,
+                type_descriptive_name (parent_type));
+      return FALSE;
+    }
+  /* ensure flat derivability */
+  if (!(finfo->type_flags & G_TYPE_FLAG_DERIVABLE))
+    {
+      g_warning ("cannot derive `%s' from non-derivable parent type `%s'",
+                type_name,
+                NODE_NAME (pnode));
+      return FALSE;
+    }
+  /* ensure deep derivability */
+  if (parent_type != G_TYPE_FUNDAMENTAL (parent_type) &&
+      !(finfo->type_flags & G_TYPE_FLAG_DEEP_DERIVABLE))
+    {
+      g_warning ("cannot derive `%s' from non-fundamental parent type `%s'",
+                type_name,
+                NODE_NAME (pnode));
+      return FALSE;
+    }
+  
+  return TRUE;
+}
+
+static gboolean
+check_type_info (TypeNode             *pnode,
+                GType                 ftype,
+                const gchar          *type_name,
+                const GTypeInfo      *info)
+{
+  GTypeFundamentalInfo *finfo = type_node_fundamental_info (LOOKUP_TYPE_NODE (ftype));
+  gboolean is_interface = G_TYPE_IS_INTERFACE (ftype);
+
+  /* check instance members */
+  if (!(finfo->type_flags & G_TYPE_FLAG_INSTANTIATABLE) &&
+      (info->instance_size || info->n_preallocs || info->instance_init))
+    {
+      if (pnode)
+       g_warning ("cannot instantiate `%s', derived from non-instantiatable parent type `%s'",
+                  type_name,
+                  NODE_NAME (pnode));
+      else
+       g_warning ("cannot instantiate `%s' as non-instantiatable fundamental",
+                  type_name);
+      return FALSE;
+    }
+  /* check class & interface members */
+  if (!(finfo->type_flags & G_TYPE_FLAG_CLASSED) &&
+      (info->class_init || info->class_finalize || info->class_data ||
+       (!is_interface && (info->class_size || info->base_init || info->base_finalize))))
+    {
+      if (pnode)
+       g_warning ("cannot create class for `%s', derived from non-classed parent type `%s'",
+                  type_name,
+                   NODE_NAME (pnode));
+      else
+       g_warning ("cannot create class for `%s' as non-classed fundamental",
+                  type_name);
+      return FALSE;
+    }
+  /* check interface size */
+  if (is_interface && info->class_size < sizeof (GTypeInterface))
+    {
+      g_warning ("specified interface size for type `%s' is smaller than `GTypeInterface' size",
+                type_name);
+      return FALSE;
+    }
+  /* check class size */
+  if (finfo->type_flags & G_TYPE_FLAG_CLASSED)
+    {
+      if (info->class_size < sizeof (GTypeClass))
+       {
+         g_warning ("specified class size for type `%s' is smaller than `GTypeClass' size",
+                    type_name);
+         return FALSE;
+       }
+      if (pnode && info->class_size < pnode->data->class.class_size)
+       {
+         g_warning ("specified class size for type `%s' is smaller "
+                    "than the parent type's `%s' class size",
+                    type_name,
+                    NODE_NAME (pnode));
+         return FALSE;
+       }
+    }
+  /* check instance size */
+  if (finfo->type_flags & G_TYPE_FLAG_INSTANTIATABLE)
+    {
+      if (info->instance_size < sizeof (GTypeInstance))
+       {
+         g_warning ("specified instance size for type `%s' is smaller than `GTypeInstance' size",
+                    type_name);
+         return FALSE;
+       }
+      if (pnode && info->instance_size < pnode->data->instance.instance_size)
+       {
+         g_warning ("specified instance size for type `%s' is smaller "
+                    "than the parent type's `%s' instance size",
+                    type_name,
+                    NODE_NAME (pnode));
+         return FALSE;
+       }
+    }
+
+  return TRUE;
+}
+
+static TypeNode*
+find_conforming_type (TypeNode *pnode,
+                     TypeNode *iface)
+{
+  TypeNode *node = NULL;
+  guint i;
+
+  if (type_lookup_iface_entry (pnode, iface))
+    return pnode;
+
+  for (i = 0; i < pnode->n_children && !node; i++)
+    node = find_conforming_type (LOOKUP_TYPE_NODE (pnode->children[i]), iface);
+
+  return node;
+}
+
+static gboolean
+check_add_interface (GType instance_type,
+                    GType iface_type)
+{
+  TypeNode *node = LOOKUP_TYPE_NODE (instance_type);
+  TypeNode *iface = LOOKUP_TYPE_NODE (iface_type);
+  TypeNode *tnode;
+
+  if (!node || !node->is_instantiatable)
+    {
+      g_warning ("cannot add interfaces to invalid (non-instantiatable) type `%s'",
+                type_descriptive_name (instance_type));
+      return FALSE;
+    }
+  if (!iface || !iface->is_iface)
+    {
+      g_warning ("cannot add invalid (non-interface) type `%s' to type `%s'",
+                type_descriptive_name (iface_type),
+                NODE_NAME (node));
+      return FALSE;
+    }
+  tnode = LOOKUP_TYPE_NODE (NODE_PARENT_TYPE (iface));
+  if (NODE_PARENT_TYPE (tnode) && !type_lookup_iface_entry (node, tnode))
+    {
+      g_warning ("cannot add sub-interface `%s' to type `%s' which does not conform to super-interface `%s'",
+                NODE_NAME (iface),
+                NODE_NAME (node),
+                NODE_NAME (tnode));
+      return FALSE;
+    }
+  tnode = find_conforming_type (node, iface);
+  if (tnode)
+    {
+      g_warning ("cannot add interface type `%s' to type `%s', since type `%s' already conforms to interface",
+                NODE_NAME (iface),
+                NODE_NAME (node),
+                NODE_NAME (tnode));
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static gboolean
+check_interface_info (TypeNode             *iface,
+                     GType                 instance_type,
+                     const GInterfaceInfo *info)
+{
+  if ((info->interface_finalize || info->interface_data) && !info->interface_init)
+    {
+      g_warning ("interface type `%s' for type `%s' comes without initializer",
+                NODE_NAME (iface),
+                type_descriptive_name (instance_type));
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+
+/* --- type info (type node data) --- */
+static void
+type_data_make (TypeNode        *node,
+               const GTypeInfo *info)
+{
+  TypeData *data = NULL;
+
+  g_assert (node->data == NULL && info != NULL);
+  
+  if (node->is_instantiatable) /* carefull, is_instantiatable is also is_classed */
+    {
+      data = g_malloc0 (sizeof (InstanceData));
+      data->instance.class_size = info->class_size;
+      data->instance.class_init_base = info->base_init;
+      data->instance.class_finalize_base = info->base_finalize;
+      data->instance.class_init = info->class_init;
+      data->instance.class_finalize = info->class_finalize;
+      data->instance.class_data = info->class_data;
+      data->instance.class = NULL;
+      data->instance.instance_size = info->instance_size;
+      data->instance.n_preallocs = MIN (info->n_preallocs, 1024);
+#ifdef FIXME_DISABLE_PREALLOCATIONS
+      data->instance.n_preallocs = 0;
+#endif
+      data->instance.instance_init = info->instance_init;
+      data->instance.mem_chunk = NULL;
+    }
+  else if (node->is_classed) /* only classed */
+    {
+      data = g_malloc0 (sizeof (ClassData));
+      data->class.class_size = info->class_size;
+      data->class.class_init_base = info->base_init;
+      data->class.class_finalize_base = info->base_finalize;
+      data->class.class_init = info->class_init;
+      data->class.class_finalize = info->class_finalize;
+      data->class.class_data = info->class_data;
+      data->class.class = NULL;
+    }
+  else if (node->is_iface)
+    {
+      data = g_malloc0 (sizeof (IFaceData));
+      data->iface.vtable_size = info->class_size;
+      data->iface.vtable_init_base = info->base_init;
+      data->iface.vtable_finalize_base = info->base_finalize;
+    }
+  else
+    data = g_malloc0 (sizeof (CommonData));
+
+  node->data = data;
+  node->data->common.ref_count = 1;
+}
+
+static inline void
+type_data_ref (TypeNode *node)
+{
+  if (!node->data)
+    {
+      TypeNode *pnode = LOOKUP_TYPE_NODE (NODE_PARENT_TYPE (node));
+      GTypeInfo tmpinfo;
+      
+      g_assert (node->plugin != NULL);
+      
+      if (pnode)
+       type_data_ref (pnode);
+      
+      memset (&tmpinfo, 0, sizeof (tmpinfo));
+      g_type_plugin_ref (node->plugin);
+      g_type_plugin_complete_type_info (node->plugin, NODE_TYPE (node), &tmpinfo);
+      check_type_info (pnode, G_TYPE_FUNDAMENTAL (NODE_TYPE (node)), NODE_NAME (node), &tmpinfo);
+      type_data_make (node, &tmpinfo);
+    }
+  else
+    {
+      g_assert (node->data->common.ref_count > 0);
+
+      node->data->common.ref_count += 1;
+    }
+}
+
+static inline void
+type_data_unref (TypeNode *node)
+{
+  g_assert (node->data && node->data->common.ref_count);
+
+  if (node->data->common.ref_count > 1)
+    node->data->common.ref_count -= 1;
+  else
+    {
+      if (!node->plugin)
+       {
+         g_warning ("static type `%s' unreferenced too often",
+                    NODE_NAME (node));
+         return;
+       }
+
+      type_data_last_unref (NODE_TYPE (node));
+    }
+}
+
+static void
+type_node_add_iface_entry (TypeNode *node,
+                          GType     iface_type)
+{
+  IFaceEntry *entries;
+  guint i;
+
+  g_assert (node->is_instantiatable && node->n_ifaces < MAX_N_IFACES);
+
+  node->n_ifaces++;
+  node->private.iface_entries = g_renew (IFaceEntry, node->private.iface_entries, node->n_ifaces);
+  entries = node->private.iface_entries;
+  for (i = 0; i < node->n_ifaces - 1; i++)
+    if (entries[i].iface_type > iface_type)
+      break;
+  g_memmove (entries + i + 1, entries + i, sizeof (entries[0]) * (node->n_ifaces - i - 1));
+  entries[i].iface_type = iface_type;
+  entries[i].vtable = NULL;
+
+  for (i = 0; i < node->n_children; i++)
+    type_node_add_iface_entry (LOOKUP_TYPE_NODE (node->children[i]), iface_type);
+}
+
+static void
+type_add_interface (TypeNode       *node,
+                   TypeNode       *iface,
+                   GInterfaceInfo *info,
+                   GTypePlugin    *plugin)
+{
+  IFaceHolder *iholder = g_new0 (IFaceHolder, 1);
+  
+  /* we must not call any functions of GInterfaceInfo from within here, since
+   * we got most probably called from _within_ a type registration function
+   */
+  g_assert (node->is_instantiatable && iface->is_iface && ((info && !plugin) || (!info && plugin)));
+  
+  iholder->next = iface->private.iholders;
+  iface->private.iholders = iholder;
+  iholder->instance_type = NODE_TYPE (node);
+  iholder->info = info ? g_memdup (info, sizeof (*info)) : NULL;
+  iholder->plugin = plugin;
+
+  type_node_add_iface_entry (node, NODE_TYPE (iface));
+}
+
+static IFaceHolder*
+type_iface_retrive_holder_info (TypeNode *iface,
+                               GType     instance_type)
+{
+  IFaceHolder *iholder = iface->private.iholders;
+
+  g_assert (iface->is_iface);
+
+  while (iholder->instance_type != instance_type)
+    iholder = iholder->next;
+
+  if (!iholder->info)
+    {
+      GInterfaceInfo tmpinfo;
+      
+      g_assert (iholder->plugin != NULL);
+      
+      type_data_ref (iface);
+
+      memset (&tmpinfo, 0, sizeof (tmpinfo));
+      g_type_plugin_ref (iholder->plugin);
+      g_type_plugin_complete_interface_info (iholder->plugin, NODE_TYPE (iface), instance_type, &tmpinfo);
+      check_interface_info (iface, instance_type, &tmpinfo);
+      iholder->info = g_memdup (&tmpinfo, sizeof (tmpinfo));
+    }
+  
+  return iholder;
+}
+
+static void
+type_iface_blow_holder_info (TypeNode *iface,
+                            GType     instance_type)
+{
+  IFaceHolder *iholder = iface->private.iholders;
+
+  g_assert (iface->is_iface);
+
+  while (iholder->instance_type != instance_type)
+    iholder = iholder->next;
+
+  if (iholder->info && iholder->plugin)
+    {
+      g_free (iholder->info);
+      iholder->info = NULL;
+      g_type_plugin_unref (iholder->plugin);
+
+      type_data_unref (iface);
+    }
+}
+
+
+/* --- type structure creation/destruction --- */
+GTypeInstance*
+g_type_create_instance (GType type)
+{
+  TypeNode *node = LOOKUP_TYPE_NODE (type);
+  GTypeInstance *instance;
+  GTypeClass *class;
+  guint i;
+  
+  if (!node || !node->is_instantiatable)
+    {
+      g_warning ("cannot create new instance of invalid (non-instantiatable) type `%s'",
+                type_descriptive_name (type));
+      return NULL;
+    }
+  
+  class = g_type_class_ref (type);
+  
+  if (node->data->instance.n_preallocs)
+    {
+      if (!node->data->instance.mem_chunk)
+       node->data->instance.mem_chunk = g_mem_chunk_new (NODE_NAME (node),
+                                                         node->data->instance.instance_size,
+                                                         (node->data->instance.instance_size *
+                                                          node->data->instance.n_preallocs),
+                                                         G_ALLOC_AND_FREE);
+      instance = g_chunk_new0 (GTypeInstance, node->data->instance.mem_chunk);
+    }
+  else
+    instance = g_malloc0 (node->data->instance.instance_size);
+  
+  for (i = node->n_supers; i > 0; i--)
+    {
+      TypeNode *pnode = LOOKUP_TYPE_NODE (node->supers[i]);
+      
+      if (pnode->data->instance.instance_init)
+       {
+         instance->g_class = pnode->data->instance.class;
+         pnode->data->instance.instance_init (instance, class);
+       }
+    }
+  instance->g_class = class;
+  if (node->data->instance.instance_init)
+    node->data->instance.instance_init (instance, class);
+
+  return instance;
+}
+
+void
+g_type_free_instance (GTypeInstance *instance)
+{
+  TypeNode *node;
+  GTypeClass *class;
+
+  g_return_if_fail (instance != NULL && instance->g_class != NULL);
+
+  class = instance->g_class;
+  node = LOOKUP_TYPE_NODE (class->g_type);
+  if (!node || !node->is_instantiatable || !node->data || node->data->class.class != (gpointer) class)
+    {
+      g_warning ("cannot free instance of invalid (non-instantiatable) type `%s'",
+                type_descriptive_name (class->g_type));
+      return;
+    }
+
+  instance->g_class = NULL;
+  if (node->data->instance.n_preallocs)
+    g_chunk_free (instance, node->data->instance.mem_chunk);
+  else
+    g_free (instance);
+
+  g_type_class_unref (class);
+}
+
+static void
+type_propagate_iface_vtable (TypeNode       *pnode,
+                            TypeNode       *iface,
+                            GTypeInterface *vtable)
+{
+  IFaceEntry *entry = type_lookup_iface_entry (pnode, iface);
+  guint i;
+
+  entry->vtable = vtable;
+  for (i = 0; i < pnode->n_children; i++)
+    {
+      TypeNode *node = LOOKUP_TYPE_NODE (pnode->children[i]);
+
+      type_propagate_iface_vtable (node, iface, vtable);
+    }
+}
+
+static void
+type_iface_vtable_init (TypeNode       *iface,
+                       TypeNode       *node)
+{
+  IFaceEntry *entry = type_lookup_iface_entry (node, iface);
+  IFaceHolder *iholder = type_iface_retrive_holder_info (iface, NODE_TYPE (node));
+  GTypeInterface *vtable;
+  
+  g_assert (iface->data && entry && entry->vtable == NULL && iholder && iholder->info);
+
+  vtable = g_malloc0 (iface->data->iface.vtable_size);
+  type_propagate_iface_vtable (node, iface, vtable);
+  vtable->g_type = NODE_TYPE (iface);
+  vtable->g_instance_type = NODE_TYPE (node);
+
+  if (iface->data->iface.vtable_init_base)
+    iface->data->iface.vtable_init_base (vtable);
+  if (iholder->info->interface_init)
+    iholder->info->interface_init (vtable, iholder->info->interface_data);
+}
+
+static void
+type_iface_vtable_finalize (TypeNode       *iface,
+                           TypeNode       *node,
+                           GTypeInterface *vtable)
+{
+  IFaceEntry *entry = type_lookup_iface_entry (node, iface);
+  IFaceHolder *iholder = iface->private.iholders;
+
+  g_assert (entry && entry->vtable == vtable);
+
+  while (iholder->instance_type != NODE_TYPE (node))
+    iholder = iholder->next;
+  g_assert (iholder && iholder->info);
+
+  type_propagate_iface_vtable (node, iface, NULL);
+  if (iholder->info->interface_finalize)
+    iholder->info->interface_finalize (vtable, iholder->info->interface_data);
+  if (iface->data->iface.vtable_finalize_base)
+    iface->data->iface.vtable_finalize_base (vtable);
+  
+  vtable->g_type = 0;
+  vtable->g_instance_type = 0;
+  g_free (vtable);
+
+  type_iface_blow_holder_info (iface, NODE_TYPE (node));
+}
+
+static void
+type_class_init (TypeNode   *node,
+                GTypeClass *pclass)
+{
+  GSList *slist, *init_slist = NULL;
+  GTypeClass *class;
+  IFaceEntry *entry;
+  TypeNode *bnode;
+  guint i;
+  
+  g_assert (node->is_classed && node->data &&
+           node->data->class.class_size &&
+           !node->data->class.class);
+  
+  class = g_malloc0 (node->data->class.class_size);
+  node->data->class.class = class;
+  
+  if (pclass)
+    {
+      TypeNode *pnode = LOOKUP_TYPE_NODE (pclass->g_type);
+      
+      memcpy (class, pclass, pnode->data->class.class_size);
+    }
+  
+  class->g_type = NODE_TYPE (node);
+  
+  /* stack all base class initialization functions, so we
+   * call them in ascending order.
+   */
+  for (bnode = node; bnode; bnode = LOOKUP_TYPE_NODE (NODE_PARENT_TYPE (bnode)))
+    if (bnode->data->class.class_init_base)
+      init_slist = g_slist_prepend (init_slist, bnode->data->class.class_init_base);
+  for (slist = init_slist; slist; slist = slist->next)
+    {
+      GBaseInitFunc class_init_base = slist->data;
+      
+      class_init_base (class);
+    }
+  g_slist_free (init_slist);
+  
+  if (node->data->class.class_init)
+    node->data->class.class_init (class, (gpointer) node->data->class.class_data);
+
+  /* ok, we got the class done, now initialize all interfaces */
+  for (entry = NULL, i = 0; i < node->n_ifaces; i++)
+    if (!node->private.iface_entries[i].vtable)
+      entry = node->private.iface_entries;
+  while (entry)
+    {
+      type_iface_vtable_init (LOOKUP_TYPE_NODE (entry->iface_type), node);
+
+      for (entry = NULL, i = 0; i < node->n_ifaces; i++)
+       if (!node->private.iface_entries[i].vtable)
+         entry = node->private.iface_entries;
+    }
+}
+
+static void
+type_data_finalize_class_ifaces (TypeNode *node)
+{
+  IFaceEntry *entry;
+  guint i;
+  
+  g_assert (node->is_instantiatable && node->data && node->data->class.class && node->data->common.ref_count == 0);
+  
+  g_message ("finalizing interfaces for %sClass `%s'",
+            type_descriptive_name (G_TYPE_FUNDAMENTAL (NODE_TYPE (node))),
+            type_descriptive_name (NODE_TYPE (node)));
+
+  for (entry = NULL, i = 0; i < node->n_ifaces; i++)
+    if (node->private.iface_entries[i].vtable &&
+       node->private.iface_entries[i].vtable->g_instance_type == NODE_TYPE (node))
+      entry = node->private.iface_entries;
+  while (entry)
+    {
+      type_iface_vtable_finalize (LOOKUP_TYPE_NODE (entry->iface_type), node, entry->vtable);
+
+  for (entry = NULL, i = 0; i < node->n_ifaces; i++)
+    if (node->private.iface_entries[i].vtable &&
+       node->private.iface_entries[i].vtable->g_instance_type == NODE_TYPE (node))
+      entry = node->private.iface_entries;
+    }
+}
+
+static void
+type_data_finalize_class (TypeNode  *node,
+                         ClassData *cdata)
+{
+  GTypeClass *class = cdata->class;
+  TypeNode *bnode;
+  
+  g_assert (cdata->class && cdata->common.ref_count == 0);
+  
+  g_message ("finalizing %sClass `%s'",
+            type_descriptive_name (G_TYPE_FUNDAMENTAL (NODE_TYPE (node))),
+            type_descriptive_name (NODE_TYPE (node)));
+
+  if (cdata->class_finalize)
+    cdata->class_finalize (class, (gpointer) cdata->class_data);
+  
+  /* call all base class destruction functions in descending order
+   */
+  if (cdata->class_finalize_base)
+    cdata->class_finalize_base (class);
+  for (bnode = LOOKUP_TYPE_NODE (NODE_PARENT_TYPE (node)); bnode; bnode = LOOKUP_TYPE_NODE (NODE_PARENT_TYPE (bnode)))
+    if (bnode->data->class.class_finalize_base)
+      bnode->data->class.class_finalize_base (class);
+  
+  class->g_type = 0;
+  g_free (cdata->class);
+}
+
+static void
+type_data_last_unref (GType type)
+{
+  TypeNode *node = LOOKUP_TYPE_NODE (type);
+  
+  g_return_if_fail (node != NULL && node->plugin != NULL);
+  
+  if (!node->data || node->data->common.ref_count == 0)
+    {
+      g_warning ("cannot drop last reference to unreferenced type `%s'",
+                type_descriptive_name (type));
+      return;
+    }
+  
+  if (node->data->common.ref_count > 1)        /* may have been re-referenced meanwhile */
+    node->data->common.ref_count -= 1;
+  else
+    {
+      GType ptype = NODE_PARENT_TYPE (node);
+      
+      node->data->common.ref_count = 0;
+      
+      if (node->is_instantiatable && node->data->instance.mem_chunk)
+       {
+         g_mem_chunk_destroy (node->data->instance.mem_chunk);
+         node->data->instance.mem_chunk = NULL;
+       }
+      
+      if (node->is_classed && node->data->class.class)
+       {
+         ClassData *cdata = &node->data->class;
+
+         if (node->n_ifaces)
+           type_data_finalize_class_ifaces (node);
+         node->data = NULL;
+         type_data_finalize_class (node, cdata);
+         g_free (cdata);
+       }
+      else
+       {
+         g_free (node->data);
+         node->data = NULL;
+       }
+      
+      if (ptype)
+       type_data_unref (LOOKUP_TYPE_NODE (ptype));
+      g_type_plugin_unref (node->plugin);
+    }
+}
+
+
+/* --- type registration --- */
+GType
+g_type_register_fundamental (GType                       type_id,
+                            const gchar                *type_name,
+                            const GTypeFundamentalInfo *finfo,
+                            const GTypeInfo            *info)
+{
+  GTypeFundamentalInfo *node_finfo;
+  TypeNode *node;
+
+  g_return_val_if_fail (type_id > 0, 0);
+  g_return_val_if_fail (type_name != NULL, 0);
+  g_return_val_if_fail (finfo != NULL, 0);
+  g_return_val_if_fail (info != NULL, 0);
+
+  if (!check_type_name (type_name))
+    return 0;
+  if (G_TYPE_FUNDAMENTAL (type_id) != type_id)
+    {
+      g_warning ("cannot register fundamental type `%s' with non-fundamental id (%u)",
+                type_name,
+                type_id);
+      return 0;
+    }
+  if (LOOKUP_TYPE_NODE (type_id))
+    {
+      g_warning ("cannot register existing fundamental type `%s' (as `%s')",
+                type_descriptive_name (type_id),
+                type_name);
+      return 0;
+    }
+  if ((finfo->type_flags & G_TYPE_FLAG_INSTANTIATABLE) &&
+      !(finfo->type_flags & G_TYPE_FLAG_CLASSED))
+    {
+      g_warning ("cannot register instantiatable fundamental type `%s' as non-classed",
+                type_name);
+      return 0;
+    }
+
+  node = type_node_fundamental_new (type_id, type_name, finfo->type_flags);
+  node_finfo = type_node_fundamental_info (node);
+  node_finfo->n_collect_bytes = finfo->n_collect_bytes; // FIXME: check max bytes
+  node_finfo->param_collector = finfo->param_collector;
+
+  if (!check_type_info (NULL, G_TYPE_FUNDAMENTAL (NODE_TYPE (node)), type_name, info))
+    return NODE_TYPE (node);
+  type_data_make (node, info);
+
+  return NODE_TYPE (node);
+}
+
+GType
+g_type_register_static (GType            parent_type,
+                       const gchar     *type_name,
+                       const GTypeInfo *info)
+{
+  TypeNode *pnode, *node;
+  GType type;
+  
+  g_return_val_if_fail (parent_type > 0, 0);
+  g_return_val_if_fail (type_name != NULL, 0);
+  g_return_val_if_fail (info != NULL, 0);
+  
+  if (!check_type_name (type_name))
+    return 0;
+  if (!check_derivation (parent_type, type_name))
+    return 0;
+
+  pnode = LOOKUP_TYPE_NODE (parent_type);
+  type_data_ref (pnode);
+
+  if (!check_type_info (pnode, G_TYPE_FUNDAMENTAL (parent_type), type_name, info))
+    return 0;
+  if (info->class_finalize)
+    {
+      g_warning ("class destructor specified for static type `%s'",
+                type_name);
+      return 0;
+    }
+
+  node = type_node_new (pnode, type_name, NULL);
+  type = NODE_TYPE (node);
+  type_data_make (node, info);
+
+  return type;
+}
+
+GType
+g_type_register_dynamic (GType        parent_type,
+                        const gchar *type_name,
+                        GTypePlugin *plugin)
+{
+  TypeNode *pnode, *node;
+  GType type;
+
+  g_return_val_if_fail (parent_type > 0, 0);
+  g_return_val_if_fail (type_name != NULL, 0);
+  g_return_val_if_fail (plugin != NULL, 0);
+
+  if (!check_type_name (type_name))
+    return 0;
+  if (!check_derivation (parent_type, type_name))
+    return 0;
+  if (!check_plugin (plugin, TRUE, FALSE, type_name))
+    return 0;
+  pnode = LOOKUP_TYPE_NODE (parent_type);
+
+  node = type_node_new (pnode, type_name, plugin);
+  type = NODE_TYPE (node);
+
+  return type;
+}
+
+void
+g_type_add_interface_static (GType           instance_type,
+                            GType           interface_type,
+                            GInterfaceInfo *info)
+{
+  TypeNode *node;
+  TypeNode *iface;
+  
+  g_return_if_fail (G_TYPE_IS_INSTANTIATABLE (instance_type));
+  g_return_if_fail (g_type_parent (interface_type) == G_TYPE_INTERFACE);
+
+  if (!check_add_interface (instance_type, interface_type))
+    return;
+  node = LOOKUP_TYPE_NODE (instance_type);
+  iface = LOOKUP_TYPE_NODE (interface_type);
+  if (!check_interface_info (iface, NODE_TYPE (node), info))
+    return;
+  type_add_interface (node, iface, info, NULL);
+}
+
+void
+g_type_add_interface_dynamic (GType        instance_type,
+                             GType        interface_type,
+                             GTypePlugin *plugin)
+{
+  TypeNode *node;
+  TypeNode *iface;
+  
+  g_return_if_fail (G_TYPE_IS_INSTANTIATABLE (instance_type));
+  g_return_if_fail (g_type_parent (interface_type) == G_TYPE_INTERFACE);
+
+  if (!check_add_interface (instance_type, interface_type))
+    return;
+  node = LOOKUP_TYPE_NODE (instance_type);
+  iface = LOOKUP_TYPE_NODE (interface_type);
+  if (!check_plugin (plugin, FALSE, TRUE, NODE_NAME (node)))
+    return;
+  type_add_interface (node, iface, NULL, plugin);
+}
+
+
+/* --- public API functions --- */
+gpointer
+g_type_class_ref (GType type)
+{
+  TypeNode *node = LOOKUP_TYPE_NODE (type);
+
+  /* optimize for common code path
+   */
+  if (node && node->is_classed && node->data &&
+      node->data->class.class && node->data->common.ref_count > 0)
+    {
+      type_data_ref (node);
+
+      return node->data->class.class;
+    }
+
+  if (!node || !node->is_classed ||
+      (node->data && node->data->common.ref_count < 1))
+    {
+      g_warning ("cannot retrive class for invalid (unclassed) type `%s'",
+                type_descriptive_name (type));
+      return NULL;
+    }
+
+  type_data_ref (node);
+
+  if (!node->data->class.class)
+    {
+      GType ptype = NODE_PARENT_TYPE (node);
+      GTypeClass *pclass = ptype ? g_type_class_ref (ptype) : NULL;
+
+      type_class_init (node, pclass);
+    }
+
+  return node->data->class.class;
+}
+
+void
+g_type_class_unref (gpointer g_class)
+{
+  TypeNode *node;
+  GTypeClass *class = g_class;
+
+  g_return_if_fail (g_class != NULL);
+
+  node = LOOKUP_TYPE_NODE (class->g_type);
+  if (node && node->is_classed && node->data &&
+      node->data->class.class == class && node->data->common.ref_count > 0)
+    type_data_unref (node);
+  else
+    g_warning ("cannot unreference class of invalid (unclassed) type `%s'",
+              type_descriptive_name (class->g_type));
+}
+
+gpointer
+g_type_class_peek (GType type)
+{
+  TypeNode *node = LOOKUP_TYPE_NODE (type);
+
+  if (node && node->is_classed && node->data && node->data->class.class) /* common.ref_count _may_ be 0 */
+    return node->data->class.class;
+  else
+    return NULL;
+}
+
+gpointer
+g_type_class_peek_parent (gpointer g_class)
+{
+  TypeNode *node;
+
+  g_return_val_if_fail (g_class != NULL, NULL);
+
+  node = LOOKUP_TYPE_NODE (G_TYPE_FROM_CLASS (g_class));
+  if (node && node->is_classed && node->data && NODE_PARENT_TYPE (node))
+    {
+      node = LOOKUP_TYPE_NODE (NODE_PARENT_TYPE (node));
+
+      return node->data->class.class;
+    }
+
+  return NULL;
+}
+
+gpointer
+g_type_interface_peek (gpointer instance_class,
+                      GType    iface_type)
+{
+  TypeNode *node;
+  TypeNode *iface;
+  GTypeClass *class = instance_class;
+
+  g_return_val_if_fail (instance_class != NULL, NULL);
+
+  node = LOOKUP_TYPE_NODE (class->g_type);
+  iface = LOOKUP_TYPE_NODE (iface_type);
+  if (node && node->is_instantiatable && iface)
+    {
+      IFaceEntry *entry = type_lookup_iface_entry (node, iface);
+
+      if (entry && entry->vtable)
+       return entry->vtable;
+    }
+
+  return NULL;
+}
+
+gchar*
+g_type_name (GType type)
+{
+  TypeNode *node = LOOKUP_TYPE_NODE (type);
+  
+  return node ? NODE_NAME (node) : NULL;
+}
+
+GQuark
+g_type_qname (GType type)
+{
+  TypeNode *node = LOOKUP_TYPE_NODE (type);
+
+  return node ? node->qname : 0;
+}
+
+GType
+g_type_from_name (const gchar *name)
+{
+  GQuark quark;
+  
+  g_return_val_if_fail (name != NULL, 0);
+  
+  quark = g_quark_try_string (name);
+  if (quark)
+    {
+      GType type = GPOINTER_TO_UINT (g_hash_table_lookup (g_type_nodes_ht, GUINT_TO_POINTER (quark)));
+      
+      if (type)
+       return type;
+    }
+  
+  return 0;
+}
+
+GType
+g_type_parent (GType type)
+{
+  TypeNode *node = LOOKUP_TYPE_NODE (type);
+
+  return node ? NODE_PARENT_TYPE (node) : 0;
+}
+
+GType
+g_type_next_base (GType type,
+                 GType base_type)
+{
+  TypeNode *node = LOOKUP_TYPE_NODE (type);
+  
+  if (node)
+    {
+      TypeNode *base_node = LOOKUP_TYPE_NODE (base_type);
+      
+      if (base_node && base_node->n_supers < node->n_supers)
+       {
+         guint n = node->n_supers - base_node->n_supers;
+         
+         if (node->supers[n] == base_type)
+           return node->supers[n - 1];
+       }
+    }
+  
+  return 0;
+}
+
+gboolean
+g_type_is_a (GType type,
+            GType is_a_type)
+{
+  if (type != is_a_type)
+    {
+      TypeNode *node = LOOKUP_TYPE_NODE (type);
+
+      if (node)
+       {
+         TypeNode *a_node = LOOKUP_TYPE_NODE (is_a_type);
+
+         if (a_node && a_node->n_supers <= node->n_supers)
+           return node->supers[node->n_supers - a_node->n_supers] == is_a_type;
+       }
+    }
+  else
+    return LOOKUP_TYPE_NODE (type) != NULL;
+
+  return FALSE;
+}
+
+gboolean
+g_type_conforms_to (GType type,
+                   GType iface_type)
+{
+  if (type != iface_type)
+    {
+      TypeNode *node = LOOKUP_TYPE_NODE (type);
+
+      if (node)
+       {
+         TypeNode *iface_node = LOOKUP_TYPE_NODE (iface_type);
+
+         if (iface_node)
+           {
+             if (iface_node->is_iface && node->is_instantiatable)
+               return type_lookup_iface_entry (node, iface_node) != NULL;
+             else if (iface_node->n_supers <= node->n_supers)
+               return node->supers[node->n_supers - iface_node->n_supers] == iface_type;
+           }
+       }
+    }
+  else
+    {
+      TypeNode *node = LOOKUP_TYPE_NODE (type);
+
+      return node && (node->is_iface || node->is_instantiatable);
+    }
+
+  return FALSE;
+}
+
+guint
+g_type_fundamental_branch_last (GType type)
+{
+  GType ftype = G_TYPE_FUNDAMENTAL (type);
+
+  return ftype < G_TYPE_FUNDAMENTAL_LAST ? g_branch_seqnos[ftype] : 0;
+}
+
+GType* /* free result */
+g_type_children (GType  type,
+                guint *n_children)
+{
+  TypeNode *node = LOOKUP_TYPE_NODE (type);
+  
+  if (node)
+    {
+      GType *children = g_new (GType, node->n_children + 1);
+      
+      memcpy (children, node->children, sizeof (GType) * node->n_children);
+      children[node->n_children] = 0;
+      
+      if (n_children)
+       *n_children = node->n_children;
+      
+      return children;
+    }
+  else
+    {
+      if (n_children)
+       *n_children = 0;
+      
+      return NULL;
+    }
+}
+
+GType* /* free result */
+g_type_interfaces (GType  type,
+                  guint *n_interfaces)
+{
+  TypeNode *node = LOOKUP_TYPE_NODE (type);
+
+  if (node && node->is_instantiatable)
+    {
+      GType *ifaces = g_new (GType, node->n_ifaces + 1);
+      guint i;
+
+      for (i = 0; i < node->n_ifaces; i++)
+       ifaces[i] = node->private.iface_entries[i].iface_type;
+      ifaces[i] = 0;
+
+      if (n_interfaces)
+       *n_interfaces = node->n_ifaces;
+
+      return ifaces;
+    }
+  else
+    {
+      if (n_interfaces)
+       *n_interfaces = 0;
+
+      return NULL;
+    }
+}
+
+typedef struct _QData QData;
+struct _GData
+{
+  guint  n_qdatas;
+  QData *qdatas;
+};
+struct _QData
+{
+  GQuark   quark;
+  gpointer data;
+};
+
+gpointer
+g_type_get_qdata (GType  type,
+                 GQuark quark)
+{
+  TypeNode *node = LOOKUP_TYPE_NODE (type);
+  GData *gdata;
+  
+  g_return_val_if_fail (node != NULL, NULL);
+
+  gdata = node->static_gdata;
+  if (quark && gdata && gdata->n_qdatas)
+    {
+      QData *qdatas = gdata->qdatas - 1;
+      guint n_qdatas = gdata->n_qdatas;
+
+      do                /* FIXME: should optimize qdata lookups for <= 4 */
+       {
+         guint i;
+         QData *check;
+
+         i = (n_qdatas + 1) / 2;
+         check = qdatas + i;
+         if (quark == check->quark)
+           return check->data;
+         else if (quark > check->quark)
+           {
+             n_qdatas -= i;
+             qdatas = check;
+           }
+         else /* if (quark < check->quark) */
+           n_qdatas = i - 1;
+       }
+      while (n_qdatas);
+    }
+
+  return NULL;
+}
+
+void
+g_type_set_qdata (GType    type,
+                 GQuark   quark,
+                 gpointer data)
+{
+  TypeNode *node = LOOKUP_TYPE_NODE (type);
+  GData *gdata;
+  QData *qdata;
+  guint i;
+
+  g_return_if_fail (node != NULL);
+  g_return_if_fail (quark != 0);
+
+  /* setup qdata list if necessary */
+  if (!node->static_gdata)
+    node->static_gdata = g_new0 (GData, 1);
+  gdata = node->static_gdata;
+
+  /* try resetting old data */
+  qdata = gdata->qdatas;
+  for (i = 0; i < gdata->n_qdatas; i++)
+    if (qdata[i].quark == quark)
+      {
+       qdata[i].data = data;
+       return;
+      }
+
+  /* add new entry */
+  gdata->n_qdatas++;
+  gdata->qdatas = g_renew (QData, gdata->qdatas, gdata->n_qdatas);
+  qdata = gdata->qdatas;
+  for (i = 0; i < gdata->n_qdatas - 1; i++)
+    if (qdata[i].quark > quark)
+      break;
+  g_memmove (qdata + i + 1, qdata + i, sizeof (qdata[0]) * (gdata->n_qdatas - i - 1));
+  qdata[i].quark = quark;
+  qdata[i].data = data;
+}
+
+
+/* --- implementation details --- */
+gboolean
+g_type_check_flags (GType      type,
+                   GTypeFlags flags)
+{
+  TypeNode *node = LOOKUP_TYPE_NODE (type);
+  
+  flags &= G_TYPE_FLAG_MASK;
+  if (node)
+    {
+      GTypeFundamentalInfo *finfo = type_node_fundamental_info (node);
+      
+      return (finfo->type_flags & flags) != 0;
+    }
+  
+  return FALSE;
+}
+
+gboolean
+g_type_is_dynamic (GType      type,
+                  GTypeFlags flags)
+{
+  TypeNode *node = LOOKUP_TYPE_NODE (type);
+
+  return node && node->plugin;
+}
+
+gboolean
+g_type_instance_conforms_to (GTypeInstance *type_instance,
+                            GType          iface_type)
+{
+  return (type_instance && type_instance->g_class &&
+         g_type_conforms_to (type_instance->g_class->g_type, iface_type));
+}
+
+gboolean
+g_type_class_is_a (GTypeClass *type_class,
+                  GType       is_a_type)
+{
+  return (type_class && g_type_is_a (type_class->g_type, is_a_type));
+}
+
+GTypeInstance*
+g_type_check_instance_cast (GTypeInstance *type_instance,
+                           GType          iface_type)
+{
+  if (!type_instance)
+    {
+      g_warning ("invalid cast from (NULL) pointer to `%s'",
+                type_descriptive_name (iface_type));
+      return type_instance;
+    }
+  if (!type_instance->g_class)
+    {
+      g_warning ("invalid unclassed pointer in cast to `%s'",
+                type_descriptive_name (iface_type));
+      return type_instance;
+    }
+  if (!G_TYPE_IS_CLASSED (type_instance->g_class->g_type))
+    {
+      g_warning ("invalid unclassed type `%s' in cast to `%s'",
+                type_descriptive_name (type_instance->g_class->g_type),
+                type_descriptive_name (iface_type));
+      return type_instance;
+    }
+  if (!g_type_conforms_to (type_instance->g_class->g_type, iface_type))
+    {
+      g_warning ("invalid cast from `%s' to `%s'",
+                type_descriptive_name (type_instance->g_class->g_type),
+                type_descriptive_name (iface_type));
+      return type_instance;
+    }
+
+  return type_instance;
+}
+
+GTypeClass*
+g_type_check_class_cast (GTypeClass *type_class,
+                        GType       is_a_type)
+{
+  if (!type_class)
+    {
+      g_warning ("invalid class cast from (NULL) pointer to `%s'",
+                type_descriptive_name (is_a_type));
+      return type_class;
+    }
+  if (!G_TYPE_IS_CLASSED (type_class->g_type))
+    {
+      g_warning ("invalid unclassed type `%s' in class cast to `%s'",
+                type_descriptive_name (type_class->g_type),
+                type_descriptive_name (is_a_type));
+      return type_class;
+    }
+  if (!g_type_is_a (type_class->g_type, is_a_type))
+    {
+      g_warning ("invalid class cast from `%s' to `%s'",
+                type_descriptive_name (type_class->g_type),
+                type_descriptive_name (is_a_type));
+      return type_class;
+    }
+
+  return type_class;
+}
+
+
+/* --- foreign prototypes --- */
+extern void     g_param_types_init              (void);        /* sync with glib-gparam.c */
+extern void    g_enum_types_init               (void); /* sync with glib-genums.c */
+extern void     g_object_type_init             (void); /* sync with glib-gobject.c */
+
+
+/* --- initialization --- */
+void
+g_type_init (void)
+{
+  static TypeNode *type0_node = NULL;
+  GTypeInfo info;
+  TypeNode *node;
+  GType type;
+
+  if (G_TYPE_FUNDAMENTAL_LAST)
+    return;
+
+  /* type qname hash table */
+  g_type_nodes_ht = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+  /* invalid type G_TYPE_INVALID (0)
+   */
+  _g_type_fundamental_last = 1;
+  g_type_nodes = g_renew (TypeNode**, g_type_nodes, G_TYPE_FUNDAMENTAL_LAST);
+  g_type_nodes[0] = &type0_node;
+  g_branch_seqnos = g_renew (GType, g_branch_seqnos, G_TYPE_FUNDAMENTAL_LAST);
+  g_branch_seqnos[0] = 1;
+
+  /* void type G_TYPE_NONE
+   */
+  node = type_node_fundamental_new (G_TYPE_NONE, "void", 0);
+  type = NODE_TYPE (node);
+  g_assert (type == G_TYPE_NONE);
+
+  /* interface fundamental type G_TYPE_INTERFACE (!classed)
+   */
+  memset (&info, 0, sizeof (info));
+  node = type_node_fundamental_new (G_TYPE_INTERFACE, "GInterface", G_TYPE_FLAG_DERIVABLE);
+  type = NODE_TYPE (node);
+  type_data_make (node, &info);
+  g_assert (type == G_TYPE_INTERFACE);
+
+  /* G_TYPE_ENUM & G_TYPE_FLAGS
+   */
+  g_enum_types_init ();
+
+  /* G_TYPE_PARAM
+   */
+  g_param_types_init ();
+
+  /* G_TYPE_OBJECT
+   */
+  g_object_type_init ();
+}
diff --git a/gobject/gtype.h b/gobject/gtype.h
new file mode 100644 (file)
index 0000000..5ddf4e9
--- /dev/null
@@ -0,0 +1,304 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 1998, 1999, 2000 Tim Janik and Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __G_TYPE_H__
+#define __G_TYPE_H__
+
+extern const char *g_log_domain_gobject;
+#include        <glib.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* Basic Type Macros
+ */
+#define G_TYPE_FUNDAMENTAL(type)                ((type) & 0xff)
+#define        G_TYPE_FUNDAMENTAL_MAX                  (0xff)
+#define G_TYPE_DERIVE_ID(ptype, branch_seqno)   (G_TYPE_FUNDAMENTAL (ptype) | ((branch_seqno) << 8))
+#define G_TYPE_BRANCH_SEQNO(type)               ((type) >> 8)
+#define G_TYPE_FUNDAMENTAL_LAST                 ((GType) _g_type_fundamental_last)
+
+
+/* predefined fundamental and derived types
+ */
+typedef enum    /*< skip >*/
+{
+  /* standard types, introduced by g_type_init() */
+  G_TYPE_INVALID,
+  G_TYPE_NONE,
+  G_TYPE_INTERFACE,
+
+  /* GLib type ids */
+  G_TYPE_ENUM,
+  G_TYPE_FLAGS,
+  G_TYPE_PARAM,
+  G_TYPE_OBJECT,
+
+  /* reserved type ids, mail gtk-devel-list@redhat.com for reservations */
+  G_TYPE_BSE_PROCEDURE,
+  G_TYPE_GLE_GOBJECT,
+
+  /* the following reserved ids should vanish soon */
+  G_TYPE_GTK_CHAR,
+  G_TYPE_GTK_UCHAR,
+  G_TYPE_GTK_BOOL,
+  G_TYPE_GTK_INT,
+  G_TYPE_GTK_UINT,
+  G_TYPE_GTK_LONG,
+  G_TYPE_GTK_ULONG,
+  G_TYPE_GTK_FLOAT,
+  G_TYPE_GTK_DOUBLE,
+  G_TYPE_GTK_STRING,
+  G_TYPE_GTK_BOXED,
+  G_TYPE_GTK_POINTER,
+  G_TYPE_GTK_SIGNAL,
+
+  G_TYPE_LAST_RESERVED_FUNDAMENTAL,
+
+  /* derived type ids */
+  G_TYPE_PARAM_CHAR             = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 1),
+  G_TYPE_PARAM_UCHAR            = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 2),
+  G_TYPE_PARAM_BOOL             = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 3),
+  G_TYPE_PARAM_INT              = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 4),
+  G_TYPE_PARAM_UINT             = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 5),
+  G_TYPE_PARAM_LONG             = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 6),
+  G_TYPE_PARAM_ULONG            = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 7),
+  G_TYPE_PARAM_ENUM             = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 8),
+  G_TYPE_PARAM_FLAGS            = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 9),
+  G_TYPE_PARAM_FLOAT            = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 10),
+  G_TYPE_PARAM_DOUBLE           = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 11),
+  G_TYPE_PARAM_STRING           = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 12),
+  G_TYPE_PARAM_OBJECT           = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 13)
+} GTypeFundamentals;
+
+
+/* Type Checking Macros
+ */
+#define G_TYPE_IS_INTERFACE(type)               (G_TYPE_FUNDAMENTAL (type) == G_TYPE_INTERFACE)
+#define G_TYPE_IS_CLASSED(type)                 (g_type_check_flags ((type), G_TYPE_FLAG_CLASSED))
+#define G_TYPE_IS_INSTANTIATABLE(type)          (g_type_check_flags ((type), G_TYPE_FLAG_INSTANTIATABLE))
+#define G_TYPE_IS_DERIVABLE(type)               (g_type_check_flags ((type), G_TYPE_FLAG_DERIVABLE))
+#define G_TYPE_IS_DEEP_DERIVABLE(type)          (g_type_check_flags ((type), G_TYPE_FLAG_DEEP_DERIVABLE))
+#define G_TYPE_IS_PARAM(type)                   (G_TYPE_FUNDAMENTAL (type) == G_TYPE_PARAM)
+
+
+/* Typedefs
+ */
+typedef guint32                         GType;
+typedef struct _GParam                  GParam;
+typedef struct _GTypePlugin             GTypePlugin;
+typedef struct _GTypePluginVTable       GTypePluginVTable;
+typedef struct _GTypeClass              GTypeClass;
+typedef struct _GTypeInterface          GTypeInterface;
+typedef struct _GTypeInstance           GTypeInstance;
+typedef struct _GTypeInfo               GTypeInfo;
+typedef struct _GTypeFundamentalInfo    GTypeFundamentalInfo;
+typedef struct _GInterfaceInfo          GInterfaceInfo;
+
+
+/* Basic Type Structures
+ */
+struct _GTypeClass
+{
+  GType g_type;
+};
+struct _GTypeInstance
+{
+  GTypeClass *g_class;
+};
+struct _GTypeInterface
+{
+  GType g_type;         /* iface type */
+  GType g_instance_type;
+};
+
+
+/* Casts, Checks And Convenience Macros For Structured Types
+ */
+#define G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type)    (_G_TYPE_CIC ((instance), (g_type), c_type))
+#define G_TYPE_CHECK_CLASS_CAST(g_class, g_type, c_type)        (_G_TYPE_CCC ((g_class), (g_type), c_type))
+#define G_TYPE_CHECK_INSTANCE_TYPE(instance, g_type)            (_G_TYPE_CIT ((instance), (g_type)))
+#define G_TYPE_CHECK_CLASS_TYPE(g_class, g_type)                (_G_TYPE_CCT ((g_class), (g_type)))
+#define G_TYPE_INSTANCE_GET_CLASS(instance, g_type, c_type)     (_G_TYPE_IGC ((instance), c_type))
+#define G_TYPE_FROM_INSTANCE(instance)                          (G_TYPE_FROM_CLASS (((GTypeInstance*) (instance))->g_class))
+#define G_TYPE_FROM_CLASS(g_class)                              (((GTypeClass*) (g_class))->g_type)
+
+
+/* --- prototypes --- */
+void     g_type_init                    (void);
+gchar*   g_type_name                    (GType                   type);
+GQuark   g_type_qname                   (GType                   type);
+GType    g_type_from_name               (const gchar            *name);
+GType    g_type_parent                  (GType                   type);
+GType    g_type_next_base               (GType                   type,
+                                         GType                   base_type);
+gboolean g_type_is_a                    (GType                   type,
+                                         GType                   is_a_type);
+gboolean g_type_conforms_to             (GType                   type,
+                                         GType                   iface_type);
+guint    g_type_fundamental_branch_last (GType                   type);
+gpointer g_type_class_ref               (GType                   type);
+gpointer g_type_class_peek              (GType                   type);
+void     g_type_class_unref             (gpointer                g_class);
+gpointer g_type_class_peek_parent       (gpointer                g_class);
+gpointer g_type_interface_peek          (gpointer                instance_class,
+                                         GType                   iface_type);
+/* g_free() the returned arrays */
+GType*   g_type_children                (GType                   type,
+                                         guint                  *n_children);
+GType*   g_type_interfaces              (GType                   type,
+                                         guint                  *n_interfaces);
+/* per-type *static* data */
+void     g_type_set_qdata               (GType                   type,
+                                         GQuark                  quark,
+                                         gpointer                data);
+gpointer g_type_get_qdata               (GType                   type,
+                                         GQuark                  quark);
+                                          
+
+/* --- type registration --- */
+typedef void   (*GBaseInitFunc)          (gpointer       g_class);
+typedef void   (*GBaseFinalizeFunc)      (gpointer       g_class);
+typedef void   (*GClassInitFunc)         (gpointer       g_class,
+                                         gpointer       class_data);
+typedef void   (*GClassFinalizeFunc)     (gpointer       g_class,
+                                         gpointer       class_data);
+typedef void   (*GInstanceInitFunc)      (GTypeInstance *instance,
+                                         gpointer       g_class);
+typedef void   (*GInterfaceInitFunc)     (gpointer       g_iface,
+                                         gpointer       iface_data);
+typedef void   (*GInterfaceFinalizeFunc) (gpointer       g_iface,
+                                         gpointer       iface_data);
+typedef gchar* (*GTypeParamCollector)    (GParam        *param,
+                                         guint          n_bytes,
+                                         guint8        *bytes);
+typedef void (*GTypePluginRef)               (GTypePlugin    *plugin);
+typedef void (*GTypePluginUnRef)             (GTypePlugin    *plugin);
+typedef void (*GTypePluginFillTypeInfo)      (GTypePlugin    *plugin,
+                                              GType           g_type,
+                                              GTypeInfo      *info);
+typedef void (*GTypePluginFillInterfaceInfo) (GTypePlugin    *plugin,
+                                              GType           interface_type,
+                                              GType           instance_type,
+                                              GInterfaceInfo *info);
+struct _GTypePlugin
+{
+  GTypePluginVTable     *vtable;
+};
+struct _GTypePluginVTable
+{
+  GTypePluginRef                plugin_ref;
+  GTypePluginUnRef              plugin_unref;
+  GTypePluginFillTypeInfo       complete_type_info;
+  GTypePluginFillInterfaceInfo  complete_interface_info;
+};
+typedef enum    /*< skip >*/
+{
+  G_TYPE_FLAG_CLASSED           = (1 << 0),
+  G_TYPE_FLAG_INSTANTIATABLE    = (1 << 1),
+  G_TYPE_FLAG_DERIVABLE         = (1 << 2),
+  G_TYPE_FLAG_DEEP_DERIVABLE    = (1 << 3)
+} GTypeFlags;
+struct _GTypeInfo
+{
+  /* interface types, classed types, instantiated types */
+  guint16                class_size;
+
+  GBaseInitFunc          base_init;
+  GBaseFinalizeFunc      base_finalize;
+
+  /* classed types, instantiated types */
+  GClassInitFunc         class_init;
+  GClassFinalizeFunc     class_finalize;
+  gconstpointer          class_data;
+
+  /* instantiated types */
+  guint16                instance_size;
+  guint16                n_preallocs;
+  GInstanceInitFunc      instance_init;
+};
+struct _GTypeFundamentalInfo
+{
+  GTypeFlags             type_flags;
+  guint                  n_collect_bytes;
+  GTypeParamCollector    param_collector;
+};
+struct _GInterfaceInfo
+{
+  GInterfaceInitFunc     interface_init;
+  GInterfaceFinalizeFunc interface_finalize;
+  gpointer               interface_data;
+};
+GType g_type_register_static       (GType                       parent_type,
+                                    const gchar                *type_name,
+                                    const GTypeInfo            *info);
+GType g_type_register_dynamic      (GType                       parent_type,
+                                    const gchar                *type_name,
+                                    GTypePlugin                *plugin);
+GType g_type_register_fundamental  (GType                       type_id,
+                                    const gchar                *type_name,
+                                    const GTypeFundamentalInfo *finfo,
+                                    const GTypeInfo            *info);
+void  g_type_add_interface_static  (GType                       instance_type,
+                                    GType                       interface_type,
+                                    GInterfaceInfo             *info);
+void  g_type_add_interface_dynamic (GType                       instance_type,
+                                    GType                       interface_type,
+                                    GTypePlugin                *plugin);
+
+
+/* --- implementation details --- */
+gboolean        g_type_class_is_a               (GTypeClass     *g_class,
+                                                 GType           is_a_type);
+GTypeClass*     g_type_check_class_cast         (GTypeClass     *g_class,
+                                                 GType           is_a_type);
+GTypeInstance*  g_type_check_instance_cast      (GTypeInstance  *instance,
+                                                 GType           iface_type);
+gboolean        g_type_instance_conforms_to     (GTypeInstance  *instance,
+                                                 GType           iface_type);
+gboolean        g_type_check_flags              (GType           type,
+                                                 GTypeFlags      flags);
+gboolean        g_type_is_dynamic               (GType           type,
+                                                 GTypeFlags      flags);
+GTypeInstance*  g_type_create_instance          (GType           type);
+void            g_type_free_instance            (GTypeInstance  *instance);
+
+#ifndef G_DISABLE_CAST_CHECKS
+#  define _G_TYPE_CIC(ip, gt, ct) \
+    ((ct*) g_type_check_instance_cast ((GTypeInstance*) ip, gt))
+#  define _G_TYPE_CCC(cp, gt, ct) \
+    ((ct*) g_type_check_class_cast ((GTypeClass*) cp, gt))
+#else /* G_DISABLE_CAST_CHECKS */
+#  define _G_TYPE_CIC(ip, gt, ct)       ((ct*) ip)
+#  define _G_TYPE_CCC(cp, gt, ct)       ((ct*) cp)
+#endif /* G_DISABLE_CAST_CHECKS */
+#define _G_TYPE_IGC(ip, ct)             ((ct*) (((GTypeInstance*) ip)->g_class))
+#define _G_TYPE_CIT(ip, gt)             (g_type_instance_conforms_to ((GTypeInstance*) ip, gt))
+#define _G_TYPE_CCT(cp, gt)             (g_type_class_is_a ((GTypeClass*) cp, gt))
+extern GType    _g_type_fundamental_last;
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __G_TYPE_H__ */
diff --git a/gobject/gvalue.c b/gobject/gvalue.c
new file mode 100644 (file)
index 0000000..d85a9f7
--- /dev/null
@@ -0,0 +1,374 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 1997, 1998, 1999, 2000 Tim Janik and Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include       "gvalue.h"
+
+
+/* --- defines --- */
+#define G_PARAM_SPEC_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_PARAM, GParamSpecClass))
+
+
+/* --- typedefs & structures --- */
+typedef struct
+{
+  GType          value_type1;
+  GType          value_type2;
+  GValueExchange func;
+  GType          first_type;
+} ExchangeEntry;
+
+
+/* --- variables --- */
+static GHashTable *param_exchange_ht = NULL;
+
+
+/* --- functions --- */
+void
+g_value_init (GValue *value,
+             GType   g_type)
+{
+  GParamSpecClass *pclass;
+
+  g_return_if_fail (value != NULL);
+  g_return_if_fail (G_VALUE_TYPE (value) == 0);
+  g_type = g_type_next_base (g_type, G_TYPE_PARAM);
+  g_return_if_fail (G_TYPE_IS_VALUE (g_type));
+
+  memset (value, 0, sizeof (*value));
+  value->g_type = g_type;
+
+  pclass = g_type_class_ref (G_VALUE_TYPE (value));
+  pclass->param_init (value, NULL);
+  g_type_class_unref (pclass);
+}
+
+void
+g_value_init_default (GValue     *value,
+                     GParamSpec *pspec)
+{
+  g_return_if_fail (value != NULL);
+  g_return_if_fail (G_VALUE_TYPE (value) == 0);
+  g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+
+  memset (value, 0, sizeof (*value));
+  value->g_type = g_type_next_base (G_PARAM_SPEC_TYPE (pspec), G_TYPE_PARAM);
+
+  G_PARAM_SPEC_GET_CLASS (pspec)->param_init (value, pspec);
+}
+
+gboolean
+g_value_validate (GValue     *value,
+                 GParamSpec *pspec)
+{
+  g_return_val_if_fail (G_IS_VALUE (value), FALSE);
+  g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
+  g_return_val_if_fail (g_type_is_a (G_PARAM_SPEC_TYPE (pspec), G_VALUE_TYPE (value)), FALSE);
+
+  if (G_PARAM_SPEC_GET_CLASS (pspec)->param_validate)
+    {
+      GValue oval = *value;
+      
+      if (G_PARAM_SPEC_GET_CLASS (pspec)->param_validate (value, pspec) ||
+         memcmp (&oval.data, &value->data, sizeof (oval.data)))
+       return TRUE;
+    }
+  return FALSE;
+}
+
+gboolean
+g_value_defaults (const GValue *value,
+                 GParamSpec   *pspec)
+{
+  GValue dflt_value = { 0, };
+  gboolean defaults;
+
+  g_return_val_if_fail (G_IS_VALUE (value), FALSE);
+  g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
+  g_return_val_if_fail (g_type_is_a (G_PARAM_SPEC_TYPE (pspec), G_VALUE_TYPE (value)), FALSE);
+  
+  dflt_value.g_type = g_type_next_base (G_PARAM_SPEC_TYPE (pspec), G_TYPE_PARAM);
+  G_PARAM_SPEC_GET_CLASS (pspec)->param_init (&dflt_value, pspec);
+  defaults = g_values_cmp (value, &dflt_value, pspec) == 0;
+  g_value_unset (&dflt_value);
+
+  return defaults;
+}
+
+void
+g_value_set_default (GValue     *value,
+                    GParamSpec *pspec)
+{
+  GValue tmp_value = { 0, };
+
+  g_return_if_fail (G_IS_VALUE (value));
+  g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+  g_return_if_fail (g_type_is_a (G_PARAM_SPEC_TYPE (pspec), G_VALUE_TYPE (value)));
+
+  /* retrive default value */
+  tmp_value.g_type = g_type_next_base (G_PARAM_SPEC_TYPE (pspec), G_TYPE_PARAM);
+  G_PARAM_SPEC_GET_CLASS (pspec)->param_init (&tmp_value, pspec);
+
+  /* set default value */
+  g_values_exchange (&tmp_value, value);
+
+  g_value_unset (&tmp_value);
+}
+
+gint
+g_values_cmp (const GValue *value1,
+             const GValue *value2,
+             GParamSpec   *pspec)
+{
+  GParamSpecClass *pclass;
+  gint cmp;
+
+  /* param_values_cmp() effectively does: value1 - value2
+   * so the return values are:
+   * -1)  value1 < value2
+   *  0)  value1 == value2
+   *  1)  value1 > value2
+   */
+  g_return_val_if_fail (G_IS_VALUE (value1), 0);
+  g_return_val_if_fail (G_IS_VALUE (value2), 0);
+  g_return_val_if_fail (G_VALUE_TYPE (value1) == G_VALUE_TYPE (value2), 0);
+  if (pspec)
+    {
+      g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), 0);
+      g_return_val_if_fail (g_type_is_a (G_PARAM_SPEC_TYPE (pspec), G_VALUE_TYPE (value1)), FALSE);
+    }
+
+  pclass = g_type_class_ref (G_VALUE_TYPE (value1));
+  cmp = pclass->param_values_cmp (value1, value2, pspec);
+  g_type_class_unref (pclass);
+
+  return CLAMP (cmp, -1, 1);
+}
+
+void
+g_value_copy (const GValue *src_value,
+             GValue       *dest_value)
+{
+  g_return_if_fail (G_IS_VALUE (src_value));
+  g_return_if_fail (G_IS_VALUE (dest_value));
+  g_return_if_fail (G_VALUE_TYPE (src_value) == G_VALUE_TYPE (dest_value));
+
+  if (src_value != dest_value)
+    {
+      GParamSpecClass *pclass = g_type_class_ref (G_VALUE_TYPE (src_value));
+      
+      /* make sure dest_value's value is free()d and zero initialized */
+      g_value_reset (dest_value);
+      
+      if (pclass->param_copy_value)
+       pclass->param_copy_value (src_value, dest_value);
+      else
+       memcpy (&dest_value->data, &src_value->data, sizeof (src_value->data));
+      g_type_class_unref (pclass);
+    }
+}
+
+void
+g_value_unset (GValue *value)
+{
+  GParamSpecClass *pclass;
+
+  g_return_if_fail (G_IS_VALUE (value));
+
+  pclass = g_type_class_ref (G_VALUE_TYPE (value));
+  if (pclass->param_free_value)
+    pclass->param_free_value (value);
+  memset (value, 0, sizeof (*value));
+  g_type_class_unref (pclass);
+}
+
+void
+g_value_reset (GValue *value)
+{
+  GParamSpecClass *pclass;
+  GType g_type;
+
+  g_return_if_fail (G_IS_VALUE (value));
+
+  g_type = G_VALUE_TYPE (value);
+  pclass = g_type_class_ref (g_type);
+
+  if (pclass->param_free_value)
+    pclass->param_free_value (value);
+  memset (value, 0, sizeof (*value));
+
+  value->g_type = g_type;
+  pclass->param_init (value, NULL);
+  
+  g_type_class_unref (pclass);
+}
+
+static gint
+exchange_entries_equal (gconstpointer v1,
+                       gconstpointer v2)
+{
+  const ExchangeEntry *entry1 = v1;
+  const ExchangeEntry *entry2 = v2;
+
+  return (entry1->value_type1 == entry2->value_type1 &&
+         entry1->value_type2 == entry2->value_type2);
+}
+
+static guint
+exchange_entry_hash (gconstpointer key)
+{
+  const ExchangeEntry *entry = key;
+
+  return entry->value_type1 ^ entry->value_type2;
+}
+
+static void
+value_exchange_memcpy (GValue *value1,
+                      GValue *value2)
+{
+  GValue tmp_value;
+
+  memcpy (&tmp_value.data, &value1->data, sizeof (value1->data));
+  memcpy (&value1->data, &value2->data, sizeof (value1->data));
+  memcpy (&value2->data, &tmp_value.data, sizeof (value2->data));
+}
+
+static inline GValueExchange
+exchange_func_lookup (GType     value_type1,
+                     GType     value_type2,
+                     gboolean *need_swap)
+{
+  if (value_type1 == value_type2)
+    return value_exchange_memcpy;
+  else
+    {
+      ExchangeEntry entry, *ret;
+      
+      entry.value_type1 = MIN (value_type1, value_type2);
+      entry.value_type2 = MAX (value_type1, value_type2);
+      
+      ret = g_hash_table_lookup (param_exchange_ht, &entry);
+      if (ret)
+       {
+         if (need_swap)
+           *need_swap = ret->first_type == value_type1;
+
+         return ret->func;
+       }
+    }
+  return NULL;
+}
+
+void
+g_value_register_exchange_func (GType          value_type1,
+                               GType          value_type2,
+                               GValueExchange func)
+{
+  GType type1, type2;
+
+  g_return_if_fail (G_TYPE_IS_VALUE (value_type1));
+  g_return_if_fail (G_TYPE_IS_VALUE (value_type2));
+  g_return_if_fail (func != NULL);
+
+  type1 = g_type_next_base (value_type1, G_TYPE_PARAM);
+  type2 = g_type_next_base (value_type2, G_TYPE_PARAM);
+
+  if (param_exchange_ht && exchange_func_lookup (type1, type2, NULL))
+    g_warning (G_STRLOC ": cannot re-register param value exchange function "
+              "for `%s' and `%s'",
+              g_type_name (type1),
+              g_type_name (type2));
+  else
+    {
+      ExchangeEntry *entry = g_new (ExchangeEntry, 1);
+
+      if (!param_exchange_ht)
+       param_exchange_ht = g_hash_table_new (exchange_entry_hash, exchange_entries_equal);
+      entry->value_type1 = MIN (type1, type2);
+      entry->value_type2 = MAX (type1, type2);
+      entry->func = func;
+      entry->first_type = type1;
+      g_hash_table_insert (param_exchange_ht, entry, entry);
+    }
+}
+
+gboolean
+g_value_types_exchangable (GType value_type1,
+                          GType value_type2)
+{
+  GType type1, type2;
+
+  g_return_val_if_fail (G_TYPE_IS_VALUE (value_type1), FALSE);
+  g_return_val_if_fail (G_TYPE_IS_VALUE (value_type2), FALSE);
+
+  type1 = g_type_next_base (value_type1, G_TYPE_PARAM);
+  type2 = g_type_next_base (value_type2, G_TYPE_PARAM);
+
+  return exchange_func_lookup (type1, type2, NULL) != NULL;
+}
+
+gboolean
+g_values_exchange (GValue *value1,
+                  GValue *value2)
+{
+  g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
+  g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
+
+  if (value1 != value2)
+    {
+      GType type1 = g_type_next_base (G_VALUE_TYPE (value1), G_TYPE_PARAM);
+      GType type2 = g_type_next_base (G_VALUE_TYPE (value2), G_TYPE_PARAM);
+      gboolean need_swap;
+      GValueExchange value_exchange = exchange_func_lookup (type1,
+                                                           type2,
+                                                           &need_swap);
+      if (value_exchange)
+       {
+         if (need_swap)
+           value_exchange (value2, value1);
+         else
+           value_exchange (value1, value2);
+       }
+
+      return value_exchange != NULL;
+    }
+
+  return TRUE;
+}
+
+gboolean
+g_value_convert (const GValue *src_value,
+                GValue       *dest_value)
+{
+  gboolean success = TRUE;
+
+  g_return_val_if_fail (G_IS_VALUE (src_value), FALSE);
+  g_return_val_if_fail (G_IS_VALUE (dest_value), FALSE);
+
+  if (src_value != dest_value)
+    {
+      GValue tmp_value = { 0, };
+
+      g_value_init (&tmp_value, G_VALUE_TYPE (src_value));
+      g_value_copy (src_value, &tmp_value);
+      
+      success = g_values_exchange (&tmp_value, dest_value);
+      g_value_unset (&tmp_value);
+    }
+
+  return success;
+}
diff --git a/gobject/gvalue.h b/gobject/gvalue.h
new file mode 100644 (file)
index 0000000..697e1df
--- /dev/null
@@ -0,0 +1,92 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 1997, 1998, 1999, 2000 Tim Janik and Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * gvalue.h: generic GValue functions
+ */
+#ifndef __G_VALUE_H__
+#define __G_VALUE_H__
+
+
+#include       <gobject/gparam.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* --- type macros --- */
+#define G_TYPE_IS_VALUE(type)          (G_TYPE_FUNDAMENTAL (type) == G_TYPE_PARAM)
+#define        G_IS_VALUE(value)               (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_PARAM))
+#define        G_VALUE_TYPE(value)             (G_TYPE_FROM_CLASS (value))
+#define        G_VALUE_TYPE_NAME(value)        (g_type_name (G_VALUE_TYPE (value)))
+
+
+/* --- typedefs & structures --- */
+/* typedef struct _GValue           GValue; */
+struct _GValue
+{
+  GType           g_type;      /* param value type */
+
+  union {
+    gint       v_int;
+    guint      v_uint;
+    glong      v_long;
+    gulong     v_ulong;
+    gfloat     v_float;
+    gdouble    v_double;
+    gpointer   v_pointer;
+  } data[4];
+};
+
+
+/* --- prototypes --- */
+void            g_value_init           (GValue       *value,
+                                        GType         g_type);
+void            g_value_init_default   (GValue       *value,
+                                        GParamSpec   *pspec);
+gboolean        g_value_validate       (GValue       *value,
+                                        GParamSpec   *pspec);
+gboolean        g_value_defaults       (const GValue *value,
+                                        GParamSpec   *pspec);
+void            g_value_set_default    (GValue       *value,
+                                        GParamSpec   *pspec);
+gint            g_values_cmp           (const GValue *value1,
+                                        const GValue *value2,
+                                        GParamSpec   *pspec);
+void            g_value_copy           (const GValue *src_value,
+                                        GValue       *dest_value);
+gboolean       g_value_convert         (const GValue *src_value,
+                                        GValue       *dest_value);
+gboolean        g_values_exchange      (GValue       *value1,
+                                        GValue       *value2);
+void            g_value_reset          (GValue       *value);
+void            g_value_unset          (GValue       *value);
+
+
+/* --- implementation bits --- */
+gboolean g_value_types_exchangable     (GType         value_type1,
+                                        GType         value_type2);
+void     g_value_register_exchange_func        (GType         value_type1,
+                                        GType         value_type2,
+                                        GValueExchange func);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __G_VALUE_H__ */
diff --git a/gobject/gvaluecollector.h b/gobject/gvaluecollector.h
new file mode 100644 (file)
index 0000000..b62c262
--- /dev/null
@@ -0,0 +1,174 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 1998, 1999, 2000 Tim Janik and Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * gvaluecollector.h: GValue varargs stubs
+ */
+#ifndef __G_VALUE_COLLECTOR_H__
+#define __G_VALUE_COLLECTOR_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* we may want to add aggregate types here some day, if requested
+ * by users. the basic C types are covered already, everything
+ * smaller than an int is promoted to an integer and floats are
+ * always promoted to doubles for varargs call constructions.
+ */
+enum   /*< skip >*/
+{
+  G_VALUE_COLLECT_NONE,
+  G_VALUE_COLLECT_INT,
+  G_VALUE_COLLECT_LONG,
+  G_VALUE_COLLECT_DOUBLE,
+  G_VALUE_COLLECT_POINTER
+};
+
+union _GParamCValue
+{
+  gint     v_int;
+  glong    v_long;
+  gdouble  v_double;
+  gpointer v_pointer;
+};
+
+
+/* G_PARAM_COLLECT_VALUE() collects a parameter's variable arguments
+ * from a va_list. we have to implement the varargs collection as a
+ * macro, because on some systems va_list variables cannot be passed
+ * by reference.
+ * param_value is supposed to be initialized according to the param
+ * type to be collected.
+ * the param_spec argument is optional, but probably needed by most
+ * param class' param_collect_value() implementations.
+ * var_args is the va_list variable and may be evaluated multiple times.
+ * __error is a gchar** variable that will be modified to hold a g_new()
+ * allocated error messages if something fails.
+ */
+#define G_PARAM_COLLECT_VALUE(param_value, param_spec, var_args, __error)              \
+G_STMT_START {                                                                         \
+  GValue *_value = (param_value);                                                      \
+  GParamSpecClass *_pclass = g_type_class_ref (_value->g_type);                                \
+  GParamSpec *_pspec = (param_spec);                                                   \
+  gchar *_error_msg = NULL;                                                            \
+  guint _collect_type = _pclass->collect_type;                                         \
+  guint _nth_value = 0;                                                                        \
+                                                                                        \
+  if (_pspec)                                                                          \
+    g_param_spec_ref (_pspec);                                                         \
+  g_value_reset (_value);                                                              \
+  while (_collect_type && !_error_msg)                                                 \
+    {                                                                                  \
+      GParamCValue _cvalue;                                                            \
+                                                                                        \
+      memset (&_cvalue, 0, sizeof (_cvalue));                                          \
+      switch (_collect_type)                                                           \
+       {                                                                               \
+       case G_VALUE_COLLECT_INT:                                                       \
+         _cvalue.v_int = va_arg ((var_args), gint);                                    \
+         break;                                                                        \
+       case G_VALUE_COLLECT_LONG:                                                      \
+         _cvalue.v_long = va_arg ((var_args), glong);                                  \
+         break;                                                                        \
+       case G_VALUE_COLLECT_DOUBLE:                                                    \
+         _cvalue.v_double = va_arg ((var_args), gdouble);                              \
+         break;                                                                        \
+       case G_VALUE_COLLECT_POINTER:                                                   \
+         _cvalue.v_pointer = va_arg ((var_args), gpointer);                            \
+         break;                                                                        \
+       default:                                                                        \
+         _error_msg  = g_strdup_printf ("%s: invalid collect type (%d) used for %s",   \
+                                        G_STRLOC,                                      \
+                                        _collect_type,                                 \
+                                        "G_PARAM_COLLECT_VALUE()");                    \
+         continue;                                                                     \
+       }                                                                               \
+      _error_msg = _pclass->param_collect_value (_value,                               \
+                                                _pspec,                                \
+                                                _nth_value++,                          \
+                                                &_collect_type,                        \
+                                                &_cvalue);                             \
+    }                                                                                  \
+  *(__error) = _error_msg;                                                             \
+  if (_pspec)                                                                          \
+    g_param_spec_unref (_pspec);                                                       \
+  g_type_class_unref (_pclass);                                                                \
+} G_STMT_END
+
+
+/* G_PARAM_LCOPY_VALUE() collects a parameter's variable argument
+ * locations from a va_list. usage is analogous to G_PARAM_COLLECT_VALUE().
+ */
+#define G_PARAM_LCOPY_VALUE(param_value, param_spec, var_args, __error)                        \
+G_STMT_START {                                                                         \
+  GValue *_value = (param_value);                                                      \
+  GParamSpecClass *_pclass = g_type_class_ref (_value->g_type);                                \
+  GParamSpec *_pspec = (param_spec);                                                   \
+  gchar *_error_msg = NULL;                                                            \
+  guint _lcopy_type = _pclass->lcopy_type;                                             \
+  guint _nth_value = 0;                                                                        \
+                                                                                        \
+  if (_pspec)                                                                          \
+    g_param_spec_ref (_pspec);                                                         \
+  while (_lcopy_type && !_error_msg)                                                   \
+    {                                                                                  \
+      GParamCValue _cvalue;                                                            \
+                                                                                        \
+      memset (&_cvalue, 0, sizeof (_cvalue));                                          \
+      switch (_lcopy_type)                                                             \
+       {                                                                               \
+       case G_VALUE_COLLECT_INT:                                                       \
+         _cvalue.v_int = va_arg ((var_args), gint);                                    \
+         break;                                                                        \
+       case G_VALUE_COLLECT_LONG:                                                      \
+         _cvalue.v_long = va_arg ((var_args), glong);                                  \
+         break;                                                                        \
+       case G_VALUE_COLLECT_DOUBLE:                                                    \
+         _cvalue.v_double = va_arg ((var_args), gdouble);                              \
+         break;                                                                        \
+       case G_VALUE_COLLECT_POINTER:                                                   \
+         _cvalue.v_pointer = va_arg ((var_args), gpointer);                            \
+         break;                                                                        \
+       default:                                                                        \
+         _error_msg  = g_strdup_printf ("%s: invalid collect type (%d) used for %s",   \
+                                        G_STRLOC,                                      \
+                                        _lcopy_type,                                   \
+                                        "G_PARAM_LCOPY_VALUE()");                      \
+         continue;                                                                     \
+       }                                                                               \
+      _error_msg = _pclass->param_lcopy_value (_value,                                 \
+                                              _pspec,                                  \
+                                              _nth_value++,                            \
+                                              &_lcopy_type,                            \
+                                              &_cvalue);                               \
+    }                                                                                  \
+  *(__error) = _error_msg;                                                             \
+  if (_pspec)                                                                          \
+    g_param_spec_unref (_pspec);                                                       \
+  g_type_class_unref (_pclass);                                                                \
+} G_STMT_END
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __G_VALUE_COLLECTOR_H__ */