added newly added gobject/ headers.
authorTim Janik <timj@gtk.org>
Wed, 25 Oct 2000 20:36:35 +0000 (20:36 +0000)
committerTim Janik <timj@src.gnome.org>
Wed, 25 Oct 2000 20:36:35 +0000 (20:36 +0000)
Tue Oct 24 22:09:14 2000  Tim Janik  <timj@gtk.org>

        * glib-object.h: added newly added gobject/ headers.

        * gmesage.c: print g_message() output to stderr instead of stdout.

Wed Oct 25 20:27:02 2000  Tim Janik  <timj@gtk.org>

        * gtype.c (g_type_free_instance): for the moment, freeing object
        structures will fill their memory portion with 0xAA. there's a
        FIXME there, remove this line at a later point.

Tue Oct 24 23:10:26 2000  Tim Janik  <timj@gtk.org>

        * glib-genmarshal.1:
        * glib-genmarshal.c: added publically installed marshaller generator.

        * gtype.h: added G_TYPE_INSTANCE_GET_INTERFACE() to retrive a certain
        interface VTable from instances.

Mon Oct 23 08:28:15 2000  Tim Janik  <timj@gtk.org>

        * gobject.[hc]: new functions for closure maintenance:
        (g_object_watch_closure): maintain validity of the object and
        the closure for objects that are used as data part of a closure.
        (g_cclosure_new_object): convenience function to create C closures
        that have an object as data argument.
        (g_closure_new_object): convenience function to create closures
        that have an object as data argument.

        * gclosure.[hc]: implementation of GClosure mechanism.
        a closure is basically an encapsulation of a callback function
        and its environment. ideally, most places supporting callback
        functions will simply take a GClosure* pointer and thus unify
        callback environments wrg destroy notification etc.
        GClosure provides destroy notifiers for arbitrary data pointers,
        reference counting, invalidation notification (it can be invalidated
        which is merely a deactivate state) and a marshallinbg abstraction.
        GCClosure is also provided in these files, they present a specialized
        GClosure implementation for C language callbacks.

        * genum.c: macro cleanups.

        * gboxed.[hc]: new files, for boxed type abstraction.
        (g_boxed_copy): copy a boxed structure
        (g_boxed_free): free a boxed structure
        (g_value_set_boxed):
        (g_value_get_boxed): standard GValue functions for boxed types
        (g_boxed_type_register_static): convenience function for easy
        introduction of new G_TYPE_BOXED derivatives.

        * gparam.[hc]: introduced g_param_type_register_static(), a short hand
        for creation of new GParamSpec derived types.

        * gtype.[hc]: many fixes, introduced ability to flag individual
        type nodes as ABSTRACT upon registration, added value_peek_pointer()
        to the value table to peek at GValue contents as a pointer for types
        that support this. fixed up GValue checks.

        * gvalue.[hc]: added g_value_fits_pointer() and g_value_get_as_pointer()
        to peek at the value contents as pointer.

        * *.[hc]: adaptions to type macro fixes and changes in the type
        registration API.

        * many const corrections over the place.

Sat Oct 21 02:49:56 2000  Tim Janik  <timj@gtk.org>

        * gtype.c (g_type_conforms_to): this function basically behaves like
        and is_a check, except that it _additionally_ features interfaces
        for instantiatable types. enforce this in the second branch as well
        (`type' conforms_to `type') even if `type' is not an interface type.

Fri Oct 20 15:31:04 2000  Tim Janik  <timj@gtk.org>

        * gvaluetypes.[hc]: added G_TYPE_POINTER implementation from jrb.

        * gtype.[hc]:
        * gobject.c:
        * gvaluetypes.c: added GTypeValueTable.value_peek_pointer and
        suitable implementations of this for G_TYPE_STRING, G_TYPE_OBJECT
        and G_TYPE_POINTER.

Mon Aug 21 04:13:37 2000  Tim Janik  <timj@gtk.org>

        * gbsearcharray.[hc]: long standing needed generic implementation
        of a binary searchable, sorted and dynamically sized array.

46 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-12
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
docs/reference/glib/tmpl/glib-unused.sgml
docs/reference/glib/tmpl/macros_misc.sgml
docs/reference/glib/tmpl/memory.sgml
docs/reference/glib/tmpl/random_numbers.sgml
docs/reference/glib/tmpl/trees-nary.sgml
docs/reference/gobject/tmpl/types.sgml
glib-object.h
glib/gbsearcharray.c [new file with mode: 0644]
glib/gbsearcharray.h [new file with mode: 0644]
glib/glib-object.h
glib/gmessages.c
gmessages.c
gobject/ChangeLog
gobject/Makefile.am
gobject/gboxed.c [new file with mode: 0644]
gobject/gboxed.h [new file with mode: 0644]
gobject/gbsearcharray.c [new file with mode: 0644]
gobject/gbsearcharray.h [new file with mode: 0644]
gobject/gclosure.c [new file with mode: 0644]
gobject/gclosure.h [new file with mode: 0644]
gobject/genums.c
gobject/genums.h
gobject/glib-genmarshal.1 [new file with mode: 0644]
gobject/glib-genmarshal.c [new file with mode: 0644]
gobject/gobject-query.c
gobject/gobject.c
gobject/gobject.h
gobject/gparam.c
gobject/gparam.h
gobject/gparamspecs.c
gobject/gsignal.c [new file with mode: 0644]
gobject/gsignal.h [new file with mode: 0644]
gobject/gtype.c
gobject/gtype.h
gobject/gvalue.c
gobject/gvalue.h
gobject/gvaluetypes.c
gobject/gvaluetypes.h

index 0e5540fd2f987d370168d6954f0251baa1e81b20..b723ec8434f5e080d1adecf9b9eacc9a69e006ec 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Tue Oct 24 22:09:14 2000  Tim Janik  <timj@gtk.org>
+
+       * glib-object.h: added newly added gobject/ headers.
+
+       * gmesage.c: print g_message() output to stderr instead of stdout.
+
 2000-10-23  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
 
        * configure.in: Use one = instead of two, which is plainly wrong.
index 0e5540fd2f987d370168d6954f0251baa1e81b20..b723ec8434f5e080d1adecf9b9eacc9a69e006ec 100644 (file)
@@ -1,3 +1,9 @@
+Tue Oct 24 22:09:14 2000  Tim Janik  <timj@gtk.org>
+
+       * glib-object.h: added newly added gobject/ headers.
+
+       * gmesage.c: print g_message() output to stderr instead of stdout.
+
 2000-10-23  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
 
        * configure.in: Use one = instead of two, which is plainly wrong.
index 0e5540fd2f987d370168d6954f0251baa1e81b20..b723ec8434f5e080d1adecf9b9eacc9a69e006ec 100644 (file)
@@ -1,3 +1,9 @@
+Tue Oct 24 22:09:14 2000  Tim Janik  <timj@gtk.org>
+
+       * glib-object.h: added newly added gobject/ headers.
+
+       * gmesage.c: print g_message() output to stderr instead of stdout.
+
 2000-10-23  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
 
        * configure.in: Use one = instead of two, which is plainly wrong.
index 0e5540fd2f987d370168d6954f0251baa1e81b20..b723ec8434f5e080d1adecf9b9eacc9a69e006ec 100644 (file)
@@ -1,3 +1,9 @@
+Tue Oct 24 22:09:14 2000  Tim Janik  <timj@gtk.org>
+
+       * glib-object.h: added newly added gobject/ headers.
+
+       * gmesage.c: print g_message() output to stderr instead of stdout.
+
 2000-10-23  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
 
        * configure.in: Use one = instead of two, which is plainly wrong.
index 0e5540fd2f987d370168d6954f0251baa1e81b20..b723ec8434f5e080d1adecf9b9eacc9a69e006ec 100644 (file)
@@ -1,3 +1,9 @@
+Tue Oct 24 22:09:14 2000  Tim Janik  <timj@gtk.org>
+
+       * glib-object.h: added newly added gobject/ headers.
+
+       * gmesage.c: print g_message() output to stderr instead of stdout.
+
 2000-10-23  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
 
        * configure.in: Use one = instead of two, which is plainly wrong.
index 0e5540fd2f987d370168d6954f0251baa1e81b20..b723ec8434f5e080d1adecf9b9eacc9a69e006ec 100644 (file)
@@ -1,3 +1,9 @@
+Tue Oct 24 22:09:14 2000  Tim Janik  <timj@gtk.org>
+
+       * glib-object.h: added newly added gobject/ headers.
+
+       * gmesage.c: print g_message() output to stderr instead of stdout.
+
 2000-10-23  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
 
        * configure.in: Use one = instead of two, which is plainly wrong.
index 0e5540fd2f987d370168d6954f0251baa1e81b20..b723ec8434f5e080d1adecf9b9eacc9a69e006ec 100644 (file)
@@ -1,3 +1,9 @@
+Tue Oct 24 22:09:14 2000  Tim Janik  <timj@gtk.org>
+
+       * glib-object.h: added newly added gobject/ headers.
+
+       * gmesage.c: print g_message() output to stderr instead of stdout.
+
 2000-10-23  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
 
        * configure.in: Use one = instead of two, which is plainly wrong.
index 0e5540fd2f987d370168d6954f0251baa1e81b20..b723ec8434f5e080d1adecf9b9eacc9a69e006ec 100644 (file)
@@ -1,3 +1,9 @@
+Tue Oct 24 22:09:14 2000  Tim Janik  <timj@gtk.org>
+
+       * glib-object.h: added newly added gobject/ headers.
+
+       * gmesage.c: print g_message() output to stderr instead of stdout.
+
 2000-10-23  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
 
        * configure.in: Use one = instead of two, which is plainly wrong.
index 268f8b4c4ecead793761f34bde1e13b83af4e90c..41191a84296f0195fd1f1dd1b2be2dc1f56da285 100644 (file)
-<!-- ##### MACRO lseek ##### -->
+<!-- ##### MACRO popen ##### -->
 <para>
 
 </para>
 
 
-<!-- ##### USER_FUNCTION GSearchFunc ##### -->
+<!-- ##### MACRO pclose ##### -->
 <para>
-Specifies the type of function passed to g_tree_search().
-</para>
 
-@key: a key from a #GTree.
-@data: the data to compare with the key.
-@Returns: 0 if the desired key has been found, a negative number if the
-desired key comes before @key in the sort order of the #GTree, or a positive
-value if the desired key comes after @key.
-
-<!-- ##### FUNCTION g_node_insert_after ##### -->
-<para>
-Inserts a #GNode beneath the parent after the given sibling.
 </para>
 
-@parent: the #GNode to place @node under.
-@sibling: the sibling #GNode to place @node after. If sibling is NULL,
-the node is inserted as the first child of @parent.
-@node: the #GNode to insert.
-@Returns: the inserted #GNode.
 
-<!-- ##### FUNCTION g_convert_error_quark ##### -->
+<!-- ##### MACRO lseek ##### -->
 <para>
 
 </para>
 
-@Returns: 
 
-<!-- ##### MACRO write ##### -->
+<!-- ##### MACRO getpid ##### -->
 <para>
 
 </para>
 
 
-<!-- ##### MACRO pclose ##### -->
+<!-- ##### MACRO close ##### -->
 <para>
 
 </para>
 
 
-<!-- ##### MACRO g_string ##### -->
+<!-- ##### MACRO fdopen ##### -->
 <para>
-Turns the argument into a string literal by using the '#' stringizing operator.
+
 </para>
 
-@x: text to convert to a literal string.
 
-<!-- ##### MACRO popen ##### -->
+<!-- ##### MACRO getcwd ##### -->
 <para>
 
 </para>
 
 
-<!-- ##### MACRO access ##### -->
+<!-- ##### USER_FUNCTION GSearchFunc ##### -->
 <para>
-
+Specifies the type of function passed to g_tree_search().
 </para>
 
+@key: a key from a #GTree.
+@data: the data to compare with the key.
+@Returns: 0 if the desired key has been found, a negative number if the
+desired key comes before @key in the sort order of the #GTree, or a positive
+value if the desired key comes after @key.
 
-<!-- ##### MACRO open ##### -->
+<!-- ##### MACRO write ##### -->
 <para>
 
 </para>
 
 
-<!-- ##### MACRO getpid ##### -->
+<!-- ##### MACRO access ##### -->
 <para>
 
 </para>
 
 
-<!-- ##### MACRO fdopen ##### -->
+<!-- ##### MACRO g_string ##### -->
 <para>
-
+Turns the argument into a string literal by using the '#' stringizing operator.
 </para>
 
+@x: text to convert to a literal string.
 
-<!-- ##### MACRO close ##### -->
+<!-- ##### MACRO read ##### -->
 <para>
 
 </para>
 
 
-<!-- ##### MACRO getcwd ##### -->
+<!-- ##### FUNCTION g_convert_error_quark ##### -->
 <para>
 
 </para>
 
+@Returns: 
 
-<!-- ##### MACRO read ##### -->
+<!-- ##### MACRO open ##### -->
 <para>
 
 </para>
index c6fbded21b9524977d5795c7ae8ae8431da0e0ad..06912edb867c686a77e0f29bdaea2b804564cfd5 100644 (file)
@@ -39,6 +39,20 @@ only one statement is expected by the compiler.
 
 
 
+<!-- ##### MACRO G_BEGIN_DECLS ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### MACRO G_END_DECLS ##### -->
+<para>
+
+</para>
+
+
+
 <!-- ##### MACRO G_N_ELEMENTS ##### -->
 <para>
 
@@ -52,6 +66,7 @@ only one statement is expected by the compiler.
 Portable way to copy <type>va_list</type> variables.
 </para>
 
+<!-- # Unused Parameters # -->
 @ap1: the <type>va_list</type> variable to place a copy of @ap2 in.
 @ap2: a <type>va_list</type>.
 
@@ -101,6 +116,13 @@ It avoids possible compiler warnings. See the GNU C documentation for details.
 
 
 
+<!-- ##### MACRO G_GNUC_PURE ##### -->
+<para>
+
+</para>
+
+
+
 <!-- ##### MACRO G_GNUC_PRINTF ##### -->
 <para>
 Expands to the GNU C format function attribute if the compiler is GNU C.
index 4a6e1b4349be09000d737e6f57cc19966fafe10c..dbab0b58655f44ac6d6a1d68f0f95dd77a7350c9 100644 (file)
@@ -98,6 +98,14 @@ If @mem is NULL it simply returns.
 @mem: the memory to free.
 
 
+<!-- ##### MACRO g_alloca ##### -->
+<para>
+
+</para>
+
+@size: 
+
+
 <!-- ##### MACRO g_memmove ##### -->
 <para>
 Copies a block of memory @n bytes long, from @s to @d.
index 6b9c8fc06629653ecd478f5b451ca27e6ca690b6..c2b34c51f83f7f14c6982a65eaa5ff6278c37161 100644 (file)
@@ -40,22 +40,107 @@ produce highly random lower bits too, but it is common not to rely on
 that, so choosing @a to be from 4 to 31 might be wise.
 </para>
 
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
 <!-- ##### STRUCT GRand ##### -->
 <para>
 The #GRand struct is an opaque data structure. It should only be
 accessed through the g_rand_* functions.
 </para>
 
+
 <!-- ##### FUNCTION g_rand_new_with_seed ##### -->
+
+
+@seed: 
+@Returns: 
+
+
 <!-- ##### FUNCTION g_rand_new ##### -->
+
+
+@Returns: 
+
+
 <!-- ##### FUNCTION g_rand_free ##### -->
+
+
+@rand: 
+
+
 <!-- ##### FUNCTION g_rand_set_seed ##### -->
+
+
+@rand: 
+@seed: 
+
+
 <!-- ##### FUNCTION g_rand_int ##### -->
+
+
+@rand: 
+@Returns: 
+
+
 <!-- ##### FUNCTION g_rand_int_range ##### -->
+
+
+@rand: 
+@min: 
+@max: 
+@Returns: 
+
+
 <!-- ##### FUNCTION g_rand_double ##### -->
+
+
+@rand: 
+@Returns: 
+
+
 <!-- ##### FUNCTION g_rand_double_range ##### -->
+
+
+@rand: 
+@min: 
+@max: 
+@Returns: 
+
+
 <!-- ##### FUNCTION g_random_set_seed ##### -->
+
+
+@seed: 
+
+
 <!-- ##### FUNCTION g_random_int ##### -->
+
+
+@Returns: 
+
+
 <!-- ##### FUNCTION g_random_int_range ##### -->
+
+
+@min: 
+@max: 
+@Returns: 
+
+
 <!-- ##### FUNCTION g_random_double ##### -->
+
+
+@Returns: 
+
+
 <!-- ##### FUNCTION g_random_double_range ##### -->
+
+
+@min: 
+@max: 
+@Returns: 
+
+
index 2019c861b12ddea5b037226e5bade26cfb2d66b5..8916fa69bf41f37c3b13571731d66eb141bdf938 100644 (file)
@@ -113,6 +113,18 @@ the node is inserted as the last child of @parent.
 @Returns: the inserted #GNode.
 
 
+<!-- ##### FUNCTION g_node_insert_after ##### -->
+<para>
+Inserts a #GNode beneath the parent after the given sibling.
+</para>
+
+@parent: the #GNode to place @node under.
+@sibling: the sibling #GNode to place @node after. If sibling is NULL,
+the node is inserted as the first child of @parent.
+@node: the #GNode to insert.
+@Returns: the inserted #GNode.
+
+
 <!-- ##### MACRO g_node_append ##### -->
 <para>
 Inserts a #GNode as the last child of the given parent.
index a42851cf19b6dd4acb2ae79ba47f28fce0721d6c..f5cc2fb9c4b35fd8631a2dea1b0c62b6a01b16c2 100644 (file)
@@ -80,9 +80,9 @@ GType
 @G_TYPE_DOUBLE: 
 @G_TYPE_STRING: 
 @G_TYPE_PARAM: 
+@G_TYPE_BOXED: 
+@G_TYPE_POINTER: 
 @G_TYPE_OBJECT: 
-@G_TYPE_GTK_BOXED: 
-@G_TYPE_GTK_POINTER: 
 @G_TYPE_GTK_SIGNAL: 
 @G_TYPE_BSE_PROCEDURE: 
 @G_TYPE_BSE_TIME: 
@@ -213,6 +213,7 @@ GType
 @value_init: 
 @value_free: 
 @value_copy: 
+@value_peek_pointer: 
 @collect_type: 
 @collect_value: 
 @lcopy_type: 
@@ -571,10 +572,7 @@ GType
 
 </para>
 
-@G_TYPE_FLAG_CLASSED: 
-@G_TYPE_FLAG_INSTANTIATABLE: 
-@G_TYPE_FLAG_DERIVABLE: 
-@G_TYPE_FLAG_DEEP_DERIVABLE: 
+@G_TYPE_FLAG_ABSTRACT: 
 
 <!-- ##### FUNCTION g_type_register_static ##### -->
 <para>
@@ -584,6 +582,7 @@ GType
 @parent_type: 
 @type_name: 
 @info: 
+@flags: 
 @Returns: 
 
 
@@ -595,6 +594,7 @@ GType
 @parent_type: 
 @type_name: 
 @plugin: 
+@flags: 
 @Returns: 
 
 
@@ -607,6 +607,7 @@ GType
 @type_name: 
 @info: 
 @finfo: 
+@flags: 
 @Returns: 
 
 
index 9336241d027ad7f45ac445069b40f9269eafb1e6..92d9bf92fd17e1403d63b56428c284e0e84e9051 100644 (file)
 #define __GLIB_GOBJECT_H__
 
 /* topmost include file for GObject header files */
-#include       <gobject/gtype.h>
+#include       <gobject/gboxed.h>
+#include       <gobject/gbsearcharray.h>
 #include       <gobject/genums.h>
-#include       <gobject/gvalue.h>
-#include       <gobject/gvaluetypes.h>
+#include       <gobject/gobject.h>
 #include       <gobject/gparam.h>
 #include       <gobject/gparamspecs.h>
-#include       <gobject/gobject.h>
+#include       <gobject/gsignal.h>
+#include       <gobject/gtype.h>
+#include       <gobject/gvalue.h>
+#include       <gobject/gvaluetypes.h>
 
 
 #endif /* __GLIB_GOBJECT_H__ */
diff --git a/glib/gbsearcharray.c b/glib/gbsearcharray.c
new file mode 100644 (file)
index 0000000..9aa1f45
--- /dev/null
@@ -0,0 +1,164 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 2000 Tim Janik
+ *
+ * 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.
+ */
+#define G_IMPLEMENT_INLINES 1
+#define __G_BSEARCHARRAY_C__
+#include "gbsearcharray.h"
+
+#include       <string.h>
+
+
+/* --- structures --- */
+static inline guint
+upper_power2 (guint number)
+{
+  return number ? 1 << g_bit_storage (number - 1) : 0;
+}
+
+static inline gpointer
+bsearch_array_insert (GBSearchArray *barray,
+                     gconstpointer  key_node,
+                     gboolean       replace)
+{
+  gint sizeof_node;
+  guint8 *check;
+  
+  sizeof_node = barray->sizeof_node;
+  if (barray->n_nodes == 0)
+    {
+      guint new_size = barray->sizeof_node;
+      
+      if (barray->flags & G_BSEARCH_ALIGN_POWER2)
+       new_size = upper_power2 (new_size);
+      barray->nodes = g_realloc (barray->nodes, new_size);
+      barray->n_nodes = 1;
+      check = barray->nodes;
+      replace = TRUE;
+    }
+  else
+    {
+      GBSearchCompareFunc cmp_func = barray->cmp_func;
+      guint n_nodes = barray->n_nodes;
+      guint8 *nodes = barray->nodes;
+      gint cmp;
+      guint i;
+      
+      nodes -= sizeof_node;
+      do
+       {
+         i = (n_nodes + 1) >> 1;
+         check = nodes + i * sizeof_node;
+         cmp = cmp_func (key_node, check);
+         if (cmp > 0)
+           {
+             n_nodes -= i;
+             nodes = check;
+           }
+         else if (cmp < 0)
+           n_nodes = i - 1;
+         else /* if (cmp == 0) */
+           goto SKIP_GROW;
+       }
+      while (n_nodes);
+      /* grow */
+      if (cmp > 0)
+       check += sizeof_node;
+      i = (check - ((guint8*) barray->nodes)) / sizeof_node;
+      n_nodes = barray->n_nodes++;
+      if (barray->flags & G_BSEARCH_ALIGN_POWER2)
+       {
+         guint new_size = upper_power2 (barray->n_nodes * sizeof_node);
+         guint old_size = upper_power2 (n_nodes * sizeof_node);
+         
+         if (new_size != old_size)
+           barray->nodes = g_realloc (barray->nodes, new_size);
+       }
+      else
+       barray->nodes = g_realloc (barray->nodes, barray->n_nodes * sizeof_node);
+      check = barray->nodes + i * sizeof_node;
+      g_memmove (check + sizeof_node, check, (n_nodes - i) * sizeof_node);
+      replace = TRUE;
+    SKIP_GROW:
+    }
+  if (replace)
+    memcpy (check, key_node, sizeof_node);
+  
+  return check;
+}
+
+gpointer
+g_bsearch_array_insert (GBSearchArray *barray,
+                       gconstpointer  key_node,
+                       gboolean       replace_existing)
+{
+  g_return_val_if_fail (barray != NULL, NULL);
+  g_return_val_if_fail (key_node != NULL, NULL);
+  
+  return bsearch_array_insert (barray, key_node, replace_existing);
+}
+
+void
+g_bsearch_array_remove_node (GBSearchArray *barray,
+                            gpointer       _node_in_array)
+{
+  guint8 *nodes, *bound, *node_in_array = _node_in_array;
+  guint old_size;
+  
+  g_return_if_fail (barray != NULL);
+  
+  nodes = barray->nodes;
+  old_size = barray->sizeof_node;
+  old_size *= barray->n_nodes;  /* beware of int widths */
+  bound = nodes + old_size;
+  
+  g_return_if_fail (node_in_array >= nodes && node_in_array < bound);
+  
+  bound -= barray->sizeof_node;
+  barray->n_nodes -= 1;
+  g_memmove (node_in_array, node_in_array + barray->sizeof_node, (bound - node_in_array) / barray->sizeof_node);
+  
+  if ((barray->flags & G_BSEARCH_DEFER_SHRINK) == 0)
+    {
+      guint new_size = bound - nodes;   /* old_size - barray->sizeof_node */
+      
+      if (barray->flags & G_BSEARCH_ALIGN_POWER2)
+       {
+         new_size = upper_power2 (new_size);
+         old_size = upper_power2 (old_size);
+         if (old_size != new_size)
+           barray->nodes = g_realloc (barray->nodes, new_size);
+       }
+      else
+       barray->nodes = g_realloc (barray->nodes, new_size);
+    }
+}
+
+void
+g_bsearch_array_remove (GBSearchArray *barray,
+                       gconstpointer  key_node)
+{
+  gpointer node_in_array;
+  
+  g_return_if_fail (barray != NULL);
+  
+  node_in_array = g_bsearch_array_lookup (barray, key_node);
+  if (!node_in_array)
+    g_warning (G_STRLOC ": unable to remove unexistant node");
+  else
+    g_bsearch_array_remove_node (barray, node_in_array);
+}
diff --git a/glib/gbsearcharray.h b/glib/gbsearcharray.h
new file mode 100644 (file)
index 0000000..aadaac8
--- /dev/null
@@ -0,0 +1,134 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 2000 Tim Janik
+ *
+ * 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.
+ *
+ * gbsearcharray.h: binary searchable sorted array maintenance
+ */
+#ifndef __G_BSEARCH_ARRAY_H__
+#define __G_BSEARCH_ARRAY_H__
+
+#include        <gobject/gtype.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* helper macro to avoid signed overflow for value comparisions */
+#define        G_BSEARCH_ARRAY_CMP(v1,v2) ((v1) < (v2) ? -1 : (v1) > (v2) ? 1 : 0)
+
+
+/* --- typedefs --- */
+typedef struct _GBSearchArray         GBSearchArray;
+typedef gint  (*GBSearchCompareFunc) (gconstpointer bsearch_node1,
+                                     gconstpointer bsearch_node2);
+typedef enum
+{
+  G_BSEARCH_ALIGN_POWER2       = 1 << 0,
+  G_BSEARCH_DEFER_SHRINK       = 1 << 1
+} GBSearchFlags;
+
+
+/* --- structures --- */
+struct _GBSearchArray
+{
+  GBSearchCompareFunc cmp_func;
+  guint16             sizeof_node;
+  guint16            flags;
+  guint               n_nodes;
+  gpointer            nodes;
+};
+
+
+/* --- prototypes --- */
+gpointer       g_bsearch_array_insert          (GBSearchArray  *barray,
+                                                gconstpointer   key_node,
+                                                gboolean        replace_existing);
+void           g_bsearch_array_remove          (GBSearchArray  *barray,
+                                                gconstpointer   key_node);
+void           g_bsearch_array_remove_node     (GBSearchArray  *barray,
+                                                gpointer        node_in_array);
+G_INLINE_FUNC
+gpointer       g_bsearch_array_lookup          (GBSearchArray  *barray,
+                                                gconstpointer   key_node);
+G_INLINE_FUNC
+gpointer       g_bsearch_array_get_nth         (GBSearchArray  *barray,
+                                                guint           n);
+
+
+/* --- implementation details --- */
+#if defined (G_CAN_INLINE) || defined (__G_BSEARCHARRAY_C__)
+G_INLINE_FUNC gpointer
+g_bsearch_array_lookup (GBSearchArray *barray,
+                       gconstpointer  key_node)
+{
+  if (barray->n_nodes > 0)
+    {
+      GBSearchCompareFunc cmp_func = barray->cmp_func;
+      gint sizeof_node = barray->sizeof_node;
+      guint n_nodes = barray->n_nodes;
+      guint8 *nodes = barray->nodes;
+      
+      nodes -= sizeof_node;
+      do
+       {
+         guint8 *check;
+         guint i;
+         register gint cmp;
+         
+         i = (n_nodes + 1) >> 1;
+         check = nodes + i * sizeof_node;
+         cmp = cmp_func (key_node, check);
+         if (cmp == 0)
+           return check;
+         else if (cmp > 0)
+           {
+             n_nodes -= i;
+             nodes = check;
+           }
+         else /* if (cmp < 0) */
+           n_nodes = i - 1;
+       }
+      while (n_nodes);
+    }
+  
+  return NULL;
+}
+G_INLINE_FUNC gpointer
+g_bsearch_array_get_nth (GBSearchArray *barray,
+                        guint          n)
+{
+  if (n < barray->n_nodes)
+    {
+      guint8 *nodes = barray->nodes;
+
+      return nodes + n * barray->sizeof_node;
+    }
+  else
+    return NULL;
+}
+#endif  /* G_CAN_INLINE && __G_BSEARCHARRAY_C__ */
+
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __G_BSEARCH_ARRAY_H__ */
index 9336241d027ad7f45ac445069b40f9269eafb1e6..92d9bf92fd17e1403d63b56428c284e0e84e9051 100644 (file)
 #define __GLIB_GOBJECT_H__
 
 /* topmost include file for GObject header files */
-#include       <gobject/gtype.h>
+#include       <gobject/gboxed.h>
+#include       <gobject/gbsearcharray.h>
 #include       <gobject/genums.h>
-#include       <gobject/gvalue.h>
-#include       <gobject/gvaluetypes.h>
+#include       <gobject/gobject.h>
 #include       <gobject/gparam.h>
 #include       <gobject/gparamspecs.h>
-#include       <gobject/gobject.h>
+#include       <gobject/gsignal.h>
+#include       <gobject/gtype.h>
+#include       <gobject/gvalue.h>
+#include       <gobject/gvaluetypes.h>
 
 
 #endif /* __GLIB_GOBJECT_H__ */
index 32b63e198662e8875243c6b113ecf6114285dcc9..1685f86f878f9a752292cff4a6634aa24c1d4c3e 100644 (file)
@@ -471,7 +471,7 @@ g_log_default_handler (const gchar    *log_domain,
    */
   fd = stdout;
 #else
-  fd = (log_level >= G_LOG_LEVEL_MESSAGE) ? 1 : 2;
+  fd = (log_level > G_LOG_LEVEL_MESSAGE) ? 1 : 2;
 #endif
   
   g_mutex_lock (g_messages_lock);
index 32b63e198662e8875243c6b113ecf6114285dcc9..1685f86f878f9a752292cff4a6634aa24c1d4c3e 100644 (file)
@@ -471,7 +471,7 @@ g_log_default_handler (const gchar    *log_domain,
    */
   fd = stdout;
 #else
-  fd = (log_level >= G_LOG_LEVEL_MESSAGE) ? 1 : 2;
+  fd = (log_level > G_LOG_LEVEL_MESSAGE) ? 1 : 2;
 #endif
   
   g_mutex_lock (g_messages_lock);
index eddfe3f6d7894fce5aeef9f4ff27ce6111cf794e..5b0bb74b678c24a002c0f957f7be84f15aae982d 100644 (file)
@@ -1,3 +1,86 @@
+Wed Oct 25 20:27:02 2000  Tim Janik  <timj@gtk.org>
+
+       * gtype.c (g_type_free_instance): for the moment, freeing object
+       structures will fill their memory portion with 0xAA. there's a
+       FIXME there, remove this line at a later point.
+
+Tue Oct 24 23:10:26 2000  Tim Janik  <timj@gtk.org>
+
+       * glib-genmarshal.1:
+       * glib-genmarshal.c: added publically installed marshaller generator.
+
+       * gtype.h: added G_TYPE_INSTANCE_GET_INTERFACE() to retrive a certain
+       interface VTable from instances.
+
+Mon Oct 23 08:28:15 2000  Tim Janik  <timj@gtk.org>
+
+       * gobject.[hc]: new functions for closure maintenance:
+       (g_object_watch_closure): maintain validity of the object and
+       the closure for objects that are used as data part of a closure.
+       (g_cclosure_new_object): convenience function to create C closures
+       that have an object as data argument.
+       (g_closure_new_object): convenience function to create closures
+       that have an object as data argument.
+
+       * gclosure.[hc]: implementation of GClosure mechanism.
+       a closure is basically an encapsulation of a callback function
+       and its environment. ideally, most places supporting callback
+       functions will simply take a GClosure* pointer and thus unify
+       callback environments wrg destroy notification etc.
+       GClosure provides destroy notifiers for arbitrary data pointers,
+       reference counting, invalidation notification (it can be invalidated
+       which is merely a deactivate state) and a marshallinbg abstraction.
+       GCClosure is also provided in these files, they present a specialized
+       GClosure implementation for C language callbacks.
+
+       * genum.c: macro cleanups.
+       
+       * gboxed.[hc]: new files, for boxed type abstraction.
+       (g_boxed_copy): copy a boxed structure
+       (g_boxed_free): free a boxed structure
+       (g_value_set_boxed):
+       (g_value_get_boxed): standard GValue functions for boxed types
+       (g_boxed_type_register_static): convenience function for easy
+       introduction of new G_TYPE_BOXED derivatives.
+
+       * gparam.[hc]: introduced g_param_type_register_static(), a short hand
+       for creation of new GParamSpec derived types.
+
+       * gtype.[hc]: many fixes, introduced ability to flag individual
+       type nodes as ABSTRACT upon registration, added value_peek_pointer()
+       to the value table to peek at GValue contents as a pointer for types
+       that support this. fixed up GValue checks.
+
+       * gvalue.[hc]: added g_value_fits_pointer() and g_value_get_as_pointer()
+       to peek at the value contents as pointer.
+
+       * *.[hc]: adaptions to type macro fixes and changes in the type
+       registration API.
+
+       * many const corrections over the place.
+
+Sat Oct 21 02:49:56 2000  Tim Janik  <timj@gtk.org>
+
+       * gtype.c (g_type_conforms_to): this function basically behaves like
+       and is_a check, except that it _additionally_ features interfaces
+       for instantiatable types. enforce this in the second branch as well
+       (`type' conforms_to `type') even if `type' is not an interface type.
+
+Fri Oct 20 15:31:04 2000  Tim Janik  <timj@gtk.org>
+
+       * gvaluetypes.[hc]: added G_TYPE_POINTER implementation from jrb.
+
+       * gtype.[hc]:
+       * gobject.c:
+       * gvaluetypes.c: added GTypeValueTable.value_peek_pointer and
+       suitable implementations of this for G_TYPE_STRING, G_TYPE_OBJECT
+       and G_TYPE_POINTER.
+
+Mon Aug 21 04:13:37 2000  Tim Janik  <timj@gtk.org>
+
+       * gbsearcharray.[hc]: long standing needed generic implementation
+       of a binary searchable, sorted and dynamically sized array.
+
 2000-10-15  Raja R Harinath  <harinath@cs.umn.edu>
 
        * Makefile.am (BUILT_EXTRA_DIST): New variable.
@@ -255,9 +338,5 @@ Sun Apr  2 04:54:36 2000  Tim Janik  <timj@gtk.org>
         * 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.
index 88e56341834ccf023fdb0f931d2aade675050bec..7e2b34a9464df23e9309681586060311d0e307bb 100644 (file)
@@ -3,7 +3,8 @@
 #
 ## Process this file with automake to produce Makefile.in
 
-INCLUDES = -I$(top_srcdir) -I$(top_builddir) -I. @GLIB_DEBUG_FLAGS@
+SUBDIRS =
+INCLUDES = -I$(top_srcdir) -I$(top_builddir) @GLIB_DEBUG_FLAGS@
 
 # libraries to compile and install
 lib_LTLIBRARIES = libgobject-1.3.la
@@ -22,28 +23,38 @@ libgobject_1_3_la_LIBADD = # $(libglib)
 # setup source file variables
 #
 # GObject header files for public installation (non-generated)
-gobject_public_h_sources = \
-       gvalue.h \
-       gvaluetypes.h \
-       gparam.h \
-       gparamspecs.h \
+gobject_public_h_sources = @STRIP_BEGIN@ \
+       gboxed.h \
+       gbsearcharray.h \
+       gclosure.h \
        genums.h \
        gobject.h \
+       gparam.h \
+       gparamspecs.h \
+       gsignal.h \
        gtype.h \
-       gvaluecollector.h 
+       gvalue.h \
+       gvaluecollector.h \
+       gvaluetypes.h \
+@STRIP_END@
 
 # private GObject header files
 gobject_private_h_sources = 
 
 # GObject C sources to build the library from
-gobject_c_sources = \
-       gvalue.c \
-       gvaluetypes.c \
-       gparam.c \
-       gparamspecs.c \
+gobject_c_sources = @STRIP_BEGIN@ \
+       gboxed.c \
+       gbsearcharray.c \
+       gclosure.c \
        genums.c \
        gobject.c \
-       gtype.c
+       gparam.c \
+       gparamspecs.c \
+       gsignal.c \
+       gtype.c \
+       gvalue.c \
+       gvaluetypes.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
@@ -66,12 +77,19 @@ EXTRA_DIST += $(gobject_extra_sources)
 #
 # programs to compile and install
 #
-bin_PROGRAMS = gobject-query
+bin_PROGRAMS = gobject-query glib-genmarshal
 # source files
 gobject_query_SOURCES = gobject-query.c
+glib_genmarshal_SOURCES = glib-genmarshal.c
 # link programs against libgobject
 progs_LDADD = ../libglib-1.3.la libgobject-1.3.la
 gobject_query_LDADD = $(progs_LDADD)
+glib_genmarshal_LDADD = $(progs_LDADD)
+
+#
+# manual pages to install
+#
+man_MANS = glib-genmarshal.1
 
 #
 # auxillary files
diff --git a/gobject/gboxed.c b/gobject/gboxed.c
new file mode 100644 (file)
index 0000000..c78612c
--- /dev/null
@@ -0,0 +1,316 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 2000 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       "gboxed.h"
+
+#include       "gbsearcharray.h"
+#include       "gvalue.h"
+#include       "gvaluecollector.h"
+
+
+
+/* --- typedefs & structures --- */
+typedef struct
+{
+  GType                 type;
+  GBoxedCopyFunc copy;
+  GBoxedFreeFunc free;
+} BoxedNode;
+
+
+/* --- prototypes --- */
+static gint    boxed_nodes_cmp         (gconstpointer  p1,
+                                        gconstpointer  p2);
+
+
+/* --- variables --- */
+static GBSearchArray boxed_bsa = { boxed_nodes_cmp, sizeof (BoxedNode), 0, 0, NULL };
+
+
+/* --- functions --- */
+static gint
+boxed_nodes_cmp        (gconstpointer p1,
+                gconstpointer p2)
+{
+  const BoxedNode *node1 = p1, *node2 = p2;
+
+  return G_BSEARCH_ARRAY_CMP (node1->type, node2->type);
+}
+
+void
+g_boxed_type_init (void)  /* sync with gtype.c */
+{
+  static const GTypeInfo info = {
+    0,                          /* class_size */
+    NULL,                       /* base_init */
+    NULL,                       /* base_destroy */
+    NULL,                       /* class_init */
+    NULL,                       /* class_destroy */
+    NULL,                       /* class_data */
+    0,                          /* instance_size */
+    0,                          /* n_preallocs */
+    NULL,                       /* instance_init */
+    NULL,                       /* value_table */
+  };
+  const GTypeFundamentalInfo finfo = { G_TYPE_FLAG_DERIVABLE, };
+  GType type;
+
+  /* G_TYPE_BOXED
+   */
+  type = g_type_register_fundamental (G_TYPE_BOXED, "GBoxed", &info, &finfo, G_TYPE_FLAG_ABSTRACT);
+  g_assert (type == G_TYPE_BOXED);
+}
+
+static void
+boxed_proxy_value_init (GValue *value)
+{
+  value->data[0].v_pointer = 0;
+}
+
+static void
+boxed_proxy_value_free (GValue *value)
+{
+  if (value->data[0].v_pointer)
+    {
+      BoxedNode key, *node;
+
+      key.type = value->g_type;
+      node = g_bsearch_array_lookup (&boxed_bsa, &key);
+      node->free (value->data[0].v_pointer);
+    }
+}
+
+static void
+boxed_proxy_value_copy (const GValue *src_value,
+                       GValue       *dest_value)
+{
+  if (src_value->data[0].v_pointer)
+    {
+      BoxedNode key, *node;
+
+      key.type = src_value->g_type;
+      node = g_bsearch_array_lookup (&boxed_bsa, &key);
+      dest_value->data[0].v_pointer = node->copy (src_value->data[0].v_pointer);
+    }
+  else
+    dest_value->data[0].v_pointer = src_value->data[0].v_pointer;
+}
+
+static gpointer
+boxed_proxy_value_peek_pointer (const GValue *value)
+{
+  return value->data[0].v_pointer;
+}
+
+static gchar*
+boxed_proxy_collect_value (GValue      *value,
+                          guint        nth_value,
+                          GType       *collect_type,
+                          GTypeCValue *collect_value)
+{
+  BoxedNode key, *node;
+
+  key.type = value->g_type;
+  node = g_bsearch_array_lookup (&boxed_bsa, &key);
+  value->data[0].v_pointer = node->copy (collect_value->v_pointer);
+
+  *collect_type = 0;
+  return NULL;
+}
+
+static gchar*
+boxed_proxy_lcopy_value (const GValue *value,
+                        guint         nth_value,
+                        GType        *collect_type,
+                        GTypeCValue  *collect_value)
+{
+  BoxedNode key, *node;
+  gpointer *boxed_p = collect_value->v_pointer;
+
+  if (!boxed_p)
+    return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
+
+  key.type = value->g_type;
+  node = g_bsearch_array_lookup (&boxed_bsa, &key);
+  *boxed_p = node->copy (value->data[0].v_pointer);
+
+  *collect_type = 0;
+  return NULL;
+}
+
+GType
+g_boxed_type_register_static (const gchar   *name,
+                             GBoxedCopyFunc boxed_copy,
+                             GBoxedFreeFunc boxed_free)
+{
+  static const GTypeValueTable vtable = {
+    boxed_proxy_value_init,
+    boxed_proxy_value_free,
+    boxed_proxy_value_copy,
+    boxed_proxy_value_peek_pointer,
+    G_VALUE_COLLECT_POINTER,
+    boxed_proxy_collect_value,
+    G_VALUE_COLLECT_POINTER,
+    boxed_proxy_lcopy_value,
+  };
+  static const GTypeInfo type_info = {
+    0,                 /* class_size */
+    NULL,              /* base_init */
+    NULL,              /* base_finalize */
+    NULL,              /* class_init */
+    NULL,              /* class_finalize */
+    NULL,              /* class_data */
+    0,                 /* instance_size */
+    0,                 /* n_preallocs */
+    NULL,              /* instance_init */
+    &vtable,           /* value_table */
+  };
+  GType type;
+
+  g_return_val_if_fail (name != NULL, 0);
+  g_return_val_if_fail (boxed_copy != NULL, 0);
+  g_return_val_if_fail (boxed_free != NULL, 0);
+  g_return_val_if_fail (g_type_from_name (name) == 0, 0);
+
+  type = g_type_register_static (G_TYPE_BOXED, name, &type_info, 0);
+
+  /* install proxy functions upon successfull registration */
+  if (type)
+    {
+      BoxedNode key;
+
+      key.type = type;
+      key.copy = boxed_copy;
+      key.free = boxed_free;
+      g_bsearch_array_insert (&boxed_bsa, &key, TRUE);
+    }
+
+  return type;
+}
+
+GBoxed*
+g_boxed_copy (GType    boxed_type,
+             gpointer src_boxed)
+{
+  GTypeValueTable *value_table;
+
+  g_return_val_if_fail (G_TYPE_IS_BOXED (boxed_type), NULL);
+  g_return_val_if_fail (G_TYPE_IS_ABSTRACT (boxed_type) == FALSE, NULL);
+  g_return_val_if_fail (src_boxed != NULL, NULL);
+
+  value_table = g_type_value_table_peek (boxed_type);
+  if (!value_table)
+    g_return_val_if_fail (G_TYPE_IS_VALUE_TYPE (boxed_type), NULL);
+
+  /* check if our proxying implementation is used, we can short-cut here */
+  if (value_table->value_copy == boxed_proxy_value_copy)
+    {
+      BoxedNode key, *node;
+
+      key.type = boxed_type;
+      node = g_bsearch_array_lookup (&boxed_bsa, &key);
+      src_boxed = node->copy (src_boxed);
+    }
+  else
+    {
+      GValue src_value, dest_value;
+      
+      /* we heavil rely on the gvalue.c implementation here */
+
+      memset (&src_value.data, 0, sizeof (src_value.data));
+      memset (&dest_value.data, 0, sizeof (dest_value.data));
+      dest_value.g_type = boxed_type;
+      src_value.g_type = boxed_type;
+      src_value.data[0].v_pointer = src_boxed;
+      value_table->value_copy (&src_value, &dest_value);
+      if (dest_value.data[1].v_ulong ||
+         dest_value.data[2].v_ulong ||
+         dest_value.data[3].v_ulong)
+       g_warning ("the copy_value() implementation of type `%s' seems to make use of reserved GValue fields",
+                  g_type_name (boxed_type));
+
+      src_boxed = dest_value.data[0].v_pointer;
+    }
+
+  return src_boxed;
+}
+
+void
+g_boxed_free (GType    boxed_type,
+             gpointer boxed)
+{
+  GTypeValueTable *value_table;
+
+  g_return_if_fail (G_TYPE_IS_BOXED (boxed_type));
+  g_return_if_fail (G_TYPE_IS_ABSTRACT (boxed_type) == FALSE);
+  g_return_if_fail (boxed != NULL);
+
+  value_table = g_type_value_table_peek (boxed_type);
+  if (!value_table)
+    g_return_if_fail (G_TYPE_IS_VALUE_TYPE (boxed_type));
+
+  /* check if our proxying implementation is used, we can short-cut here */
+  if (value_table->value_free == boxed_proxy_value_free)
+    {
+      BoxedNode key, *node;
+
+      key.type = boxed_type;
+      node = g_bsearch_array_lookup (&boxed_bsa, &key);
+      node->free (boxed);
+    }
+  else
+    {
+      GValue value;
+
+      /* we heavil rely on the gvalue.c implementation here */
+      memset (&value.data, 0, sizeof (value.data));
+      value.g_type = boxed_type;
+      value.data[0].v_pointer = boxed;
+      value_table->value_free (&value);
+    }
+}
+
+void
+g_value_set_boxed (GValue  *value,
+                  gpointer boxed)
+{
+  g_return_if_fail (G_IS_VALUE_BOXED (value));
+  g_return_if_fail (G_TYPE_IS_VALUE (G_VALUE_TYPE (value)));
+
+  if (value->data[0].v_pointer)
+    g_boxed_free (G_VALUE_TYPE (value), value->data[0].v_pointer);
+  value->data[0].v_pointer = boxed ? g_boxed_copy (G_VALUE_TYPE (value), boxed) : NULL;
+}
+
+gpointer
+g_value_get_boxed (GValue *value)
+{
+  g_return_val_if_fail (G_IS_VALUE_BOXED (value), NULL);
+  g_return_val_if_fail (G_TYPE_IS_VALUE (G_VALUE_TYPE (value)), NULL);
+
+  return value->data[0].v_pointer;
+}
+
+gpointer
+g_value_dup_boxed (GValue *value)
+{
+  g_return_val_if_fail (G_IS_VALUE_BOXED (value), NULL);
+  g_return_val_if_fail (G_TYPE_IS_VALUE (G_VALUE_TYPE (value)), NULL);
+
+  return value->data[0].v_pointer ? g_boxed_copy (G_VALUE_TYPE (value), value->data[0].v_pointer) : NULL;
+}
diff --git a/gobject/gboxed.h b/gobject/gboxed.h
new file mode 100644 (file)
index 0000000..edd51b0
--- /dev/null
@@ -0,0 +1,64 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 2000 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_BOXED_H__
+#define __G_BOXED_H__
+
+#include        <gobject/gtype.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* --- type macros --- */
+#define G_TYPE_IS_BOXED(type)  (G_TYPE_FUNDAMENTAL (type) == G_TYPE_BOXED)
+#define G_IS_VALUE_BOXED(value)        (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_BOXED))
+
+
+/* --- typedefs --- */
+typedef struct _GBoxed GBoxed;
+typedef gpointer (*GBoxedCopyFunc)     (gpointer        boxed);
+typedef void     (*GBoxedFreeFunc)     (gpointer        boxed);
+
+
+/* --- prototypes --- */
+GBoxed*                g_boxed_copy            (GType           boxed_type,
+                                        gpointer        src_boxed);
+void           g_boxed_free            (GType           boxed_type,
+                                        gpointer        boxed);
+void            g_value_set_boxed       (GValue         *value,
+                                        gpointer        boxed);
+gpointer       g_value_get_boxed       (GValue         *value);
+gpointer       g_value_dup_boxed       (GValue         *value);
+
+
+/* --- convenience --- */
+GType  g_boxed_type_register_static    (const gchar   *name,
+                                        GBoxedCopyFunc boxed_copy,
+                                        GBoxedFreeFunc boxed_free);
+
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __G_BOXED_H__ */
diff --git a/gobject/gbsearcharray.c b/gobject/gbsearcharray.c
new file mode 100644 (file)
index 0000000..9aa1f45
--- /dev/null
@@ -0,0 +1,164 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 2000 Tim Janik
+ *
+ * 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.
+ */
+#define G_IMPLEMENT_INLINES 1
+#define __G_BSEARCHARRAY_C__
+#include "gbsearcharray.h"
+
+#include       <string.h>
+
+
+/* --- structures --- */
+static inline guint
+upper_power2 (guint number)
+{
+  return number ? 1 << g_bit_storage (number - 1) : 0;
+}
+
+static inline gpointer
+bsearch_array_insert (GBSearchArray *barray,
+                     gconstpointer  key_node,
+                     gboolean       replace)
+{
+  gint sizeof_node;
+  guint8 *check;
+  
+  sizeof_node = barray->sizeof_node;
+  if (barray->n_nodes == 0)
+    {
+      guint new_size = barray->sizeof_node;
+      
+      if (barray->flags & G_BSEARCH_ALIGN_POWER2)
+       new_size = upper_power2 (new_size);
+      barray->nodes = g_realloc (barray->nodes, new_size);
+      barray->n_nodes = 1;
+      check = barray->nodes;
+      replace = TRUE;
+    }
+  else
+    {
+      GBSearchCompareFunc cmp_func = barray->cmp_func;
+      guint n_nodes = barray->n_nodes;
+      guint8 *nodes = barray->nodes;
+      gint cmp;
+      guint i;
+      
+      nodes -= sizeof_node;
+      do
+       {
+         i = (n_nodes + 1) >> 1;
+         check = nodes + i * sizeof_node;
+         cmp = cmp_func (key_node, check);
+         if (cmp > 0)
+           {
+             n_nodes -= i;
+             nodes = check;
+           }
+         else if (cmp < 0)
+           n_nodes = i - 1;
+         else /* if (cmp == 0) */
+           goto SKIP_GROW;
+       }
+      while (n_nodes);
+      /* grow */
+      if (cmp > 0)
+       check += sizeof_node;
+      i = (check - ((guint8*) barray->nodes)) / sizeof_node;
+      n_nodes = barray->n_nodes++;
+      if (barray->flags & G_BSEARCH_ALIGN_POWER2)
+       {
+         guint new_size = upper_power2 (barray->n_nodes * sizeof_node);
+         guint old_size = upper_power2 (n_nodes * sizeof_node);
+         
+         if (new_size != old_size)
+           barray->nodes = g_realloc (barray->nodes, new_size);
+       }
+      else
+       barray->nodes = g_realloc (barray->nodes, barray->n_nodes * sizeof_node);
+      check = barray->nodes + i * sizeof_node;
+      g_memmove (check + sizeof_node, check, (n_nodes - i) * sizeof_node);
+      replace = TRUE;
+    SKIP_GROW:
+    }
+  if (replace)
+    memcpy (check, key_node, sizeof_node);
+  
+  return check;
+}
+
+gpointer
+g_bsearch_array_insert (GBSearchArray *barray,
+                       gconstpointer  key_node,
+                       gboolean       replace_existing)
+{
+  g_return_val_if_fail (barray != NULL, NULL);
+  g_return_val_if_fail (key_node != NULL, NULL);
+  
+  return bsearch_array_insert (barray, key_node, replace_existing);
+}
+
+void
+g_bsearch_array_remove_node (GBSearchArray *barray,
+                            gpointer       _node_in_array)
+{
+  guint8 *nodes, *bound, *node_in_array = _node_in_array;
+  guint old_size;
+  
+  g_return_if_fail (barray != NULL);
+  
+  nodes = barray->nodes;
+  old_size = barray->sizeof_node;
+  old_size *= barray->n_nodes;  /* beware of int widths */
+  bound = nodes + old_size;
+  
+  g_return_if_fail (node_in_array >= nodes && node_in_array < bound);
+  
+  bound -= barray->sizeof_node;
+  barray->n_nodes -= 1;
+  g_memmove (node_in_array, node_in_array + barray->sizeof_node, (bound - node_in_array) / barray->sizeof_node);
+  
+  if ((barray->flags & G_BSEARCH_DEFER_SHRINK) == 0)
+    {
+      guint new_size = bound - nodes;   /* old_size - barray->sizeof_node */
+      
+      if (barray->flags & G_BSEARCH_ALIGN_POWER2)
+       {
+         new_size = upper_power2 (new_size);
+         old_size = upper_power2 (old_size);
+         if (old_size != new_size)
+           barray->nodes = g_realloc (barray->nodes, new_size);
+       }
+      else
+       barray->nodes = g_realloc (barray->nodes, new_size);
+    }
+}
+
+void
+g_bsearch_array_remove (GBSearchArray *barray,
+                       gconstpointer  key_node)
+{
+  gpointer node_in_array;
+  
+  g_return_if_fail (barray != NULL);
+  
+  node_in_array = g_bsearch_array_lookup (barray, key_node);
+  if (!node_in_array)
+    g_warning (G_STRLOC ": unable to remove unexistant node");
+  else
+    g_bsearch_array_remove_node (barray, node_in_array);
+}
diff --git a/gobject/gbsearcharray.h b/gobject/gbsearcharray.h
new file mode 100644 (file)
index 0000000..aadaac8
--- /dev/null
@@ -0,0 +1,134 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 2000 Tim Janik
+ *
+ * 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.
+ *
+ * gbsearcharray.h: binary searchable sorted array maintenance
+ */
+#ifndef __G_BSEARCH_ARRAY_H__
+#define __G_BSEARCH_ARRAY_H__
+
+#include        <gobject/gtype.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* helper macro to avoid signed overflow for value comparisions */
+#define        G_BSEARCH_ARRAY_CMP(v1,v2) ((v1) < (v2) ? -1 : (v1) > (v2) ? 1 : 0)
+
+
+/* --- typedefs --- */
+typedef struct _GBSearchArray         GBSearchArray;
+typedef gint  (*GBSearchCompareFunc) (gconstpointer bsearch_node1,
+                                     gconstpointer bsearch_node2);
+typedef enum
+{
+  G_BSEARCH_ALIGN_POWER2       = 1 << 0,
+  G_BSEARCH_DEFER_SHRINK       = 1 << 1
+} GBSearchFlags;
+
+
+/* --- structures --- */
+struct _GBSearchArray
+{
+  GBSearchCompareFunc cmp_func;
+  guint16             sizeof_node;
+  guint16            flags;
+  guint               n_nodes;
+  gpointer            nodes;
+};
+
+
+/* --- prototypes --- */
+gpointer       g_bsearch_array_insert          (GBSearchArray  *barray,
+                                                gconstpointer   key_node,
+                                                gboolean        replace_existing);
+void           g_bsearch_array_remove          (GBSearchArray  *barray,
+                                                gconstpointer   key_node);
+void           g_bsearch_array_remove_node     (GBSearchArray  *barray,
+                                                gpointer        node_in_array);
+G_INLINE_FUNC
+gpointer       g_bsearch_array_lookup          (GBSearchArray  *barray,
+                                                gconstpointer   key_node);
+G_INLINE_FUNC
+gpointer       g_bsearch_array_get_nth         (GBSearchArray  *barray,
+                                                guint           n);
+
+
+/* --- implementation details --- */
+#if defined (G_CAN_INLINE) || defined (__G_BSEARCHARRAY_C__)
+G_INLINE_FUNC gpointer
+g_bsearch_array_lookup (GBSearchArray *barray,
+                       gconstpointer  key_node)
+{
+  if (barray->n_nodes > 0)
+    {
+      GBSearchCompareFunc cmp_func = barray->cmp_func;
+      gint sizeof_node = barray->sizeof_node;
+      guint n_nodes = barray->n_nodes;
+      guint8 *nodes = barray->nodes;
+      
+      nodes -= sizeof_node;
+      do
+       {
+         guint8 *check;
+         guint i;
+         register gint cmp;
+         
+         i = (n_nodes + 1) >> 1;
+         check = nodes + i * sizeof_node;
+         cmp = cmp_func (key_node, check);
+         if (cmp == 0)
+           return check;
+         else if (cmp > 0)
+           {
+             n_nodes -= i;
+             nodes = check;
+           }
+         else /* if (cmp < 0) */
+           n_nodes = i - 1;
+       }
+      while (n_nodes);
+    }
+  
+  return NULL;
+}
+G_INLINE_FUNC gpointer
+g_bsearch_array_get_nth (GBSearchArray *barray,
+                        guint          n)
+{
+  if (n < barray->n_nodes)
+    {
+      guint8 *nodes = barray->nodes;
+
+      return nodes + n * barray->sizeof_node;
+    }
+  else
+    return NULL;
+}
+#endif  /* G_CAN_INLINE && __G_BSEARCHARRAY_C__ */
+
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __G_BSEARCH_ARRAY_H__ */
diff --git a/gobject/gclosure.c b/gobject/gclosure.c
new file mode 100644 (file)
index 0000000..31cdca6
--- /dev/null
@@ -0,0 +1,534 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 2000 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       "gclosure.h"
+
+#include       "gvalue.h"
+
+
+/* FIXME: need caching allocators
+ */
+
+#define        CLOSURE_MAX_REF_COUNT           ((1 << 15) - 1)
+#define        CLOSURE_MAX_N_GUARDS            ((1 << 1) - 1)
+#define        CLOSURE_MAX_N_FNOTIFIERS        ((1 << 2) - 1)
+#define        CLOSURE_MAX_N_INOTIFIERS        ((1 << 8) - 1)
+#define        CLOSURE_N_MFUNCS(cl)            ((cl)->meta_marshal + \
+                                         ((cl)->n_guards << 1L))
+#define        CLOSURE_N_NOTIFIERS(cl)         (CLOSURE_N_MFUNCS (cl) + \
+                                         (cl)->n_fnotifiers + \
+                                         (cl)->n_inotifiers)
+enum {
+  FNOTIFY,
+  INOTIFY,
+  PRE_NOTIFY,
+  POST_NOTIFY
+};
+
+
+/* --- functions --- */
+GClosure*
+g_closure_new_simple (guint           sizeof_closure,
+                     gpointer        data)
+{
+  GClosure *closure;
+
+  g_return_val_if_fail (sizeof_closure >= sizeof (GClosure), NULL);
+
+  closure = g_malloc (sizeof_closure);
+  closure->ref_count = 1;
+  closure->meta_marshal = 0;
+  closure->n_guards = 0;
+  closure->n_fnotifiers = 0;
+  closure->n_inotifiers = 0;
+  closure->in_inotify = FALSE;
+  closure->floating = TRUE;
+  closure->derivative_flag = 0;
+  closure->in_marshal = FALSE;
+  closure->is_invalid = FALSE;
+  closure->marshal = NULL;
+  closure->data = data;
+  closure->notifiers = NULL;
+  memset (G_STRUCT_MEMBER_P (closure, sizeof (*closure)), 0, sizeof_closure - sizeof (*closure));
+
+  return closure;
+}
+
+static inline void
+closure_invoke_notifiers (GClosure *closure,
+                         guint     notify_type)
+{
+  /* notifier layout:
+   *     meta_marshal  n_guards    n_guards     n_fnotif.  n_inotifiers
+   * ->[[meta_marshal][pre_guards][post_guards][fnotifers][inotifiers]]
+   *
+   * CLOSURE_N_MFUNCS(cl)    = meta_marshal + n_guards + n_guards;
+   * CLOSURE_N_NOTIFIERS(cl) = CLOSURE_N_MFUNCS(cl) + n_fnotifiers + n_inotifiers
+   *
+   * constrains/catches:
+   * - closure->notifiers may be reloacted during callback
+   * - closure->n_fnotifiers and closure->n_inotifiers may change during callback
+   * - i.e. callbacks can be removed/added during invocation
+   * - have to prepare for callback removal during invocation (->marshal & ->data)
+   * - have to distinguish (->marshal & ->data) for INOTIFY/FNOTIFY (->in_inotify)
+   * + closure->n_guards is const during PRE_NOTIFY & POST_NOTIFY
+   * + closure->meta_marshal is const for all cases
+   * + none of the callbacks can cause recursion
+   * + closure->n_inotifiers is const 0 during FNOTIFY
+   */
+  switch (notify_type)
+    {
+      GClosureNotifyData *ndata;
+      guint i, offs;
+    case FNOTIFY:
+      while (closure->n_fnotifiers)
+       {
+         register guint n = --closure->n_fnotifiers;
+
+         ndata = closure->notifiers + CLOSURE_N_MFUNCS (closure) + n;
+         closure->marshal = (gpointer) ndata->notify;
+         closure->data = ndata->data;
+         ndata->notify (ndata->data, closure);
+       }
+      closure->marshal = NULL;
+      closure->data = NULL;
+      break;
+    case INOTIFY:
+      closure->in_inotify = TRUE;
+      while (closure->n_inotifiers)
+       {
+          register guint n = --closure->n_inotifiers;
+
+         ndata = closure->notifiers + CLOSURE_N_MFUNCS (closure) + closure->n_fnotifiers + n;
+         closure->marshal = (gpointer) ndata->notify;
+         closure->data = ndata->data;
+         ndata->notify (ndata->data, closure);
+       }
+      closure->marshal = NULL;
+      closure->data = NULL;
+      closure->in_inotify = FALSE;
+      break;
+    case PRE_NOTIFY:
+      i = closure->n_guards;
+      offs = closure->meta_marshal;
+      while (i--)
+       {
+         ndata = closure->notifiers + offs + i;
+         ndata->notify (ndata->data, closure);
+       }
+      break;
+    case POST_NOTIFY:
+      i = closure->n_guards;
+      offs = closure->meta_marshal + i;
+      while (i--)
+       {
+         ndata = closure->notifiers + offs + i;
+         ndata->notify (ndata->data, closure);
+       }
+      break;
+    }
+}
+
+void
+g_closure_set_meta_marshal (GClosure       *closure,
+                           gpointer        marshal_data,
+                           GClosureMarshal meta_marshal)
+{
+  GClosureNotifyData *notifiers;
+  guint n;
+
+  g_return_if_fail (closure != NULL);
+  g_return_if_fail (meta_marshal != NULL);
+  g_return_if_fail (closure->is_invalid == FALSE);
+  g_return_if_fail (closure->in_marshal == FALSE);
+  g_return_if_fail (closure->meta_marshal == FALSE);
+
+  n = CLOSURE_N_NOTIFIERS (closure);
+  notifiers = closure->notifiers;
+  closure->notifiers = g_renew (GClosureNotifyData, NULL, CLOSURE_N_NOTIFIERS (closure) + 1);
+  closure->notifiers[0].data = marshal_data;
+  closure->notifiers[0].notify = (GClosureNotify) meta_marshal;
+  if (notifiers)
+    {
+      /* usually the meta marshal will be setup right after creation, so the
+       * memcpy() should be rare-case scenario
+       */
+      memcpy (closure->notifiers + 1, notifiers, CLOSURE_N_NOTIFIERS (closure) * sizeof (notifiers[0]));
+      g_free (notifiers);
+    }
+  closure->meta_marshal = 1;
+}
+
+void
+g_closure_add_marshal_guards (GClosure      *closure,
+                             gpointer       pre_marshal_data,
+                             GClosureNotify pre_marshal_notify,
+                             gpointer       post_marshal_data,
+                             GClosureNotify post_marshal_notify)
+{
+  guint i;
+
+  g_return_if_fail (closure != NULL);
+  g_return_if_fail (pre_marshal_notify != NULL);
+  g_return_if_fail (post_marshal_notify != NULL);
+  g_return_if_fail (closure->is_invalid == FALSE);
+  g_return_if_fail (closure->in_marshal == FALSE);
+  g_return_if_fail (closure->n_guards < CLOSURE_MAX_N_GUARDS);
+
+  closure->notifiers = g_renew (GClosureNotifyData, closure->notifiers, CLOSURE_N_NOTIFIERS (closure) + 2);
+  if (closure->n_inotifiers)
+    closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
+                       closure->n_fnotifiers +
+                       closure->n_inotifiers + 1)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
+                                                                         closure->n_fnotifiers + 0)];
+  if (closure->n_inotifiers > 1)
+    closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
+                       closure->n_fnotifiers +
+                       closure->n_inotifiers)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
+                                                                     closure->n_fnotifiers + 1)];
+  if (closure->n_fnotifiers)
+    closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
+                       closure->n_fnotifiers + 1)] = closure->notifiers[CLOSURE_N_MFUNCS (closure) + 0];
+  if (closure->n_fnotifiers > 1)
+    closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
+                       closure->n_fnotifiers)] = closure->notifiers[CLOSURE_N_MFUNCS (closure) + 1];
+  if (closure->n_guards)
+    closure->notifiers[(closure->meta_marshal +
+                       closure->n_guards +
+                       closure->n_guards + 1)] = closure->notifiers[closure->meta_marshal + closure->n_guards];
+  i = closure->n_guards++;
+  closure->notifiers[closure->meta_marshal + i].data = pre_marshal_data;
+  closure->notifiers[closure->meta_marshal + i].notify = pre_marshal_notify;
+  closure->notifiers[closure->meta_marshal + i + i].data = post_marshal_data;
+  closure->notifiers[closure->meta_marshal + i + i].notify = post_marshal_notify;
+}
+
+void
+g_closure_add_fnotify (GClosure      *closure,
+                      gpointer       notify_data,
+                      GClosureNotify notify_func)
+{
+  guint i;
+
+  g_return_if_fail (closure != NULL);
+  g_return_if_fail (notify_func != NULL);
+  g_return_if_fail (closure->n_fnotifiers < CLOSURE_MAX_N_FNOTIFIERS);
+
+  closure->notifiers = g_renew (GClosureNotifyData, closure->notifiers, CLOSURE_N_NOTIFIERS (closure) + 1);
+  if (closure->n_inotifiers)
+    closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
+                       closure->n_fnotifiers +
+                       closure->n_inotifiers)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
+                                                                     closure->n_fnotifiers + 0)];
+  i = CLOSURE_N_MFUNCS (closure) + closure->n_fnotifiers++;
+  closure->notifiers[i].data = notify_data;
+  closure->notifiers[i].notify = notify_func;
+}
+
+void
+g_closure_add_inotify (GClosure      *closure,
+                      gpointer       notify_data,
+                      GClosureNotify notify_func)
+{
+  guint i;
+
+  g_return_if_fail (closure != NULL);
+  g_return_if_fail (notify_func != NULL);
+  g_return_if_fail (closure->is_invalid == FALSE);
+  g_return_if_fail (closure->n_inotifiers < CLOSURE_MAX_N_INOTIFIERS);
+
+  closure->notifiers = g_renew (GClosureNotifyData, closure->notifiers, CLOSURE_N_NOTIFIERS (closure) + 1);
+  i = CLOSURE_N_MFUNCS (closure) + closure->n_fnotifiers + closure->n_inotifiers++;
+  closure->notifiers[i].data = notify_data;
+  closure->notifiers[i].notify = notify_func;
+}
+
+static inline gboolean
+closure_try_remove_inotify (GClosure       *closure,
+                           gpointer       notify_data,
+                           GClosureNotify notify_func)
+{
+  GClosureNotifyData *ndata, *nlast;
+
+  nlast = closure->notifiers + CLOSURE_N_NOTIFIERS (closure) - 1;
+  for (ndata = nlast + 1 - closure->n_inotifiers; ndata <= nlast; ndata++)
+    if (ndata->notify == notify_func && ndata->data == notify_data)
+      {
+       closure->n_inotifiers -= 1;
+       if (ndata < nlast)
+         *ndata = *nlast;
+
+       return TRUE;
+      }
+  return FALSE;
+}
+
+static inline gboolean
+closure_try_remove_fnotify (GClosure       *closure,
+                           gpointer       notify_data,
+                           GClosureNotify notify_func)
+{
+  GClosureNotifyData *ndata, *nlast;
+
+  nlast = closure->notifiers + CLOSURE_N_NOTIFIERS (closure) - closure->n_inotifiers - 1;
+  for (ndata = nlast + 1 - closure->n_fnotifiers; ndata <= nlast; ndata++)
+    if (ndata->notify == notify_func && ndata->data == notify_data)
+      {
+       closure->n_fnotifiers -= 1;
+       if (ndata < nlast)
+         *ndata = *nlast;
+       if (closure->n_inotifiers)
+         closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
+                             closure->n_fnotifiers)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
+                                                                           closure->n_fnotifiers +
+                                                                           closure->n_inotifiers)];
+       return TRUE;
+      }
+  return FALSE;
+}
+
+GClosure*
+g_closure_ref (GClosure *closure)
+{
+  g_return_val_if_fail (closure != NULL, NULL);
+  g_return_val_if_fail (closure->ref_count > 0, NULL);
+  g_return_val_if_fail (closure->ref_count < CLOSURE_MAX_REF_COUNT, NULL);
+
+  /* floating is basically a kludge to avoid creating closures
+   * with a ref_count of 0. so the first one doing _ref() will
+   * own the closure's initial ref_count
+   */
+  if (closure->floating)
+    closure->floating = FALSE;
+  else
+    closure->ref_count += 1;
+
+  return closure;
+}
+
+void
+g_closure_invalidate (GClosure *closure)
+{
+  g_return_if_fail (closure != NULL);
+
+  if (!closure->is_invalid)
+    {
+      closure->ref_count += 1; /* preserve floating flag */
+      closure->is_invalid = TRUE;
+      closure_invoke_notifiers (closure, INOTIFY);
+      g_closure_unref (closure);
+    }
+}
+
+void
+g_closure_unref (GClosure *closure)
+{
+  g_return_if_fail (closure != NULL);
+  g_return_if_fail (closure->ref_count > 0);
+
+  if (closure->ref_count == 1) /* last unref, invalidate first */
+    g_closure_invalidate (closure);
+
+  closure->ref_count -= 1;
+
+  if (closure->ref_count == 0)
+    {
+      closure_invoke_notifiers (closure, FNOTIFY);
+      g_free (closure);
+    }
+}
+
+void
+g_closure_remove_inotify (GClosure      *closure,
+                         gpointer       notify_data,
+                         GClosureNotify notify_func)
+{
+  g_return_if_fail (closure != NULL);
+  g_return_if_fail (notify_func != NULL);
+
+  if (closure->is_invalid && closure->in_inotify && /* account removal of notify_func() while its called */
+      ((gpointer) closure->marshal) == ((gpointer) notify_func) && closure->data == notify_data)
+    closure->marshal = NULL;
+  else if (!closure_try_remove_inotify (closure, notify_data, notify_func))
+    g_warning (G_STRLOC ": unable to remove uninstalled invalidation notifier: %p (%p)",
+              notify_func, notify_data);
+}
+
+void
+g_closure_remove_fnotify (GClosure      *closure,
+                          gpointer       notify_data,
+                         GClosureNotify notify_func)
+{
+  g_return_if_fail (closure != NULL);
+  g_return_if_fail (notify_func != NULL);
+
+  if (closure->is_invalid && !closure->in_inotify && /* account removal of notify_func() while its called */
+      ((gpointer) closure->marshal) == ((gpointer) notify_func) && closure->data == notify_data)
+    closure->marshal = NULL;
+  else if (!closure_try_remove_fnotify (closure, notify_data, notify_func))
+    g_warning (G_STRLOC ": unable to remove uninstalled finalization notifier: %p (%p)",
+               notify_func, notify_data);
+}
+
+void
+g_closure_invoke (GClosure       *closure,
+                 guint           invocation_hint,
+                 GValue /*out*/ *return_value,
+                 guint           n_param_values,
+                 const GValue   *param_values)
+{
+  g_return_if_fail (closure != NULL);
+  g_return_if_fail (closure->marshal || closure->meta_marshal);
+
+  if (!closure->is_invalid)
+    {
+      GClosureMarshal marshal;
+      gpointer marshal_data;
+      gboolean in_marshal = closure->in_marshal;
+
+      closure->ref_count += 1; /* preserve floating flag */
+      closure->in_marshal = TRUE;
+      if (closure->meta_marshal)
+       {
+         marshal_data = closure->notifiers[0].data;
+         marshal = (GClosureMarshal) closure->notifiers[0].notify;
+       }
+      else
+       {
+         marshal_data = NULL;
+         marshal = closure->marshal;
+       }
+      if (!in_marshal)
+       closure_invoke_notifiers (closure, PRE_NOTIFY);
+      marshal (closure, invocation_hint,
+              return_value,
+              n_param_values, param_values,
+              marshal_data);
+      if (!in_marshal)
+       closure_invoke_notifiers (closure, POST_NOTIFY);
+      closure->in_marshal = in_marshal;
+      g_closure_unref (closure);
+    }
+}
+
+void
+g_closure_set_marshal (GClosure       *closure,
+                      GClosureMarshal marshal)
+{
+  g_return_if_fail (closure != NULL);
+  g_return_if_fail (marshal != NULL);
+
+  if (closure->marshal && closure->marshal != marshal)
+    g_warning ("attempt to override closure->marshal (%p) with new marshal (%p)",
+              closure->marshal, marshal);
+  else
+    closure->marshal = marshal;
+}
+
+GClosure*
+g_cclosure_new (GCallback      callback_func,
+               gpointer       user_data,
+               GClosureNotify destroy_data)
+{
+  GClosure *closure;
+  
+  g_return_val_if_fail (callback_func != NULL, NULL);
+  
+  closure = g_closure_new_simple (sizeof (GCClosure), user_data);
+  if (destroy_data)
+    g_closure_add_fnotify (closure, user_data, destroy_data);
+  ((GCClosure*) closure)->callback = callback_func;
+  
+  return closure;
+}
+
+GClosure*
+g_cclosure_new_swap (GCallback      callback_func,
+                    gpointer       user_data,
+                    GClosureNotify destroy_data)
+{
+  GClosure *closure;
+  
+  g_return_val_if_fail (callback_func != NULL, NULL);
+  
+  closure = g_closure_new_simple (sizeof (GCClosure), user_data);
+  if (destroy_data)
+    g_closure_add_fnotify (closure, user_data, destroy_data);
+  ((GCClosure*) closure)->callback = callback_func;
+  closure->derivative_flag = TRUE;
+  
+  return closure;
+}
+
+static void
+g_type_class_meta_marshal (GClosure       *closure,
+                          guint           invocation_hint,
+                          GValue /*out*/ *return_value,
+                          guint           n_param_values,
+                          const GValue   *param_values,
+                          gpointer        marshal_data)
+{
+  GTypeClass *class;
+  gpointer callback;
+  /* GType itype = GPOINTER_TO_UINT (closure->data); */
+  guint offset = GPOINTER_TO_UINT (marshal_data);
+  
+  class = G_TYPE_INSTANCE_GET_CLASS (g_value_get_as_pointer (param_values + 0), itype, GTypeClass);
+  callback = G_STRUCT_MEMBER (gpointer, class, offset);
+  if (callback)
+    closure->marshal (closure, invocation_hint, return_value,
+                     n_param_values, param_values, callback);
+}
+
+static void
+g_type_iface_meta_marshal (GClosure       *closure,
+                          guint           invocation_hint,
+                          GValue /*out*/ *return_value,
+                          guint           n_param_values,
+                          const GValue   *param_values,
+                          gpointer        marshal_data)
+{
+  GTypeClass *class;
+  gpointer callback;
+  GType itype = GPOINTER_TO_UINT (closure->data);
+  guint offset = GPOINTER_TO_UINT (marshal_data);
+  
+  class = G_TYPE_INSTANCE_GET_INTERFACE (g_value_get_as_pointer (param_values + 0), itype, GTypeClass);
+  callback = G_STRUCT_MEMBER (gpointer, class, offset);
+  if (callback)
+    closure->marshal (closure, invocation_hint, return_value,
+                     n_param_values, param_values, callback);
+}
+
+GClosure*
+g_signal_type_closure_new (GType    itype,
+                          guint    struct_offset)
+{
+  GClosure *closure;
+  
+  g_return_val_if_fail (G_TYPE_IS_CLASSED (itype) || G_TYPE_IS_INTERFACE (itype), NULL);
+  g_return_val_if_fail (struct_offset >= sizeof (GTypeClass), NULL);
+  
+  closure = g_closure_new_simple (sizeof (GClosure), GUINT_TO_POINTER (itype));
+  if (G_TYPE_IS_INTERFACE (itype))
+    g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_iface_meta_marshal);
+  else
+    g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_class_meta_marshal);
+  
+  return closure;
+}
diff --git a/gobject/gclosure.h b/gobject/gclosure.h
new file mode 100644 (file)
index 0000000..423cceb
--- /dev/null
@@ -0,0 +1,185 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 2000 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_CLOSURE_H__
+#define __G_CLOSURE_H__
+
+
+#include        <gobject/gtype.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+
+/* --- defines --- */
+#define        G_CLOSURE_NEEDS_MARSHAL(closure) (((GClosure*) (closure))->marshal == NULL)
+#define        G_CCLOSURE_SWAP_DATA(cclosure)   (((GClosure*) (closure))->derivative_flag)
+
+
+/* -- typedefs --- */
+typedef struct _GClosure                GClosure;
+typedef struct _GClosureNotifyData      GClosureNotifyData;
+typedef        gpointer GCallback;
+typedef void  (*GClosureNotify)                (gpointer        data,
+                                        GClosure       *closure);
+typedef void  (*GClosureMarshal)       (GClosure       *closure,
+                                        guint           invocation_hint,
+                                        GValue         *return_value,
+                                        guint           n_param_values,
+                                        const GValue   *param_values,
+                                        gpointer        marshal_data);
+typedef struct _GCClosure               GCClosure;
+
+
+/* --- structures --- */
+struct _GClosureNotifyData
+{
+  gpointer       data;
+  GClosureNotify notify;
+};
+struct _GClosure
+{
+  /*< private >*/      guint    ref_count : 15;
+  /*< private >*/      guint    meta_marshal : 1;
+  /*< private >*/      guint    n_guards : 1;
+  /*< private >*/      guint    n_fnotifiers : 2;      /* finalization notifiers */
+  /*< private >*/      guint    n_inotifiers : 8;      /* invalidation notifiers */
+  /*< private >*/      guint    in_inotify : 1;
+  /*< private >*/      guint    floating : 1;
+  /*< protected >*/    guint    derivative_flag : 1;
+  /*< puplic >*/       guint    in_marshal : 1;
+  /*< public >*/       guint    is_invalid : 1;
+
+  /*< private >*/      void   (*marshal)  (GClosure       *closure,
+                                           guint           invocation_hint,
+                                           GValue /*out*/ *return_value,
+                                           guint           n_param_values,
+                                           const GValue   *param_values,
+                                           gpointer        marshal_data);
+  /*< protected >*/    gpointer data;
+
+  /*< private >*/      GClosureNotifyData *notifiers;
+
+  /* invariants/constrains:
+   * - ->marshal and ->data are _invalid_ as soon as ->is_invalid==TRUE
+   * - invocation of all inotifiers occours prior to fnotifiers
+   * - order of inotifiers is random
+   *   inotifiers may _not_ free/invalidate parameter values (e.g. ->data)
+   * - order of fnotifiers is random
+   * - notifiers may only be removed before or during their invocation
+   * - reference counting may only happen prior to fnotify invocation
+   *   (in that sense, fnotifiers are really finalization handlers)
+   */
+};
+/* closure for C function calls, callback() is the user function
+ */
+struct _GCClosure
+{
+  GClosure     closure;
+  gpointer     callback;
+};
+
+
+/* --- prototypes --- */
+GClosure*      g_cclosure_new                  (GCallback      callback_func,
+                                                gpointer       user_data,
+                                                GClosureNotify destroy_data);
+GClosure*      g_cclosure_new_swap             (GCallback      callback_func,
+                                                gpointer       user_data,
+                                                GClosureNotify destroy_data);
+GClosure*      g_signal_type_closure_new       (GType          itype,
+                                                guint          struct_offset);
+
+
+/* --- prototypes --- */
+GClosure*      g_closure_ref                   (GClosure       *closure);
+void           g_closure_unref                 (GClosure       *closure);
+/* intimidating */
+GClosure*      g_closure_new_simple            (guint           sizeof_closure,
+                                                gpointer        data);
+void           g_closure_add_fnotify           (GClosure       *closure,
+                                                gpointer        notify_data,
+                                                GClosureNotify  notify_func);
+void           g_closure_remove_fnotify        (GClosure       *closure,
+                                                gpointer        notify_data,
+                                                GClosureNotify  notify_func);
+void           g_closure_add_inotify           (GClosure       *closure,
+                                                gpointer        notify_data,
+                                                GClosureNotify  notify_func);
+void           g_closure_remove_inotify        (GClosure       *closure,
+                                                gpointer        notify_data,
+                                                GClosureNotify  notify_func);
+void           g_closure_add_marshal_guards    (GClosure       *closure,
+                                                gpointer        pre_marshal_data,
+                                                GClosureNotify  pre_marshal_notify,
+                                                gpointer        post_marshal_data,
+                                                GClosureNotify  post_marshal_notify);
+void           g_closure_set_marshal           (GClosure       *closure,
+                                                GClosureMarshal marshal);
+void           g_closure_set_meta_marshal      (GClosure       *closure,
+                                                gpointer        marshal_data,
+                                                GClosureMarshal meta_marshal);
+void           g_closure_invalidate            (GClosure       *closure);
+void           g_closure_invoke                (GClosure       *closure,
+                                                guint           invocation_hint,
+                                                GValue /*out*/ *return_value,
+                                                guint           n_param_values,
+                                                const GValue   *param_values);
+
+
+/*
+  data_object::destroy         -> closure_invalidate();
+  closure_invalidate()         -> disconnect(closure);
+  disconnect(closure)          -> (unlink) closure_unref();
+  closure_finalize()           -> g_free (data_string);
+  
+  1) need GObject and GType in glib
+  2) need GParam
+  3) need to resolve dtor cycles
+  4) need GSignal move
+  5) destroy on last caller ref or last data ref?
+  
+  
+  random remarks:
+  - don't mandate signals for GObject
+  - OTOH, don't mandate GObject for GSignal
+  - need marshaller repo with decent aliasing to base types
+  - provide marshaller collection, virtually covering anything out there
+  - at that point, still need GSignalCMarhsaller to g_signal_new() ?
+  - can we combine varargs collect mechanisms with marshaller stubs?
+  for out values (i.e. returntypes), that might get rid of the following
+  point...
+  - char* return signals with connections ala:
+  connect({ return "static data that can't work"; }),
+  connect({ return g_strdup ("properly duplicated string"); })
+  won't work anymore. CRASH
+
+  problems:
+  - accumulator needs gboolean to indicate EMISSION_STOP
+  - accumulator needs data
+*/
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __G_CLOSURE_H__ */
index f18db25cf90adb6af0080604871cfcbaf38910f9..e60ec2048b67cf7f1d3c759ca84d03e7513c887b 100644 (file)
@@ -30,14 +30,14 @@ static void g_enum_class_init               (GEnumClass     *class,
                                                 gpointer        class_data);
 static void    g_flags_class_init              (GFlagsClass    *class,
                                                 gpointer        class_data);
-static void    g_value_enum_init               (GValue         *value);
-static void    g_value_enum_copy_value         (const GValue   *src_value,
+static void    value_flags_enum_init           (GValue         *value);
+static void    value_flags_enum_copy_value     (const GValue   *src_value,
                                                 GValue         *dest_value);
-static gchar*  g_value_enum_collect_value      (GValue         *value,
-                                                guint           nth_value,
-                                                GType          *collect_type,
-                                                GTypeCValue    *collect_value);
-static gchar*  g_value_enum_lcopy_value        (const GValue   *value,
+static gchar*  value_flags_enum_collect_value (GValue          *value,
+                                               guint            nth_value,
+                                               GType           *collect_type,
+                                               GTypeCValue     *collect_value);
+static gchar*  value_flags_enum_lcopy_value    (const GValue   *value,
                                                 guint           nth_value,
                                                 GType          *collect_type,
                                                 GTypeCValue    *collect_value);
@@ -48,57 +48,106 @@ void
 g_enum_types_init (void)       /* sync with gtype.c */
 {
   static gboolean initialized = FALSE;
-  static const GTypeFundamentalInfo finfo = {
-    G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_DERIVABLE,
+  static const GTypeValueTable flags_enum_value_table = {
+    value_flags_enum_init,       /* value_init */
+    NULL,                                /* value_free */
+    value_flags_enum_copy_value,    /* value_copy */
+    NULL,                                /* value_peek_pointer */
+    G_VALUE_COLLECT_INT,                 /* collect_type */
+    value_flags_enum_collect_value, /* collect_value */
+    G_VALUE_COLLECT_POINTER,     /* lcopy_type */
+    value_flags_enum_lcopy_value,   /* lcopy_value */
   };
   static GTypeInfo info = {
-    0  /* class_size */,
-    NULL       /* base_init */,
-    NULL       /* base_finalize */,
-    NULL       /* class_init */,
-    NULL       /* class_finalize */,
-    NULL       /* class_data */,
+    0,                          /* class_size */
+    NULL,                       /* base_init */
+    NULL,                       /* base_destroy */
+    NULL,                       /* class_init */
+    NULL,                       /* class_destroy */
+    NULL,                       /* class_data */
+    0,                          /* instance_size */
+    0,                          /* n_preallocs */
+    NULL,                       /* instance_init */
+    &flags_enum_value_table,    /* value_table */
   };
-  static const GTypeValueTable value_table = {
-    g_value_enum_init,           /* value_init */
-    NULL,                        /* value_free */
-    g_value_enum_copy_value,     /* value_copy */
-    G_VALUE_COLLECT_INT,         /* collect_type */
-    g_value_enum_collect_value,          /* collect_value */
-    G_VALUE_COLLECT_POINTER,     /* lcopy_type */
-    g_value_enum_lcopy_value,    /* lcopy_value */
+  static const GTypeFundamentalInfo finfo = {
+    G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_DERIVABLE,
   };
   GType type;
   
   g_return_if_fail (initialized == FALSE);
   initialized = TRUE;
-
-  info.value_table = &value_table;
-
+  
   /* G_TYPE_ENUM
    */
   info.class_size = sizeof (GEnumClass);
-  type = g_type_register_fundamental (G_TYPE_ENUM, "GEnum", &info, &finfo);
+  type = g_type_register_fundamental (G_TYPE_ENUM, "GEnum", &info, &finfo, G_TYPE_FLAG_ABSTRACT);
   g_assert (type == G_TYPE_ENUM);
   
   /* G_TYPE_FLAGS
    */
   info.class_size = sizeof (GFlagsClass);
-  type = g_type_register_fundamental (G_TYPE_FLAGS, "GFlags", &info, &finfo);
+  type = g_type_register_fundamental (G_TYPE_FLAGS, "GFlags", &info, &finfo, G_TYPE_FLAG_ABSTRACT);
   g_assert (type == G_TYPE_FLAGS);
 }
 
+static void
+value_flags_enum_init (GValue *value)
+{
+  value->data[0].v_long = 0;
+}
+
+static void
+value_flags_enum_copy_value (const GValue *src_value,
+                            GValue       *dest_value)
+{
+  dest_value->data[0].v_long = src_value->data[0].v_long;
+}
+
+static gchar*
+value_flags_enum_collect_value (GValue      *value,
+                               guint        nth_value,
+                               GType       *collect_type,
+                               GTypeCValue *collect_value)
+{
+  value->data[0].v_long = collect_value->v_int;
+  
+  *collect_type = 0;
+  return NULL;
+}
+
+static gchar*
+value_flags_enum_lcopy_value (const GValue *value,
+                             guint         nth_value,
+                             GType        *collect_type,
+                             GTypeCValue  *collect_value)
+{
+  gint *int_p = collect_value->v_pointer;
+  
+  if (!int_p)
+    return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
+  
+  *int_p = value->data[0].v_long;
+  
+  *collect_type = 0;
+  return NULL;
+}
+
 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 */,
+    sizeof (GEnumClass), /* class_size */
+    NULL,                /* base_init */
+    NULL,                /* base_finalize */
     (GClassInitFunc) g_enum_class_init,
-    NULL       /* class_finalize */,
-    NULL       /* class_data */,
+    NULL,                /* class_finalize */
+    NULL,                /* class_data */
+    0,                   /* instance_size */
+    0,                   /* n_preallocs */
+    NULL,                /* instance_init */
+    NULL,               /* value_table */
   };
   GType type;
   
@@ -107,7 +156,7 @@ g_enum_register_static (const gchar  *name,
   
   enum_type_info.class_data = const_static_values;
   
-  type = g_type_register_static (G_TYPE_ENUM, name, &enum_type_info);
+  type = g_type_register_static (G_TYPE_ENUM, name, &enum_type_info, 0);
   
   return type;
 }
@@ -117,12 +166,16 @@ g_flags_register_static (const gchar         *name,
                         const GFlagsValue *const_static_values)
 {
   GTypeInfo flags_type_info = {
-    sizeof (GFlagsClass),
-    NULL       /* base_init */,
-    NULL       /* base_finalize */,
+    sizeof (GFlagsClass), /* class_size */
+    NULL,                 /* base_init */
+    NULL,                 /* base_finalize */
     (GClassInitFunc) g_flags_class_init,
-    NULL       /* class_finalize */,
-    NULL       /* class_data */,
+    NULL,                 /* class_finalize */
+    NULL,                 /* class_data */
+    0,                    /* instance_size */
+    0,                    /* n_preallocs */
+    NULL,                 /* instance_init */
+    NULL,                /* value_table */
   };
   GType type;
   
@@ -131,7 +184,7 @@ g_flags_register_static (const gchar           *name,
   
   flags_type_info.class_data = const_static_values;
   
-  type = g_type_register_static (G_TYPE_FLAGS, name, &flags_type_info);
+  type = g_type_register_static (G_TYPE_FLAGS, name, &flags_type_info, 0);
   
   return type;
 }
@@ -335,15 +388,15 @@ 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_value_get_enum (const GValue *value)
 {
   g_return_val_if_fail (G_IS_VALUE_ENUM (value), 0);
-
+  
   return value->data[0].v_long;
 }
 
@@ -352,56 +405,14 @@ 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_value_get_flags (const GValue *value)
 {
   g_return_val_if_fail (G_IS_VALUE_FLAGS (value), 0);
-
-  return value->data[0].v_ulong;
-}
-
-static void
-g_value_enum_init (GValue *value)
-{
-  value->data[0].v_long = 0;
-}
-
-static void
-g_value_enum_copy_value (const GValue *src_value,
-                        GValue       *dest_value)
-{
-  dest_value->data[0].v_long = src_value->data[0].v_long;
-}
-
-static gchar*
-g_value_enum_collect_value (GValue     *value,
-                           guint        nth_value,
-                           GType       *collect_type,
-                           GTypeCValue *collect_value)
-{
-  value->data[0].v_long = collect_value->v_int;
-  
-  *collect_type = 0;
-  return NULL;
-}
-
-static gchar*
-g_value_enum_lcopy_value (const GValue *value,
-                         guint         nth_value,
-                         GType        *collect_type,
-                         GTypeCValue  *collect_value)
-{
-  gint *int_p = collect_value->v_pointer;
-  
-  if (!int_p)
-    return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
   
-  *int_p = value->data[0].v_long;
-  
-  *collect_type = 0;
-  return NULL;
+  return value->data[0].v_ulong;
 }
index f04b7d60f2776f963cf04bcef47534cde15bcea9..7fc48ba95da1059498c73d88cd5319842119067d 100644 (file)
@@ -38,8 +38,8 @@ extern "C" {
 #define G_IS_FLAGS_CLASS(class)        (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_FLAGS))
 #define G_FLAGS_CLASS_TYPE(class)      (G_TYPE_FROM_CLASS (class))
 #define G_FLAGS_CLASS_TYPE_NAME(class) (g_type_name (G_FLAGS_TYPE (class)))
-#define G_IS_VALUE_ENUM(value)         (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_ENUM))
-#define G_IS_VALUE_FLAGS(value)        (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_FLAGS))
+#define G_IS_VALUE_ENUM(value)         (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_ENUM))
+#define G_IS_VALUE_FLAGS(value)        (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_FLAGS))
 
 
 /* --- enum/flag values & classes --- */
@@ -93,10 +93,10 @@ GFlagsValue*        g_flags_get_value_by_nick       (GFlagsClass    *flags_class,
                                                 const gchar    *nick);
 void            g_value_set_enum               (GValue         *value,
                                                 gint            v_enum);
-gint            g_value_get_enum               (GValue         *value);
+gint            g_value_get_enum               (const GValue   *value);
 void            g_value_set_flags              (GValue         *value,
                                                 guint           v_flags);
-guint           g_value_get_flags              (GValue         *value);
+guint           g_value_get_flags              (const GValue   *value);
 
 
 
diff --git a/gobject/glib-genmarshal.1 b/gobject/glib-genmarshal.1
new file mode 100644 (file)
index 0000000..d68ff6b
--- /dev/null
@@ -0,0 +1,196 @@
+.TH GLIB-GENMARSHAL 1 "18 Oct 2000"
+.SH NAME
+glib-genmarshal \- C code marshaller generation utility for GLib closures
+.SH SYNOPSIS
+
+\fBglib-genmarshal\fP [\fIoptions\fP] [\fIfiles...\fP]
+
+.SH DESCRIPTION
+\fBglib-genmarshal\fP is a small utility that generates C code marshallers
+for callback functions of the GClosure mechanism in the GObject sublibrary
+of GLib. The marshaller functions have a standard signature, they get passed
+in the invoking closure, an array of value structures holding the callback
+function parameters and a value structure for the return value of the
+callback. The marshaller is then responsible to call the respective C code
+function of the closure with all the parameters on the stack and to collect
+its return value.
+
+.SH INVOCATION
+
+\fBglib-genmarshal\fP takes a list of marshallers to generate as input.
+The marshaller list is either read from standard input or from files
+passed as additional arguments on the command line.
+
+.SS Options
+.TP
+\fI--header
+Generate header file contents of the marshallers.
+.TP
+\fI--body
+Generate C code file contents of the marshallers.
+.TP
+\fI--prefix=string, --prefix string
+Specify marshaller prefix. The default prefix is `\fIg_cclosure_marshal\fP'.
+.TP
+\fI--skip-source
+Skip source location remarks in generated comments.
+.TP
+\fI--g-fatal-warnings
+Make warnings fatal, that is, exit immediately once a warning occours.
+.TP
+\fI-h, --help\fP 
+Print brief help and exit.
+.TP
+\fI-v, --version\fP 
+Print version and exit.
+.PP
+
+.SS Marshaller list format
+.PP
+The marshaller lists are processed line by line, a line can contain a
+comment in the form of
+.RS
+.PP
+# this is a comment
+.PP
+.RE
+or a marshaller specification of the form
+.RS
+.PP
+\fIRTYPE\fP:\fBPTYPE\fP
+.PP
+\fIRTYPE\fP:\fBPTYPE\fP,\fBPTYPE\fP
+.PP
+\fIRTYPE\fP:\fBPTYPE\fP,\fBPTYPE\fP,\fBPTYPE\fP
+.PP
+# up to 16 \fBPTYPE\fPs may be present
+.PP
+.RE
+The \fIRTYPE\fP part specifies the callback's return type and
+the \fBPTYPE\fPs right to the colon specify the callback's
+parameter list, except for the first and the last arguments which
+are always pointers.
+.PP
+
+.SS Parameter types
+Currently, the following types are supported:
+.TP 12
+\fIVOID
+indicates no return type, or no extra parameters. if \fIVOID\fP is used as
+the parameter list, no additional parameters may be present.
+.TP 12
+\fIBOOLEAN
+for boolean types (gboolean)
+.TP 12
+\fICHAR
+for signed char types (gchar)
+.TP 12
+\fIUCHAR
+for unsigned char types (guchar)
+.TP 12
+\fIINT
+for signed integer types (gint)
+.TP 12
+\fIUINT
+for unsigned integer types (guint)
+.TP 12
+\fILONG
+for signed long integer types (glong)
+.TP 12
+\fIULONG
+for unsigned long integer types (gulong)
+.TP 12
+\fIENUM
+for enumeration types (gint)
+.TP 12
+\fIFLAGS
+for flag enumeration types (guint)
+.TP 12
+\fIFLOAT
+for single-precision float types (gfloat)
+.TP 12
+\fIDOUBLE
+for double-precision float types (gdouble)
+.TP 12
+\fISTRING
+for string types (gchar*)
+.TP 12
+\fIBOXED
+for boxed (anonymous but reference counted) types (GBoxed*)
+.TP 12
+\fIPOINTER
+for anonymous pointer types (gpointer)
+.TP 12
+\fIOBJECT
+for GObject or derived types (GObject*)
+.TP 12
+\fINONE
+deprecated alias for \fIVOID\fP
+.TP 12
+\fIBOOL
+deprecated alias for \fIBOOLEAN\fP
+
+.SH EXAMPLE
+To generate marshallers for the following callback functions:
+.PP
+.RS
+.nf
+void   foo (gpointer data1,
+            gpointer data2);
+void   bar (gpointer data1,
+            gint     param1,
+            gpointer data2);
+gfloat baz (gpointer data1,
+            gboolean param1,
+            guchar   param2,
+            gpointer data2);
+.fi
+.RE
+.PP
+The marshaller list has to look like this:
+.PP
+.RS
+.nf
+VOID:VOID
+VOID:INT
+FLOAT:BOOLEAN,UCHAR
+.fi
+.RE
+.PP
+The generated marshallers have the arguments encoded
+in their function name. For this particular list, they
+are
+g_cclosure_marshal_VOID__VOID(),
+g_cclosure_marshal_VOID__INT(), 
+g_cclosure_marshal_FLOAT__BOOLEAN_UCHAR().
+.PP
+They can be used directly for GClosures or be passed in as
+the GSignalCMarshaller c_marshaller; argument upon creation
+of signals:
+.PP
+.nf
+GClosure *cc_foo, *cc_bar, *cc_baz;
+
+cc_foo = g_cclosure_new (NULL, foo, NULL);
+g_closure_set_marshal (cc_foo, g_cclosure_marshal_VOID__VOID);
+cc_bar = g_cclosure_new (NULL, bar, NULL);
+g_closure_set_marshal (cc_bar, g_cclosure_marshal_VOID__INT);
+cc_baz = g_cclosure_new (NULL, baz, NULL);
+g_closure_set_marshal (cc_baz, g_cclosure_marshal_FLOAT__BOOLEAN_UCHAR);
+.fi
+.PP
+
+
+.SH SEE ALSO
+\fB
+glib-config(1)
+\fP
+
+.SH BUGS 
+None known yet.
+
+.SH AUTHOR
+.B glib-genmarshal
+has been written by Tim Janik <timj@gtk.org>.
+.PP
+This manual page was provided by Tim Janik <timj@gtk.org>.
diff --git a/gobject/glib-genmarshal.c b/gobject/glib-genmarshal.c
new file mode 100644 (file)
index 0000000..34081f7
--- /dev/null
@@ -0,0 +1,693 @@
+/* GLIB-GenMarshal - Marshaller generator for GObject library
+ * Copyright (C) 2000 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       <fcntl.h>
+#include       <string.h>
+#include       <errno.h>
+#include       <unistd.h>
+#include       <sys/types.h>
+#include       <sys/stat.h>
+
+
+/* --- defines --- */
+#define        PRG_NAME        "glib-genmarshal"
+#define        PKG_NAME        "GLib"
+#define PKG_HTTP_HOME  "http://www.gtk.org"
+
+
+/* --- typedefs & structures --- */
+typedef struct _Argument  Argument;
+typedef struct _Signature Signature;
+struct _Argument
+{
+  gchar       *pname;          /* parsed name */
+  const gchar *sname;          /* signature name */
+  const gchar *func;           /* functional extension */
+  const gchar *cname;          /* C name */
+};
+struct _Signature
+{
+  gchar    *ploc;
+  Argument *rarg;
+  GList    *args;      /* of type Argument* */
+};
+
+
+/* --- prototypes --- */
+static void    parse_args      (gint           *argc_p,
+                                gchar       ***argv_p);
+static void    print_blurb     (FILE           *bout,
+                                gboolean        print_help);
+
+
+/* --- variables --- */
+static FILE          *fout = NULL;
+static GScannerConfig scanner_config_template =
+{
+  (
+   " \t\r"             /* "\n" is statement delimiter */
+   )                    /* cset_skip_characters */,
+  (
+   G_CSET_a_2_z
+   "_"
+   G_CSET_A_2_Z
+   )                    /* cset_identifier_first */,
+  (
+   G_CSET_a_2_z
+   "_0123456789"
+   G_CSET_A_2_Z
+   )                    /* cset_identifier_nth */,
+  ( "#\n" )             /* cpair_comment_single */,
+
+  FALSE                 /* case_sensitive */,
+
+  TRUE                  /* skip_comment_multi */,
+  TRUE                  /* skip_comment_single */,
+  TRUE                  /* scan_comment_multi */,
+  TRUE                  /* scan_identifier */,
+  FALSE                 /* scan_identifier_1char */,
+  FALSE                 /* scan_identifier_NULL */,
+  TRUE                  /* scan_symbols */,
+  FALSE                 /* scan_binary */,
+  TRUE                  /* scan_octal */,
+  TRUE                  /* scan_float */,
+  TRUE                  /* scan_hex */,
+  FALSE                 /* scan_hex_dollar */,
+  TRUE                  /* scan_string_sq */,
+  TRUE                  /* scan_string_dq */,
+  TRUE                  /* numbers_2_int */,
+  FALSE                 /* int_2_float */,
+  FALSE                 /* identifier_2_string */,
+  TRUE                  /* char_2_token */,
+  FALSE                 /* symbol_2_token */,
+  FALSE                 /* scope_0_fallback */,
+};
+static gchar           *marshaller_prefix = "g_cclosure_marshal";
+static GHashTable      *marshallers = NULL;
+static gboolean                 gen_cheader = FALSE;
+static gboolean                 gen_cbody = FALSE;
+static gboolean                 skip_ploc = FALSE;
+
+
+/* --- functions --- */
+static gboolean
+complete_arg (Argument *arg,
+             gboolean  is_return)
+{
+  static const Argument inout_arguments[] = {
+    /* pname,          sname,          func,                   cname           */
+    { "VOID",          "VOID",         NULL,                   "void",         },
+    { "BOOLEAN",       "BOOLEAN",      "boolean",              "gboolean",     },
+    { "CHAR",          "CHAR",         "char",                 "gchar",        },
+    { "UCHAR",         "UCHAR",        "uchar",                "guchar",       },
+    { "INT",           "INT",          "int",                  "gint",         },
+    { "UINT",          "UINT",         "uint",                 "guint",        },
+    { "LONG",          "LONG",         "long",                 "glong",        },
+    { "ULONG",         "ULONG",        "ulong",                "gulong",       },
+    { "ENUM",          "ENUM",         "enum",                 "gint",         },
+    { "FLAGS",         "FLAGS",        "flags",                "guint",        },
+    { "FLOAT",         "FLOAT",        "float",                "gfloat",       },
+    { "DOUBLE",                "DOUBLE",       "double",               "gdouble",      },
+    /* deprecated: */
+    { "NONE",          "VOID",         NULL,                   "void",         },
+    { "BOOL",          "BOOLEAN",      "boolean",              "gboolean",     },
+  };
+  static const Argument in_arguments[] = {
+    { "STRING",                "POINTER",      "as_pointer",           "gpointer",     },
+    { "BOXED",         "POINTER",      "as_pointer",           "gpointer",     },
+    { "POINTER",       "POINTER",      "as_pointer",           "gpointer",     },
+    { "OBJECT",                "POINTER",      "as_pointer",           "gpointer",     },
+  };
+  static const Argument out_arguments[] = {
+    { "STRING",                "STRING",       "string",               "gchar*",       },
+    { "BOXED",         "BOXED",        "boxed",                "gpointer",     },
+    { "POINTER",       "POINTER",      "pointer",              "gpointer",     },
+    { "OBJECT",                "OBJECT",       "object",               "GObject*",     },
+  };
+  const guint n_inout_arguments = sizeof (inout_arguments) / sizeof (inout_arguments[0]);
+  const guint n_out_arguments = sizeof (out_arguments) / sizeof (out_arguments[0]);
+  const guint n_in_arguments = sizeof (in_arguments) / sizeof (in_arguments[0]);
+  const Argument *arguments;
+  guint i, n_arguments;
+
+  g_return_val_if_fail (arg != NULL, FALSE);
+
+  arguments = inout_arguments;
+  n_arguments = n_inout_arguments;
+  for (i = 0; i < n_arguments; i++)
+    if (strcmp (arguments[i].pname, arg->pname) == 0)
+      {
+       arg->sname = arguments[i].sname;
+       arg->func = arguments[i].func;
+       arg->cname = arguments[i].cname;
+
+       return TRUE;
+      }
+  arguments = is_return ? out_arguments : in_arguments;
+  n_arguments = is_return ? n_out_arguments : n_in_arguments;
+  for (i = 0; i < n_arguments; i++)
+    if (strcmp (arguments[i].pname, arg->pname) == 0)
+      {
+       arg->sname = arguments[i].sname;
+       arg->func = arguments[i].func;
+       arg->cname = arguments[i].cname;
+
+       return TRUE;
+      }
+
+  return FALSE;
+}
+
+static const gchar*
+pad (const gchar *string)
+{
+#define PAD_LENGTH     12
+  static gchar *buffer = NULL;
+  gint i;
+
+  g_return_val_if_fail (string != NULL, NULL);
+
+  if (!buffer)
+    buffer = g_new (gchar, PAD_LENGTH + 1);
+
+  /* paranoid check */
+  if (strlen (string) >= PAD_LENGTH)
+    {
+      g_free (buffer);
+      buffer = g_strdup_printf ("%s ", string);
+      g_warning ("overfull string (%u bytes) for padspace", strlen (string));
+
+      return buffer;
+    }
+
+  for (i = 0; i < PAD_LENGTH; i++)
+    {
+      gboolean done = *string == 0;
+
+      buffer[i] = done ? ' ' : *string++;
+    }
+  buffer[i] = 0;
+
+  return buffer;
+}
+
+static const gchar*
+indent (guint n_spaces)
+{
+  static gchar *buffer;
+  static guint blength = 0;
+
+  if (blength <= n_spaces)
+    {
+      blength = n_spaces + 1;
+      g_free (buffer);
+      buffer = g_new (gchar, blength);
+    }
+  memset (buffer, ' ', n_spaces);
+  buffer[n_spaces] = 0;
+
+  return buffer;
+}
+
+static void
+generate_marshal (const gchar *signame,
+                 Signature   *sig)
+{
+  guint ind, a;
+  GList *node;
+
+  if (g_hash_table_lookup (marshallers, signame))
+    return;
+  else
+    {
+      gchar *tmp = g_strdup (signame);
+
+      g_hash_table_insert (marshallers, tmp, tmp);
+    }
+  
+  if (gen_cheader)
+    {
+      ind = fprintf (fout, "extern void ");
+      ind += fprintf (fout, "%s_%s (", marshaller_prefix, signame);
+      fprintf (fout,   "GClosure     *closure,\n");
+      fprintf (fout, "%sguint         invocation_hint,\n", indent (ind));
+      fprintf (fout, "%sGValue       *return_value,\n", indent (ind));
+      fprintf (fout, "%sguint         n_param_values,\n", indent (ind));
+      fprintf (fout, "%sconst GValue *param_values,\n", indent (ind));
+      fprintf (fout, "%sgpointer      marshal_data);\n", indent (ind));
+    }
+  if (gen_cbody)
+    {
+      /* cfile marhsal header */
+      fprintf (fout, "void\n");
+      ind = fprintf (fout, "%s_%s (", marshaller_prefix, signame);
+      fprintf (fout,   "GClosure     *closure,\n");
+      fprintf (fout, "%sguint         invocation_hint,\n", indent (ind));
+      fprintf (fout, "%sGValue       *return_value,\n", indent (ind));
+      fprintf (fout, "%sguint         n_param_values,\n", indent (ind));
+      fprintf (fout, "%sconst GValue *param_values,\n", indent (ind));
+      fprintf (fout, "%sgpointer      marshal_data)\n", indent (ind));
+      fprintf (fout, "{\n");
+
+      /* cfile GSignalFunc typedef */
+      ind = fprintf (fout, "  typedef %s (*GSignalFunc_%s) (", sig->rarg->cname, signame);
+      fprintf (fout, "%s data1,\n", pad ("gpointer"));
+      for (a = 1, node = sig->args; node; node = node->next)
+       {
+         Argument *arg = node->data;
+
+         if (arg->func)
+           fprintf (fout, "%s%s arg_%d,\n", indent (ind), pad (arg->cname), a++);
+       }
+      fprintf (fout, "%s%s data2);\n", indent (ind), pad ("gpointer"));
+
+      /* cfile marshal variables */
+      fprintf (fout, "  register GSignalFunc_%s callback;\n", signame);
+      fprintf (fout, "  register GCClosure *cc = (GCClosure*) closure;\n");
+      fprintf (fout, "  register gpointer data1, data2;\n");
+      if (sig->rarg->func)
+       fprintf (fout, "  %s v_return;\n", sig->rarg->cname);
+
+      if (sig->args || sig->rarg->func)
+       {
+         fprintf (fout, "\n");
+
+         if (sig->rarg->func)
+           fprintf (fout, "  g_return_if_fail (return_value != NULL);\n");
+         if (sig->args)
+           {
+             for (a = 0, node = sig->args; node; node = node->next)
+               {
+                 Argument *arg = node->data;
+
+                 if (arg->func)
+                   a++;
+               }
+             fprintf (fout, "  g_return_if_fail (n_param_values >= %u);\n", 1 + a);
+           }
+       }
+
+      /* cfile marshal data1, data2 and callback setup */
+      fprintf (fout, "\n");
+      fprintf (fout, "  if (G_CCLOSURE_SWAP_DATA (closure))\n    {\n");
+      fprintf (fout, "      data1 = closure->data;\n");
+      fprintf (fout, "      data2 = g_value_get_as_pointer (param_values + 0);\n");
+      fprintf (fout, "    }\n  else\n    {\n");
+      fprintf (fout, "      data1 = g_value_get_as_pointer (param_values + 0);\n");
+      fprintf (fout, "      data2 = closure->data;\n");
+      fprintf (fout, "    }\n");
+      fprintf (fout, "  callback = (GSignalFunc_%s) (marshal_data ? marshal_data : cc->callback);\n", signame);
+
+      /* cfile marshal callback action */
+      fprintf (fout, "\n");
+      ind = fprintf (fout, " %s callback (", sig->rarg->func ? " v_return =" : "");
+      fprintf (fout, "data1,\n");
+      for (a = 1, node = sig->args; node; node = node->next)
+       {
+         Argument *arg = node->data;
+
+         if (arg->func)
+           fprintf (fout, "%sg_value_get_%s (param_values + %d),\n", indent (ind), arg->func, a++);
+       }
+      fprintf (fout, "%sdata2);\n", indent (ind));
+
+      /* cfile marshal return value storage */
+      if (sig->rarg->func)
+       {
+         fprintf (fout, "\n");
+         fprintf (fout, "  g_value_set_%s (return_value, v_return);\n", sig->rarg->func);
+       }
+
+      /* cfile marshal footer */
+      fprintf (fout, "}\n");
+    }
+}
+
+static void
+process_signature (Signature *sig)
+{
+  gchar *pname, *sname;
+  GList *node;
+
+  /* lookup and complete info on arguments */
+  if (!complete_arg (sig->rarg, TRUE))
+    {
+      g_warning ("unknown type: %s", sig->rarg->pname);
+      return;
+    }
+  for (node = sig->args; node; node = node->next)
+    {
+      Argument *arg = node->data;
+
+      if (!complete_arg (arg, FALSE))
+       {
+         g_warning ("unknown type: %s", arg->pname);
+         return;
+       }
+    }
+
+  /* construct requested marshaller name and technical marshaller name */
+  pname = g_strconcat (sig->rarg->pname, "_", NULL);
+  sname = g_strconcat (sig->rarg->sname, "_", NULL);
+  for (node = sig->args; node; node = node->next)
+    {
+      Argument *arg = node->data;
+      gchar *tmp;
+
+      tmp = sname;
+      sname = g_strconcat (tmp, "_", arg->sname, NULL);
+      g_free (tmp);
+      tmp = pname;
+      pname = g_strconcat (tmp, "_", arg->pname, NULL);
+      g_free (tmp);
+    }
+
+  /* introductionary comment */
+  fprintf (fout, "\n/* %s", sig->rarg->pname);
+  for (node = sig->args; node; node = node->next)
+    {
+      Argument *arg = node->data;
+
+      fprintf (fout, "%c%s", node->prev ? ',' : ':', arg->pname);
+    }
+  if (!skip_ploc)
+    fprintf (fout, " (%s)", sig->ploc);
+  fprintf (fout, " */\n");
+
+  /* generate signature marshaller */
+  generate_marshal (sname, sig);
+
+  /* put out marshaler alias if required */
+  if (gen_cheader && !g_hash_table_lookup (marshallers, pname))
+    {
+      gchar *tmp = g_strdup (pname);
+
+      fprintf (fout, "#define %s_%s\t%s_%s\n", marshaller_prefix, pname, marshaller_prefix, sname);
+
+      g_hash_table_insert (marshallers, tmp, tmp);
+    }
+
+  g_free (pname);
+  g_free (sname);
+}
+
+static Argument*
+new_arg (const gchar *pname)
+{
+  Argument *arg = g_new0 (Argument, 1);
+
+  arg->pname = g_strdup (pname);
+
+  return arg;
+}
+
+static guint
+parse_line (GScanner  *scanner,
+           Signature *sig)
+{
+  /* parse identifier for return value */
+  if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
+    return G_TOKEN_IDENTIFIER;
+  sig->rarg = new_arg (scanner->value.v_identifier);
+
+  /* keep a note on the location */
+  sig->ploc = g_strdup_printf ("%s:%u", scanner->input_name, scanner->line);
+
+  /* expect ':' */
+  if (g_scanner_get_next_token (scanner) != ':')
+    return ':';
+
+  /* parse first argument */
+  if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
+    return G_TOKEN_IDENTIFIER;
+  sig->args = g_list_append (sig->args, new_arg (scanner->value.v_identifier));
+
+  /* parse rest of argument list */
+  while (g_scanner_peek_next_token (scanner) == ',')
+    {
+      /* eat comma */
+      g_scanner_get_next_token (scanner);
+
+      /* parse arg identifier */
+      if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
+       return G_TOKEN_IDENTIFIER;
+      sig->args = g_list_append (sig->args, new_arg (scanner->value.v_identifier));
+    }
+  
+  /* expect end of line, done */
+  if (g_scanner_get_next_token (scanner) != '\n')
+    return '\n';
+  
+  /* success */
+  return G_TOKEN_NONE;
+}
+
+static gboolean
+string_key_destroy (gpointer key,
+                   gpointer value,
+                   gpointer user_data)
+{
+  g_free (key);
+
+  return TRUE;
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+  GScanner *scanner;
+  GSList *slist, *files = NULL;
+  gint i;
+
+  /* parse args and do fast exits */
+  parse_args (&argc, &argv);
+
+  /* list input files */
+  for (i = 1; i < argc; i++)
+    files = g_slist_prepend (files, argv[i]);
+  if (files)
+    files = g_slist_reverse (files);
+  else
+    files = g_slist_prepend (files, "/dev/stdin");
+
+  /* setup auxillary structs */
+  scanner = g_scanner_new (&scanner_config_template);
+  fout = stdout;
+  marshallers = g_hash_table_new (g_str_hash, g_str_equal);
+
+  /* process input files */
+  for (slist = files; slist; slist = slist->next)
+    {
+      gchar *file = slist->data;
+      gint fd = open (file, O_RDONLY);
+
+      if (fd < 0)
+       {
+         g_warning ("failed to open \"%s\": %s", file, g_strerror (errno));
+         continue;
+       }
+
+      /* set file name for error reports */
+      scanner->input_name = file;
+
+      /* parse & process file */
+      g_scanner_input_file (scanner, fd);
+      
+      /* scanning loop, we parse the input untill it's end is reached,
+       * or our sub routine came across invalid syntax
+       */
+      do
+       {
+         guint expected_token = G_TOKEN_NONE;
+
+         switch (g_scanner_peek_next_token (scanner))
+           {
+           case '\n':
+             /* eat newline and restart */
+             g_scanner_get_next_token (scanner);
+             continue;
+           case G_TOKEN_EOF:
+             /* done */
+             break;
+           default:
+             /* parse and process signatures */
+             {
+               Signature signature = { NULL, NULL, NULL };
+               GList *node;
+
+               expected_token = parse_line (scanner, &signature);
+               
+               /* once we got a valid signature, process it */
+               if (expected_token == G_TOKEN_NONE)
+                 process_signature (&signature);
+               
+               /* clean up signature contents */
+               g_free (signature.ploc);
+               if (signature.rarg)
+                 g_free (signature.rarg->pname);
+               g_free (signature.rarg);
+               for (node = signature.args; node; node = node->next)
+                 {
+                   Argument *arg = node->data;
+                   
+                   g_free (arg->pname);
+                   g_free (arg);
+                 }
+               g_list_free (signature.args);
+             }
+             break;
+           }
+
+         /* bail out on errors */
+         if (expected_token != G_TOKEN_NONE)
+           {
+             g_scanner_unexp_token (scanner, expected_token, "type name", NULL, NULL, NULL, TRUE);
+             break;
+           }
+
+         g_scanner_peek_next_token (scanner);
+       }
+      while (scanner->next_token != G_TOKEN_EOF);
+
+      close (fd);
+    }
+
+  /* clean up */
+  g_slist_free (files);
+  g_scanner_destroy (scanner);
+  g_hash_table_foreach_remove (marshallers, string_key_destroy, NULL);
+  g_hash_table_destroy (marshallers);
+
+  return 0;
+}
+
+static void
+parse_args (gint    *argc_p,
+           gchar ***argv_p)
+{
+  guint argc = *argc_p;
+  gchar **argv = *argv_p;
+  guint i, e;
+  
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp ("--header", argv[i]) == 0)
+       {
+         gen_cheader = TRUE;
+         argv[i] = NULL;
+       }
+      else if (strcmp ("--body", argv[i]) == 0)
+       {
+         gen_cbody = TRUE;
+         argv[i] = NULL;
+       }
+      else if (strcmp ("--skip-source", argv[i]) == 0)
+       {
+         skip_ploc = TRUE;
+         argv[i] = NULL;
+       }
+      else if ((strcmp ("--prefix", argv[i]) == 0) ||
+              (strncmp ("--prefix=", argv[i], 9) == 0))
+       {
+          gchar *equal = argv[i] + 8;
+
+         if (*equal == '=')
+           marshaller_prefix = g_strdup (equal + 1);
+         else if (i + 1 < argc)
+           {
+             marshaller_prefix = g_strdup (argv[i + 1]);
+             argv[i] = NULL;
+             i += 1;
+           }
+         argv[i] = NULL;
+       }
+      else if (strcmp ("-h", argv[i]) == 0 ||
+         strcmp ("--help", argv[i]) == 0)
+       {
+         print_blurb (stderr, TRUE);
+         argv[i] = NULL;
+         exit (0);
+       }
+      else if (strcmp ("-v", argv[i]) == 0 ||
+              strcmp ("--version", argv[i]) == 0)
+       {
+         print_blurb (stderr, FALSE);
+         argv[i] = NULL;
+         exit (0);
+       }
+      else if (strcmp (argv[i], "--g-fatal-warnings") == 0)
+       {
+         GLogLevelFlags fatal_mask;
+         
+         fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
+         fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
+         g_log_set_always_fatal (fatal_mask);
+         
+         argv[i] = NULL;
+       }
+    }
+  
+  e = 0;
+  for (i = 1; i < argc; i++)
+    {
+      if (e)
+       {
+         if (argv[i])
+           {
+             argv[e++] = argv[i];
+             argv[i] = NULL;
+           }
+       }
+      else if (!argv[i])
+       e = i;
+    }
+  if (e)
+    *argc_p = e;
+}
+
+static void
+print_blurb (FILE    *bout,
+            gboolean print_help)
+{
+  if (!print_help)
+    {
+      fprintf (bout, "%s version ", PRG_NAME);
+      fprintf (bout, "%u.%u.%u", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
+      fprintf (bout, "\n");
+      fprintf (bout, "%s comes with ABSOLUTELY NO WARRANTY.\n", PRG_NAME);
+      fprintf (bout, "You may redistribute copies of %s under the terms of\n", PRG_NAME);
+      fprintf (bout, "the GNU General Public License which can be found in the\n");
+      fprintf (bout, "%s source package. Sources, examples and contact\n", PKG_NAME);
+      fprintf (bout, "information are available at %s\n", PKG_HTTP_HOME);
+    }
+  else
+    {
+      fprintf (bout, "Usage: %s [options] [files...]\n", PRG_NAME);
+      fprintf (bout, "  --header                        generate C headers\n");
+      fprintf (bout, "  --body                          generate C code\n");
+      fprintf (bout, "  --prefix=string                 specify marshaller prefix\n");
+      fprintf (bout, "  --skip-source                   skip source location comments\n");
+      fprintf (bout, "  -h, --help                      show this help message\n");
+      fprintf (bout, "  -v, --version                   print version informations\n");
+      fprintf (bout, "  --g-fatal-warnings              make warnings fatal (abort)\n");
+    }
+}
index 3e0b37d5384813f378ba96ad057cdb9046ad9227..b80709adcc3b5b338317b64810b8fa6919688bef 100644 (file)
@@ -16,7 +16,7 @@
  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  * Boston, MA 02111-1307, USA.
  */
-#include       "config.h"
+#include       "../config.h"
 
 #include        <glib-object.h>
 
index 5a703cebb396c3930b7f08e560d53461a11e66ab..e5519107cf55d65a282b5518a50c26aaf3a4e9d6 100644 (file)
@@ -46,6 +46,7 @@ static void   g_value_object_init                     (GValue         *value);
 static void    g_value_object_free_value               (GValue         *value);
 static void    g_value_object_copy_value               (const GValue   *src_value,
                                                         GValue         *dest_value);
+static gpointer g_value_object_peek_pointer             (const GValue   *value);
 static gchar*  g_value_object_collect_value            (GValue         *value,
                                                         guint           nth_value,
                                                         GType          *collect_type,
@@ -59,6 +60,7 @@ static gchar* g_value_object_lcopy_value              (const GValue   *value,
 /* --- variables --- */
 static GQuark           quark_param_id = 0;
 static GQuark           quark_param_changed_queue = 0;
+static GQuark           quark_closure_array = 0;
 static GHashTable      *param_spec_hash_table = NULL;
 
 
@@ -122,6 +124,7 @@ g_object_type_init (void)   /* sync with gtype.c */
     g_value_object_init,         /* value_init */
     g_value_object_free_value,   /* value_free */
     g_value_object_copy_value,   /* value_copy */
+    g_value_object_peek_pointer,  /* value_peek_pointer */
     G_VALUE_COLLECT_POINTER,     /* collect_type */
     g_value_object_collect_value, /* collect_value */
     G_VALUE_COLLECT_POINTER,     /* lcopy_type */
@@ -135,7 +138,7 @@ g_object_type_init (void)   /* sync with gtype.c */
   /* G_TYPE_OBJECT
    */
   info.value_table = &value_table;
-  type = g_type_register_fundamental (G_TYPE_OBJECT, "GObject", &info, &finfo);
+  type = g_type_register_fundamental (G_TYPE_OBJECT, "GObject", &info, &finfo, 0);
   g_assert (type == G_TYPE_OBJECT);
   
 #ifdef DEBUG_OBJECTS
@@ -178,6 +181,7 @@ 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");
+  quark_closure_array = g_quark_from_static_string ("GObject-closure-array");
   param_spec_hash_table = g_param_spec_hash_table_new ();
   
   class->queue_param_changed = g_object_do_queue_param_changed;
@@ -810,6 +814,12 @@ g_value_object_copy_value (const GValue *src_value,
     dest_value->data[0].v_pointer = NULL;
 }
 
+static gpointer
+g_value_object_peek_pointer (const GValue *value)
+{
+  return value->data[0].v_pointer;
+}
+
 static gchar*
 g_value_object_collect_value (GValue     *value,
                              guint        nth_value,
@@ -874,7 +884,7 @@ g_value_set_object (GValue  *value,
 }
 
 GObject*
-g_value_get_object (GValue *value)
+g_value_get_object (const GValue *value)
 {
   g_return_val_if_fail (G_IS_VALUE_OBJECT (value), NULL);
   
@@ -882,9 +892,137 @@ g_value_get_object (GValue *value)
 }
 
 GObject*
-g_value_dup_object (GValue *value)
+g_value_dup_object (const 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;
 }
+
+typedef struct {
+  GObject  *object;
+  guint     n_closures;
+  GClosure *closures[1]; /* flexible array */
+} CArray;
+
+static void
+object_remove_closure (gpointer  data,
+                      GClosure *closure)
+{
+  GObject *object = data;
+  CArray *carray = g_object_get_qdata (object, quark_closure_array);
+  guint i;
+  
+  for (i = 0; i < carray->n_closures; i++)
+    if (carray->closures[i] == closure)
+      {
+       carray->n_closures--;
+       if (i < carray->n_closures)
+         carray->closures[i] = carray->closures[carray->n_closures];
+       return;
+      }
+  g_assert_not_reached ();
+}
+
+static void
+destroy_closure_array (gpointer data)
+{
+  CArray *carray = data;
+  GObject *object = carray->object;
+  guint i, n = carray->n_closures;
+  
+  for (i = 0; i < n; i++)
+    {
+      GClosure *closure = carray->closures[i];
+      
+      /* removing object_remove_closure() upfront is probably faster than
+       * letting it fiddle with quark_closure_array which is empty anyways
+       */
+      g_closure_remove_inotify (closure, object, object_remove_closure);
+      g_closure_invalidate (closure);
+    }
+  g_free (carray);
+}
+
+void
+g_object_watch_closure (GObject  *object,
+                       GClosure *closure)
+{
+  CArray *carray;
+  
+  g_return_if_fail (G_IS_OBJECT (object));
+  g_return_if_fail (closure != NULL);
+  g_return_if_fail (closure->is_invalid == FALSE);
+  g_return_if_fail (closure->in_marshal == FALSE);
+  g_return_if_fail (object->ref_count > 0);    /* this doesn't work on finalizing objects */
+  
+  g_closure_add_inotify (closure, object, object_remove_closure);
+  g_closure_add_marshal_guards (closure,
+                               object, (GClosureNotify) g_object_ref,
+                               object, (GClosureNotify) g_object_unref);
+  carray = g_object_get_qdata (object, quark_closure_array);
+  if (!carray)
+    {
+      carray = g_renew (CArray, NULL, 1);
+      carray->object = object;
+      carray->n_closures = 1;
+      carray->closures[0] = closure;
+      g_object_set_qdata_full (object, quark_closure_array, carray, destroy_closure_array);
+    }
+  else
+    {
+      guint i = carray->n_closures++;
+      
+      carray = g_realloc (carray, sizeof (*carray) + sizeof (carray->closures[0]) * i);
+      carray->closures[i] = closure;
+    }
+}
+
+GClosure*
+g_closure_new_object (guint    sizeof_closure,
+                     GObject *object)
+{
+  GClosure *closure;
+
+  g_return_val_if_fail (G_IS_OBJECT (object), NULL);
+  g_return_val_if_fail (object->ref_count > 0, NULL);     /* this doesn't work on finalizing objects */
+
+  closure = g_closure_new_simple (sizeof_closure, object);
+  g_object_watch_closure (object, closure);
+
+  return closure;
+}
+
+GClosure*
+g_cclosure_new_object (gpointer  _object,
+                      GCallback callback_func)
+{
+  GObject *object = _object;
+  GClosure *closure;
+
+  g_return_val_if_fail (G_IS_OBJECT (object), NULL);
+  g_return_val_if_fail (object->ref_count > 0, NULL);     /* this doesn't work on finalizing objects */
+  g_return_val_if_fail (callback_func != NULL, NULL);
+
+  closure = g_cclosure_new (callback_func, object, NULL);
+  g_object_watch_closure (object, closure);
+
+  return closure;
+}
+
+GClosure*
+g_cclosure_new_object_swap (gpointer  _object,
+                           GCallback callback_func)
+{
+  GObject *object = _object;
+  GClosure *closure;
+
+  g_return_val_if_fail (G_IS_OBJECT (object), NULL);
+  g_return_val_if_fail (object->ref_count > 0, NULL);     /* this doesn't work on finalizing objects */
+  g_return_val_if_fail (callback_func != NULL, NULL);
+
+  closure = g_cclosure_new_swap (callback_func, object, NULL);
+  g_object_watch_closure (object, closure);
+
+  return closure;
+}
index 68657abb06617a0a39ad2f54041dcc70e34995ce..4926468880ec49c282af2ff9646043de14b0a6d8 100644 (file)
  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  * Boston, MA 02111-1307, USA.
  */
-#ifndef __G_GOBJECT_H__
-#define __G_GOBJECT_H__
+#ifndef __G_OBJECT_H__
+#define __G_OBJECT_H__
 
 #include       <gobject/gtype.h>
 #include       <gobject/gvalue.h>
 #include       <gobject/gparam.h>
+#include       <gobject/gclosure.h>
 
 
 #ifdef __cplusplus
@@ -31,38 +32,35 @@ extern "C" {
 
 /* --- 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(object)          (G_TYPE_CHECK_INSTANCE_CAST ((object), G_TYPE_OBJECT, GObject))
+#define G_OBJECT_CLASS(class)     (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_OBJECT, GObjectClass))
+#define G_IS_OBJECT(object)       (G_TYPE_CHECK_INSTANCE_TYPE ((object), G_TYPE_OBJECT))
+#define G_IS_OBJECT_CLASS(class)   (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_OBJECT))
 #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_IS_VALUE_OBJECT(value)   (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_OBJECT))
+#define G_IS_VALUE_OBJECT(value)   (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_OBJECT))
 
 #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);
+typedef struct _GObject                      GObject;
+typedef struct _GObjectClass          GObjectClass;
+typedef struct _GObjectConstructParam GObjectConstructParam;
+typedef void (*GObjectGetParamFunc)    (GObject      *object,
+                                        guint         param_id,
+                                        GValue       *value,
+                                        GParamSpec   *pspec,
+                                        const gchar  *trailer);
+typedef void (*GObjectSetParamFunc)    (GObject      *object,
+                                        guint         param_id,
+                                        const GValue *value,
+                                        GParamSpec   *pspec,
+                                        const gchar  *trailer);
+typedef void (*GObjectFinalizeFunc)    (GObject      *object);
 struct _GObject
 {
   GTypeInstance g_type_instance;
@@ -77,7 +75,10 @@ struct       _GObjectClass
 
   guint               n_param_specs;
   GParamSpec **param_specs;
-  
+
+  GObject*   (*constructor)    (GType                  type, // FIXME!!!
+                                guint                  n_construct_params,
+                                GObjectConstructParam *construct_params);
   void      (*get_param)               (GObject        *object,
                                         guint           param_id,
                                         GValue         *value,
@@ -85,7 +86,7 @@ struct        _GObjectClass
                                         const gchar    *trailer);
   void      (*set_param)               (GObject        *object,
                                         guint           param_id,
-                                        GValue         *value,
+                                        const GValue   *value,
                                         GParamSpec     *pspec,
                                         const gchar    *trailer);
   void      (*queue_param_changed)     (GObject        *object,
@@ -95,6 +96,12 @@ struct       _GObjectClass
   void      (*shutdown)                (GObject        *object);
   void      (*finalize)                (GObject        *object);
 };
+struct _GObjectConstructParam
+{
+  GParamSpec *pspec;
+  GValue     *value;
+  gchar      *trailer;
+};
 
 
 /* --- prototypes --- */
@@ -142,10 +149,18 @@ void          g_object_set_qdata_full        (GObject        *object,
                                            GDestroyNotify  destroy);
 gpointer    g_object_steal_qdata          (GObject        *object,
                                            GQuark          quark);
+void       g_object_watch_closure         (GObject        *object,
+                                           GClosure       *closure);
+GClosure*   g_cclosure_new_object         (gpointer        object,
+                                           GCallback       callback_func);
+GClosure*   g_cclosure_new_object_swap    (gpointer        object,
+                                           GCallback       callback_func);
+GClosure*   g_closure_new_object          (guint           sizeof_closure,
+                                           GObject        *object);
 void        g_value_set_object            (GValue         *value,
                                            GObject        *v_object);
-GObject*    g_value_get_object            (GValue         *value);
-GObject*    g_value_dup_object            (GValue         *value);
+GObject*    g_value_get_object            (const GValue   *value);
+GObject*    g_value_dup_object            (const GValue   *value);
 
 
 /* --- implementation macros --- */
@@ -168,4 +183,4 @@ G_STMT_START { \
 }
 #endif /* __cplusplus */
 
-#endif /* __G_GOBJECT_H__ */
+#endif /* __G_OBJECT_H__ */
index e74787851e49561016b316e42221575e7eede984..9ce72c379180472d2759a827886fb7271e3cc7b4 100644 (file)
@@ -63,7 +63,7 @@ g_param_type_init (void)      /* sync with gtype.c */
   };
   GType type;
 
-  type = g_type_register_fundamental (G_TYPE_PARAM, "GParam", &param_spec_info, &finfo);
+  type = g_type_register_fundamental (G_TYPE_PARAM, "GParam", &param_spec_info, &finfo, G_TYPE_FLAG_ABSTRACT);
   g_assert (type == G_TYPE_PARAM);
 }
 
@@ -380,3 +380,91 @@ g_param_spec_hash_table_lookup (GHashTable   *hash_table,
   
   return pspec;
 }
+
+
+/* --- auxillary functions --- */
+typedef struct
+{
+  /* class portion */
+  GType           value_type;
+  void          (*finalize)             (GParamSpec   *pspec);
+  void          (*value_set_default)    (GParamSpec   *pspec,
+                                        GValue       *value);
+  gboolean      (*value_validate)       (GParamSpec   *pspec,
+                                        GValue       *value);
+  gint          (*values_cmp)           (GParamSpec   *pspec,
+                                        const GValue *value1,
+                                        const GValue *value2);
+} ParamSpecClassInfo;
+
+static void
+param_spec_generic_class_init (gpointer g_class,
+                              gpointer class_data)
+{
+  GParamSpecClass *class = g_class;
+  ParamSpecClassInfo *info = class_data;
+
+  class->value_type = info->value_type;
+  if (info->finalize)
+    class->finalize = info->finalize;                  /* optional */
+  class->value_set_default = info->value_set_default;
+  if (info->value_validate)
+    class->value_validate = info->value_validate;      /* optional */
+  class->values_cmp = info->values_cmp;
+  g_free (class_data);
+}
+
+static void
+default_value_set_default (GParamSpec *pspec,
+                          GValue     *value)
+{
+  /* value is already zero initialized */
+}
+
+static gint
+default_values_cmp (GParamSpec   *pspec,
+                   const GValue *value1,
+                   const GValue *value2)
+{
+  return memcmp (&value1->data, &value2->data, sizeof (value1->data));
+}
+
+GType
+g_param_type_register_static (const gchar              *name,
+                             const GParamSpecTypeInfo *pspec_info)
+{
+  GTypeInfo info = {
+    sizeof (GParamSpecClass),      /* class_size */
+    NULL,                          /* base_init */
+    NULL,                          /* base_destroy */
+    param_spec_generic_class_init, /* class_init */
+    NULL,                          /* class_destroy */
+    NULL,                          /* class_data */
+    0,                             /* instance_size */
+    16,                            /* n_preallocs */
+    NULL,                          /* instance_init */
+  };
+  ParamSpecClassInfo *cinfo;
+
+  g_return_val_if_fail (name != NULL, 0);
+  g_return_val_if_fail (pspec_info != NULL, 0);
+  g_return_val_if_fail (g_type_from_name (name) == 0, 0);
+  g_return_val_if_fail (pspec_info->instance_size >= sizeof (GParamSpec), 0);
+  g_return_val_if_fail (g_type_name (pspec_info->value_type) != NULL, 0);
+  /* default: g_return_val_if_fail (pspec_info->value_set_default != NULL, 0); */
+  /* optional: g_return_val_if_fail (pspec_info->value_validate != NULL, 0); */
+  /* default: g_return_val_if_fail (pspec_info->values_cmp != NULL, 0); */
+
+  info.instance_size = pspec_info->instance_size;
+  info.n_preallocs = pspec_info->n_preallocs;
+  info.instance_init = (GInstanceInitFunc) pspec_info->instance_init;
+  cinfo = g_new (ParamSpecClassInfo, 1);
+  cinfo->value_type = pspec_info->value_type;
+  cinfo->finalize = pspec_info->finalize;
+  cinfo->value_set_default = pspec_info->value_set_default ? pspec_info->value_set_default : default_value_set_default;
+  cinfo->value_validate = pspec_info->value_validate;
+  cinfo->values_cmp = pspec_info->values_cmp ? pspec_info->values_cmp : default_values_cmp;
+  info.class_data = cinfo;
+
+  return g_type_register_static (G_TYPE_PARAM, name, &info, 0);
+}
index 370fb4ff9f1f02257d986b2985ed51378b3ae2e6..8b1f3f1cf8cb1a894a0f46640064b4c72ea46c17 100644 (file)
@@ -113,6 +113,30 @@ gint               g_param_values_cmp              (GParamSpec    *pspec,
                                                 const GValue  *value2);
 
 
+/* --- convenience functions --- */
+typedef struct _GParamSpecTypeInfo GParamSpecTypeInfo;
+struct _GParamSpecTypeInfo
+{
+  /* type system portion */
+  guint16         instance_size;                               /* obligatory */
+  guint16         n_preallocs;                                 /* optional */
+  void         (*instance_init)        (GParamSpec   *pspec); /* optional */
+
+  /* class portion */
+  GType           value_type;                                 /* obligatory */
+  void          (*finalize)             (GParamSpec   *pspec); /* optional */
+  void          (*value_set_default)    (GParamSpec   *pspec,  /* recommended */
+                                        GValue       *value);
+  gboolean      (*value_validate)       (GParamSpec   *pspec,  /* optional */
+                                        GValue       *value);
+  gint          (*values_cmp)           (GParamSpec   *pspec,  /* recommended */
+                                        const GValue *value1,
+                                        const GValue *value2);
+};
+GType  g_param_type_register_static    (const gchar              *name,
+                                        const GParamSpecTypeInfo *pspec_info);
+
+
 /* --- private --- */
 gpointer       g_param_spec_internal           (GType          param_type,
                                                 const gchar   *name,
@@ -134,44 +158,18 @@ GParamSpec*       g_param_spec_hash_table_lookup  (GHashTable    *hash_table,
 
 /* contracts:
  *
- * +++ OUTDATED +++
- *
- * 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
+ * gboolean value_validate (GParamSpec *pspec,
+ *                          GValue     *value):
+ *     modify value contents 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.
- *
+ * gint values_cmp (GParamSpec   *pspec,
+ *                  const GValue *value1,
+ *                  const GValue *value2):
+ *     return value1 - value2, i.e. <0 if value1 < value2,
+ *     >0 if value1 > value2, and 0 otherwise (they are equal)
  */
 
 #ifdef __cplusplus
index d78689f0aa1772891708edbf76baee5e802444e6..10b8ab3c6b6c082aa658b798d8e689c7df326d7c 100644 (file)
@@ -20,7 +20,7 @@
 
 #include       "gvaluecollector.h"
 #include       <string.h>
-#include       "config.h"      /* for SIZEOF_LONG */
+#include       "../config.h"   /* for SIZEOF_LONG */
 
 #define        G_FLOAT_EPSILON         (1e-30)
 #define        G_DOUBLE_EPSILON        (1e-90)
@@ -710,272 +710,229 @@ value_exch_double_float (GValue *value1,
 
 
 /* --- type initialization --- */
-typedef struct {
-  GType           value_type;
-  void         (*finalize)             (GParamSpec   *pspec);
-  void          (*value_set_default)    (GParamSpec   *pspec,
-                                        GValue       *value);
-  gboolean      (*value_validate)       (GParamSpec   *pspec,
-                                        GValue       *value);
-  gint          (*values_cmp)           (GParamSpec   *pspec,
-                                        const GValue *value1,
-                                        const GValue *value2);
-} ParamSpecClassInfo;
-
-static void
-param_spec_class_init (gpointer g_class,
-                      gpointer class_data)
-{
-  GParamSpecClass *class = g_class;
-  ParamSpecClassInfo *info = class_data;
-
-  g_assert (info->value_type && !G_TYPE_IS_PARAM (info->value_type));
-
-  class->value_type = info->value_type;
-  if (info->finalize)
-    class->finalize = info->finalize;
-  if (info->value_set_default)
-    class->value_set_default = info->value_set_default;
-  if (info->value_validate)
-    class->value_validate = info->value_validate;
-  if (info->values_cmp)
-    class->values_cmp = info->values_cmp;
-}
-
 void
 g_param_spec_types_init (void) /* sync with gtype.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 = {
+    static const GParamSpecTypeInfo pspec_info = {
+      sizeof (GParamSpecChar), /* instance_size */
+      16,                      /* n_preallocs */
+      param_spec_char_init,    /* instance_init */
       G_TYPE_CHAR,             /* value_type */
       NULL,                    /* finalize */
       param_char_set_default,  /* value_set_default */
       param_char_validate,     /* value_validate */
       param_int_values_cmp,    /* values_cmp */
     };
-    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);
+    type = g_param_type_register_static ("GParamChar", &pspec_info);
     g_assert (type == G_TYPE_PARAM_CHAR);
   }
   
   /* G_TYPE_PARAM_UCHAR
    */
   {
-    static const ParamSpecClassInfo class_info = {
+    static const GParamSpecTypeInfo pspec_info = {
+      sizeof (GParamSpecUChar), /* instance_size */
+      16,                       /* n_preallocs */
+      param_spec_uchar_init,    /* instance_init */
       G_TYPE_UCHAR,            /* value_type */
       NULL,                    /* finalize */
       param_uchar_set_default, /* value_set_default */
       param_uchar_validate,    /* value_validate */
       param_uint_values_cmp,   /* values_cmp */
     };
-    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);
+    type = g_param_type_register_static ("GParamUChar", &pspec_info);
     g_assert (type == G_TYPE_PARAM_UCHAR);
   }
   
   /* G_TYPE_PARAM_BOOLEAN
    */
   {
-    static const ParamSpecClassInfo class_info = {
-      G_TYPE_BOOLEAN,            /* value_type */
-      NULL,                      /* finalize */
-      param_boolean_set_default, /* value_set_default */
-      param_boolean_validate,    /* value_validate */
-      param_int_values_cmp,      /* values_cmp */
+    static const GParamSpecTypeInfo pspec_info = {
+      sizeof (GParamSpecBoolean), /* instance_size */
+      16,                         /* n_preallocs */
+      NULL,                      /* instance_init */
+      G_TYPE_BOOLEAN,             /* value_type */
+      NULL,                       /* finalize */
+      param_boolean_set_default,  /* value_set_default */
+      param_boolean_validate,     /* value_validate */
+      param_int_values_cmp,       /* values_cmp */
     };
-    info.class_data = &class_info;
-    info.instance_size = sizeof (GParamSpecBoolean);
-    info.instance_init = (GInstanceInitFunc) NULL;
-    type = g_type_register_static (G_TYPE_PARAM, "GParamBoolean", &info);
+    type = g_param_type_register_static ("GParamBoolean", &pspec_info);
     g_assert (type == G_TYPE_PARAM_BOOLEAN);
   }
   
   /* G_TYPE_PARAM_INT
    */
   {
-    static const ParamSpecClassInfo class_info = {
+    static const GParamSpecTypeInfo pspec_info = {
+      sizeof (GParamSpecInt),   /* instance_size */
+      16,                       /* n_preallocs */
+      param_spec_int_init,      /* instance_init */
       G_TYPE_INT,              /* value_type */
       NULL,                    /* finalize */
       param_int_set_default,   /* value_set_default */
       param_int_validate,      /* value_validate */
       param_int_values_cmp,    /* values_cmp */
     };
-    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);
+    type = g_param_type_register_static ("GParamInt", &pspec_info);
     g_assert (type == G_TYPE_PARAM_INT);
   }
   
   /* G_TYPE_PARAM_UINT
    */
   {
-    static const ParamSpecClassInfo class_info = {
+    static const GParamSpecTypeInfo pspec_info = {
+      sizeof (GParamSpecUInt),  /* instance_size */
+      16,                       /* n_preallocs */
+      param_spec_uint_init,     /* instance_init */
       G_TYPE_UINT,             /* value_type */
       NULL,                    /* finalize */
       param_uint_set_default,  /* value_set_default */
       param_uint_validate,     /* value_validate */
       param_uint_values_cmp,   /* values_cmp */
     };
-    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);
+    type = g_param_type_register_static ("GParamUInt", &pspec_info);
     g_assert (type == G_TYPE_PARAM_UINT);
   }
   
   /* G_TYPE_PARAM_LONG
    */
   {
-    static const ParamSpecClassInfo class_info = {
+    static const GParamSpecTypeInfo pspec_info = {
+      sizeof (GParamSpecLong),  /* instance_size */
+      16,                       /* n_preallocs */
+      param_spec_long_init,     /* instance_init */
       G_TYPE_LONG,             /* value_type */
       NULL,                    /* finalize */
       param_long_set_default,  /* value_set_default */
       param_long_validate,     /* value_validate */
       param_long_values_cmp,   /* values_cmp */
     };
-    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);
+    type = g_param_type_register_static ("GParamLong", &pspec_info);
     g_assert (type == G_TYPE_PARAM_LONG);
   }
   
   /* G_TYPE_PARAM_ULONG
    */
   {
-    static const ParamSpecClassInfo class_info = {
+    static const GParamSpecTypeInfo pspec_info = {
+      sizeof (GParamSpecULong), /* instance_size */
+      16,                       /* n_preallocs */
+      param_spec_ulong_init,    /* instance_init */
       G_TYPE_ULONG,            /* value_type */
       NULL,                    /* finalize */
       param_ulong_set_default, /* value_set_default */
       param_ulong_validate,    /* value_validate */
       param_ulong_values_cmp,  /* values_cmp */
     };
-    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);
+    type = g_param_type_register_static ("GParamULong", &pspec_info);
     g_assert (type == G_TYPE_PARAM_ULONG);
   }
   
   /* G_TYPE_PARAM_ENUM
    */
   {
-    static const ParamSpecClassInfo class_info = {
+    static const GParamSpecTypeInfo pspec_info = {
+      sizeof (GParamSpecEnum),  /* instance_size */
+      16,                       /* n_preallocs */
+      param_spec_enum_init,     /* instance_init */
       G_TYPE_ENUM,             /* value_type */
       param_spec_enum_finalize,        /* finalize */
       param_enum_set_default,  /* value_set_default */
       param_enum_validate,     /* value_validate */
       param_long_values_cmp,   /* values_cmp */
     };
-    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);
+    type = g_param_type_register_static ("GParamEnum", &pspec_info);
     g_assert (type == G_TYPE_PARAM_ENUM);
   }
   
   /* G_TYPE_PARAM_FLAGS
    */
   {
-    static const ParamSpecClassInfo class_info = {
+    static const GParamSpecTypeInfo pspec_info = {
+      sizeof (GParamSpecFlags), /* instance_size */
+      16,                       /* n_preallocs */
+      param_spec_flags_init,    /* instance_init */
       G_TYPE_FLAGS,            /* value_type */
       param_spec_flags_finalize,/* finalize */
       param_flags_set_default, /* value_set_default */
       param_flags_validate,    /* value_validate */
       param_ulong_values_cmp,  /* values_cmp */
     };
-    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);
+    type = g_param_type_register_static ("GParamFlags", &pspec_info);
     g_assert (type == G_TYPE_PARAM_FLAGS);
   }
   
   /* G_TYPE_PARAM_FLOAT
    */
   {
-    static const ParamSpecClassInfo class_info = {
+    static const GParamSpecTypeInfo pspec_info = {
+      sizeof (GParamSpecFloat), /* instance_size */
+      16,                       /* n_preallocs */
+      param_spec_float_init,    /* instance_init */
       G_TYPE_FLOAT,            /* value_type */
       NULL,                    /* finalize */
       param_float_set_default, /* value_set_default */
       param_float_validate,    /* value_validate */
       param_float_values_cmp,  /* values_cmp */
     };
-    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);
+    type = g_param_type_register_static ("GParamFloat", &pspec_info);
     g_assert (type == G_TYPE_PARAM_FLOAT);
   }
   
   /* G_TYPE_PARAM_DOUBLE
    */
   {
-    static const ParamSpecClassInfo class_info = {
-      G_TYPE_DOUBLE,           /* value_type */
-      NULL,                    /* finalize */
-      param_double_set_default,        /* value_set_default */
-      param_double_validate,   /* value_validate */
-      param_double_values_cmp, /* values_cmp */
+    static const GParamSpecTypeInfo pspec_info = {
+      sizeof (GParamSpecDouble), /* instance_size */
+      16,                        /* n_preallocs */
+      param_spec_double_init,    /* instance_init */
+      G_TYPE_DOUBLE,            /* value_type */
+      NULL,                     /* finalize */
+      param_double_set_default,         /* value_set_default */
+      param_double_validate,    /* value_validate */
+      param_double_values_cmp,  /* values_cmp */
     };
-    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);
+    type = g_param_type_register_static ("GParamDouble", &pspec_info);
     g_assert (type == G_TYPE_PARAM_DOUBLE);
   }
   
   /* G_TYPE_PARAM_STRING
    */
   {
-    static const ParamSpecClassInfo class_info = {
+    static const GParamSpecTypeInfo pspec_info = {
+      sizeof (GParamSpecString),  /* instance_size */
+      16,                        /* n_preallocs */
+      param_spec_string_init,    /* instance_init */
       G_TYPE_STRING,             /* value_type */
       param_spec_string_finalize, /* finalize */
       param_string_set_default,          /* value_set_default */
       param_string_validate,     /* value_validate */
       param_string_values_cmp,   /* values_cmp */
     };
-    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);
+    type = g_param_type_register_static ("GParamString", &pspec_info);
     g_assert (type == G_TYPE_PARAM_STRING);
   }
   
   /* G_TYPE_PARAM_OBJECT
    */
   {
-    static const ParamSpecClassInfo class_info = {
-      G_TYPE_OBJECT,           /* value_type */
-      NULL,                    /* finalize */
-      param_object_set_default,        /* value_set_default */
-      param_object_validate,   /* value_validate */
-      param_object_values_cmp, /* values_cmp */
+    static const GParamSpecTypeInfo pspec_info = {
+      sizeof (GParamSpecObject), /* instance_size */
+      16,                        /* n_preallocs */
+      param_spec_object_init,    /* instance_init */
+      G_TYPE_OBJECT,            /* value_type */
+      NULL,                     /* finalize */
+      param_object_set_default,         /* value_set_default */
+      param_object_validate,    /* value_validate */
+      param_object_values_cmp,  /* values_cmp */
     };
-    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);
+    type = g_param_type_register_static ("GParamObject", &pspec_info);
     g_assert (type == G_TYPE_PARAM_OBJECT);
   }
   
diff --git a/gobject/gsignal.c b/gobject/gsignal.c
new file mode 100644 (file)
index 0000000..5006ebf
--- /dev/null
@@ -0,0 +1,1335 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 2000 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.
+ *
+ * this code is based on the original GtkSignal implementation
+ * for the Gtk+ library by Peter Mattis <petm@xcf.berkeley.edu>
+ */
+#include        "gsignal.h"
+
+#include        "gbsearcharray.h"
+
+
+/* pre allocation configurations
+ */
+#define BSA_PRE_ALLOC           (20)
+#define HANDLER_PRE_ALLOC       (48)
+#define EMISSION_PRE_ALLOC      (16)
+
+#define TIGHT_MEMORY    (1)
+
+#define REPORT_BUG      "please report occourance circumstances to gtk-devel-list@gnome.org"
+
+
+/* --- generic allocation --- */
+/* we can special case allocations generically by replacing
+ * these functions with more speed/memory aware variants
+ */
+static inline gpointer
+g_generic_node_alloc (GTrashStack **trash_stack_p,
+                      guint         sizeof_node,
+                      guint         nodes_pre_alloc)
+{
+  gpointer node = g_trash_stack_pop (trash_stack_p);
+  
+  if (!node)
+    {
+      guint8 *block;
+      
+      nodes_pre_alloc = MAX (nodes_pre_alloc, 1);
+      block = g_malloc (sizeof_node * nodes_pre_alloc);
+      while (--nodes_pre_alloc)
+        {
+          g_trash_stack_push (trash_stack_p, block);
+          block += sizeof_node;
+        }
+      node = block;
+    }
+  
+  return node;
+}
+static inline void
+g_generic_node_free (GTrashStack **trash_stack_p,
+                     gpointer      node)
+{
+  g_trash_stack_push (trash_stack_p, node);
+}
+
+
+/* --- typedefs --- */
+typedef struct _SignalNode  SignalNode;
+typedef struct _SignalKey   SignalKey;
+typedef struct _Emission    Emission;
+typedef struct _Handler     Handler;
+typedef struct _HandlerList HandlerList;
+typedef enum
+{
+  EMISSION_STOP,
+  EMISSION_RUN,
+  EMISSION_HOOK,
+  EMISSION_RESTART
+} EmissionState;
+
+
+/* --- prototypes --- */
+static inline guint             signal_id_lookup      (GQuark           quark,
+                                                      GType            itype);
+static        void              signal_destroy_R      (SignalNode      *signal_node);
+static inline HandlerList*      handler_list_ensure   (guint            signal_id,
+                                                      gpointer         instance);
+static inline HandlerList*      handler_list_lookup   (guint            signal_id,
+                                                      gpointer         instance);
+static inline Handler*          handler_new           (gboolean         after);
+static        void              handler_insert        (guint            signal_id,
+                                                      gpointer         instance,
+                                                      Handler         *handler);
+static        Handler*          handler_lookup        (gpointer         instance,
+                                                      guint            handler_id,
+                                                      guint           *signal_id_p);
+static        Handler*          handler_find          (gpointer         instance,
+                                                      GSignalMatchType mask,
+                                                      guint            signal_id,
+                                                      GClosure        *closure,
+                                                      gpointer         func,
+                                                      gpointer         data);
+static inline void              handler_ref           (Handler         *handler);
+static inline void              handler_unref_R       (guint            signal_id,
+                                                      gpointer         instance,
+                                                      Handler         *handler);
+static inline void              emission_push         (Emission       **emission_list_p,
+                                                      guint            signal_id,
+                                                      gpointer         instance,
+                                                      EmissionState   *state_p);
+static inline void              emission_pop          (Emission       **emission_list_p);
+static inline Emission*         emission_find         (Emission        *emission_list,
+                                                      guint            signal_id,
+                                                      gpointer         instance);
+static       void              signal_emit_R         (SignalNode      *node,
+                                                      gpointer         instance,
+                                                      GValue          *return_value,
+                                                      const GValue    *instance_and_params);
+
+
+/* --- structures --- */
+struct _SignalNode
+{
+  /* permanent portion */
+  guint              signal_id;
+  GType              itype;
+  gchar             *name;
+  guint              destroyed : 1;
+  
+  /* reinitializable portion */
+  guint              flags : 8;
+  guint              n_params : 8;
+  GType                    *param_types;
+  GType                     return_type;
+  GClosure          *class_closure;
+  GSignalAccumulator accumulator;
+  GSignalCMarshaller c_marshaller;
+  GHookList         *emission_hooks;
+};
+
+struct _SignalKey
+{
+  GType  itype;
+  GQuark quark;
+  guint  signal_id;
+};
+
+struct _Emission
+{
+  Emission      *next;
+  guint          signal_id;
+  gpointer       instance;
+  EmissionState *state_p;
+};
+
+struct _HandlerList
+{
+  guint    signal_id;
+  Handler *handlers;
+};
+
+struct _Handler
+{
+  guint         id;
+  Handler      *next;
+  Handler      *prev;
+  guint         ref_count : 16;
+#define HANDLER_MAX_REF_COUNT   (1 << 16)
+  guint         block_count : 12;
+#define HANDLER_MAX_BLOCK_COUNT (1 << 12)
+  guint         after : 1;
+  GClosure     *closure;
+};
+
+
+/* --- variables --- */
+static GBSearchArray  g_signal_key_bsa = { NULL, 0, 0, 0, NULL };
+static GHashTable    *g_handler_list_bsa_ht = NULL;
+static Emission      *g_recursive_emissions = NULL;
+static Emission      *g_restart_emissions = NULL;
+static GTrashStack   *g_bsa_ts = NULL;
+static GTrashStack   *g_handler_ts = NULL;
+static GTrashStack   *g_emission_ts = NULL;
+G_LOCK_DEFINE_STATIC (g_signal_mutex);
+
+
+/* --- signal nodes --- */
+static guint          g_n_signal_nodes = 0;
+static SignalNode   **g_signal_nodes = NULL;
+
+static inline SignalNode*
+LOOKUP_SIGNAL_NODE (register guint signal_id)
+{
+  if (signal_id < g_n_signal_nodes)
+    return g_signal_nodes[signal_id];
+  else
+    return NULL;
+}
+
+
+/* --- functions --- */
+static inline guint
+signal_id_lookup (GQuark quark,
+                 GType  itype)
+{
+  SignalKey key, *signal_key;
+  
+  key.itype = itype;
+  key.quark = quark;
+  
+  signal_key = g_bsearch_array_lookup (&g_signal_key_bsa, &key);
+  
+  return signal_key ? signal_key->signal_id : 0;
+}
+
+static gint
+handler_lists_cmp (gconstpointer node1,
+                   gconstpointer node2)
+{
+  const HandlerList *hlist1 = node1, *hlist2 = node2;
+  
+  return G_BSEARCH_ARRAY_CMP (hlist1->signal_id, hlist2->signal_id);
+}
+
+static inline HandlerList*
+handler_list_ensure (guint    signal_id,
+                    gpointer instance)
+{
+  GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
+  HandlerList key;
+  
+  if (!hlbsa)
+    {
+      hlbsa = g_generic_node_alloc (&g_bsa_ts,
+                                    sizeof (GBSearchArray),
+                                    BSA_PRE_ALLOC);
+      hlbsa->cmp_func = handler_lists_cmp;
+      hlbsa->sizeof_node = sizeof (HandlerList);
+      hlbsa->flags = G_BSEARCH_DEFER_SHRINK;
+      hlbsa->n_nodes = 0;
+      hlbsa->nodes = NULL;
+      g_hash_table_insert (g_handler_list_bsa_ht, instance, hlbsa);
+    }
+  key.signal_id = signal_id;
+  key.handlers = NULL;
+  
+  return g_bsearch_array_insert (hlbsa, &key, FALSE);
+}
+
+static inline HandlerList*
+handler_list_lookup (guint    signal_id,
+                    gpointer instance)
+{
+  GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
+  HandlerList key;
+  
+  key.signal_id = signal_id;
+  
+  return hlbsa ? g_bsearch_array_lookup (hlbsa, &key) : NULL;
+}
+
+static Handler*
+handler_lookup (gpointer instance,
+               guint    handler_id,
+               guint   *signal_id_p)
+{
+  GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
+  
+  if (hlbsa)
+    {
+      guint i;
+      
+      for (i = 0; i < hlbsa->n_nodes; i++)
+        {
+          HandlerList *hlist = g_bsearch_array_get_nth (hlbsa, i);
+          Handler *handler;
+          
+          for (handler = hlist->handlers; handler; handler = handler->next)
+            if (handler->id == handler_id)
+              {
+                if (signal_id_p)
+                  *signal_id_p = hlist->signal_id;
+               
+                return handler;
+              }
+        }
+    }
+  
+  return NULL;
+}
+
+static Handler*
+handler_find (gpointer         instance,
+             GSignalMatchType mask,
+             guint            signal_id,
+             GClosure        *closure,
+             gpointer         func,
+             gpointer         data)
+{
+  if (mask & G_SIGNAL_MATCH_ID)
+    {
+      HandlerList *hlist = handler_list_lookup (signal_id, instance);
+      Handler *handler;
+      SignalNode *node;
+      
+      if (mask & G_SIGNAL_MATCH_FUNC)
+       {
+         node = LOOKUP_SIGNAL_NODE (signal_id);
+         if (!node || !node->c_marshaller)
+           return NULL;
+       }
+         
+      mask = ~mask;
+      for (handler = hlist ? hlist->handlers : NULL; handler; handler = handler->next)
+        if (((mask & G_SIGNAL_MATCH_CLOSURE) || handler->closure == closure) &&
+           ((mask & G_SIGNAL_MATCH_UNBLOCKED) || handler->block_count == 0) &&
+            ((mask & G_SIGNAL_MATCH_DATA) || handler->closure->data == data) &&
+           ((mask & G_SIGNAL_MATCH_FUNC) || (handler->closure->marshal == node->c_marshaller &&
+                                             handler->closure->meta_marshal == 0 &&
+                                             ((GCClosure*) handler->closure)->callback == func)))
+          return handler;
+    }
+  else
+    {
+      GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
+      
+      mask = ~mask;
+      if (hlbsa)
+        {
+          guint i;
+          
+          for (i = 0; i < hlbsa->n_nodes; i++)
+            {
+              HandlerList *hlist = g_bsearch_array_get_nth (hlbsa, i);
+             SignalNode *node;
+              Handler *handler;
+              
+             if (!(mask & G_SIGNAL_MATCH_FUNC))
+               {
+                 node = LOOKUP_SIGNAL_NODE (hlist->signal_id);
+                 if (!node->c_marshaller)
+                   continue;
+               }
+
+              for (handler = hlist->handlers; handler; handler = handler->next)
+                if (((mask & G_SIGNAL_MATCH_CLOSURE) || handler->closure == closure) &&
+                   ((mask & G_SIGNAL_MATCH_UNBLOCKED) || handler->block_count == 0) &&
+                    ((mask & G_SIGNAL_MATCH_DATA) || handler->closure->data == data) &&
+                   ((mask & G_SIGNAL_MATCH_FUNC) || (handler->closure->marshal == node->c_marshaller &&
+                                                     handler->closure->meta_marshal == 0 &&
+                                                     ((GCClosure*) handler->closure)->callback == func)))
+                  return handler;
+            }
+        }
+    }
+  
+  return NULL;
+}
+
+static inline Handler*
+handler_new (gboolean after)
+{
+  static guint handler_id = 1;
+  Handler *handler = g_generic_node_alloc (&g_handler_ts,
+                                           sizeof (Handler),
+                                           HANDLER_PRE_ALLOC);
+#ifndef G_DISABLE_CHECKS
+  if (handler_id == 0)
+    g_error (G_STRLOC ": handler id overflow, %s", REPORT_BUG);
+#endif
+  
+  handler->id = handler_id++;
+  handler->prev = NULL;
+  handler->next = NULL;
+  handler->ref_count = 1;
+  handler->block_count = 0;
+  handler->after = after != FALSE;
+  handler->closure = NULL;
+  
+  return handler;
+}
+
+static inline void
+handler_ref (Handler *handler)
+{
+  g_return_if_fail (handler->ref_count > 0);
+  
+#ifndef G_DISABLE_CHECKS
+  if (handler->ref_count >= HANDLER_MAX_REF_COUNT - 1)
+    g_error (G_STRLOC ": handler ref_count overflow, %s", REPORT_BUG);
+#endif
+  
+  handler->ref_count += 1;
+}
+
+static inline void
+handler_unref_R (guint    signal_id,
+                gpointer instance,
+                Handler *handler)
+{
+  g_return_if_fail (handler->ref_count > 0);
+  
+  handler->ref_count -= 1;
+  if (!handler->ref_count)
+    {
+      if (handler->next)
+        handler->next->prev = handler->prev;
+      if (handler->prev)       /* watch out for g_signal_handlers_destroy()! */
+        handler->prev->next = handler->next;
+      else
+        {
+          HandlerList *hlist = handler_list_lookup (signal_id, instance);
+          
+          hlist->handlers = handler->next;
+        }
+      G_UNLOCK (g_signal_mutex);
+      g_closure_unref (handler->closure);
+      G_LOCK (g_signal_mutex);
+      g_generic_node_free (&g_handler_ts, handler);
+    }
+}
+
+static void
+handler_insert (guint    signal_id,
+               gpointer instance,
+               Handler  *handler)
+{
+  HandlerList *hlist;
+  
+  g_assert (handler->prev == NULL && handler->next == NULL); // FIXME: paranoid
+  
+  hlist = handler_list_ensure (signal_id, instance);
+  if (!hlist->handlers)
+    hlist->handlers = handler;
+  else if (hlist->handlers->after && !handler->after)
+    {
+      handler->next = hlist->handlers;
+      hlist->handlers->prev = handler;
+      hlist->handlers = handler;
+    }
+  else
+    {
+      Handler *tmp = hlist->handlers;
+      
+      if (handler->after)
+        while (tmp->next)
+          tmp = tmp->next;
+      else
+        while (tmp->next && !tmp->next->after)
+          tmp = tmp->next;
+      if (tmp->next)
+        tmp->next->prev = handler;
+      handler->next = tmp->next;
+      handler->prev = tmp;
+      tmp->next = handler;
+    }
+}
+
+static inline void
+emission_push (Emission     **emission_list_p,
+              guint          signal_id,
+              gpointer       instance,
+              EmissionState *state_p)
+{
+  Emission *emission = g_generic_node_alloc (&g_emission_ts,
+                                             sizeof (Emission),
+                                             EMISSION_PRE_ALLOC);
+  emission->next = *emission_list_p;
+  emission->signal_id = signal_id;
+  emission->instance = instance;
+  emission->state_p = state_p;
+  *emission_list_p = emission;
+}
+
+static inline void
+emission_pop (Emission **emission_list_p)
+{
+  Emission *emission = *emission_list_p;
+  
+  *emission_list_p = emission->next;
+  g_generic_node_free (&g_emission_ts, emission);
+}
+
+static inline Emission*
+emission_find (Emission *emission_list,
+              guint     signal_id,
+              gpointer  instance)
+{
+  Emission *emission;
+  
+  for (emission = emission_list; emission; emission = emission->next)
+    if (emission->instance == instance && emission->signal_id == signal_id)
+      return emission;
+  return NULL;
+}
+
+static gint
+signal_key_cmp (gconstpointer node1,
+                gconstpointer node2)
+{
+  const SignalKey *key1 = node1, *key2 = node2;
+  
+  if (key1->itype == key2->itype)
+    return G_BSEARCH_ARRAY_CMP (key1->quark, key2->quark);
+  else
+    return G_BSEARCH_ARRAY_CMP (key1->itype, key2->itype);
+}
+
+void
+g_signal_init (void) /* sync with gtype.c */
+{
+  G_LOCK (g_signal_mutex);
+  if (!g_n_signal_nodes)
+    {
+      /* setup signal key array */
+      g_signal_key_bsa.cmp_func = signal_key_cmp;
+      g_signal_key_bsa.sizeof_node = sizeof (SignalKey);
+      g_signal_key_bsa.flags = 0; /* alloc-only */
+      
+      /* setup handler list binary searchable array hash table (in german, that'd be one word ;) */
+      g_handler_list_bsa_ht = g_hash_table_new (g_direct_hash, NULL);
+      
+      /* invalid (0) signal_id */
+      g_n_signal_nodes = 1;
+      g_signal_nodes = g_renew (SignalNode*, g_signal_nodes, g_n_signal_nodes);
+      g_signal_nodes[0] = NULL;
+    }
+  G_UNLOCK (g_signal_mutex);
+}
+
+void
+g_signals_destroy (GType itype)
+{
+  guint i;
+  gboolean found_one = FALSE;
+  
+  G_LOCK (g_signal_mutex);
+  for (i = 0; i < g_n_signal_nodes; i++)
+    {
+      SignalNode *node = g_signal_nodes[i];
+      
+      if (node->itype == itype)
+        {
+          if (node->destroyed)
+            g_warning (G_STRLOC ": signal \"%s\" of type `%s' already destroyed",
+                       node->name,
+                       g_type_name (node->itype));
+          else
+            {
+              found_one = TRUE;
+              signal_destroy_R (node);
+            }
+        }
+    }
+  if (!found_one)
+    g_warning (G_STRLOC ": type `%s' has no signals that could be destroyed",
+               g_type_name (itype));
+  G_UNLOCK (g_signal_mutex);
+}
+
+void
+g_signal_stop_emission (gpointer instance,
+                        guint    signal_id)
+{
+  SignalNode *node;
+  
+  g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
+  g_return_if_fail (signal_id > 0);
+  
+  G_LOCK (g_signal_mutex);
+  node = LOOKUP_SIGNAL_NODE (signal_id);
+  if (node && g_type_conforms_to (G_TYPE_FROM_INSTANCE (instance), node->itype))
+    {
+      Emission *emission_list = node->flags & G_SIGNAL_NO_RECURSE ? g_restart_emissions : g_recursive_emissions;
+      Emission *emission = emission_find (emission_list, signal_id, instance);
+      
+      if (emission)
+        {
+          if (*emission->state_p == EMISSION_HOOK)
+            g_warning (G_STRLOC ": emission of signal \"%s\" for instance `%p' cannot be stopped from emission hook",
+                       node->name, instance);
+          else if (*emission->state_p == EMISSION_RUN)
+            *emission->state_p = EMISSION_STOP;
+        }
+      else
+        g_warning (G_STRLOC ": no emission of signal \"%s\" to stop for instance `%p'",
+                   node->name, instance);
+    }
+  else
+    g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance);
+  G_UNLOCK (g_signal_mutex);
+}
+
+guint
+g_signal_lookup (const gchar *name,
+                 GType        itype)
+{
+  GQuark quark;
+
+  g_return_val_if_fail (name != NULL, 0);
+  g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), 0);
+  
+  G_LOCK (g_signal_mutex);
+  quark = g_quark_try_string (name);
+  if (quark)
+    do
+      {
+       guint signal_id = signal_id_lookup (quark, itype);
+
+       if (signal_id)
+         return signal_id;
+
+       itype = g_type_parent (itype);
+      }
+    while (itype);
+  G_UNLOCK (g_signal_mutex);
+  
+  return 0;
+}
+
+gchar*
+g_signal_name (guint signal_id)
+{
+  SignalNode *node;
+  gchar *name;
+
+  G_LOCK (g_signal_mutex);
+  node = LOOKUP_SIGNAL_NODE (signal_id);
+  name = node ? node->name : NULL;
+  G_UNLOCK (g_signal_mutex);
+  
+  return name;
+}
+
+void
+g_signal_query (guint         signal_id,
+               GSignalQuery *query)
+{
+  SignalNode *node;
+
+  g_return_if_fail (query != NULL);
+
+  G_LOCK (g_signal_mutex);
+  node = LOOKUP_SIGNAL_NODE (signal_id);
+  if (!node || node->destroyed)
+    query->signal_id = 0;
+  else
+    {
+      query->signal_id = node->signal_id;
+      query->signal_name = node->name;
+      query->itype = node->itype;
+      query->signal_flags = node->flags;
+      query->return_type = node->return_type;
+      query->n_params = node->n_params;
+      query->param_types = node->param_types;
+    }
+  G_UNLOCK (g_signal_mutex);
+}
+
+guint
+g_signal_newv (const gchar       *signal_name,
+               GType              itype,
+               GSignalType        signal_flags,
+               GClosure          *class_closure,
+               GSignalAccumulator accumulator,
+               GSignalCMarshaller c_marshaller,
+               GType             return_type,
+               guint              n_params,
+               GType            *param_types)
+{
+  gchar *name;
+  guint signal_id, i;
+  SignalNode *node;
+  
+  g_return_val_if_fail (signal_name != NULL, 0);
+  g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), 0);
+  if (n_params)
+    g_return_val_if_fail (param_types != NULL, 0);
+  if (return_type != G_TYPE_NONE)
+    g_return_val_if_fail (accumulator == NULL, 0);
+  
+  name = g_strdup (signal_name);
+  g_strdelimit (name, G_STR_DELIMITERS ":^", '_');  // FIXME do character checks like for types
+  
+  G_LOCK (g_signal_mutex);
+  
+  signal_id = g_signal_lookup (name, itype);
+  node = LOOKUP_SIGNAL_NODE (signal_id);
+  if (node && !node->destroyed)
+    {
+      g_warning (G_STRLOC ": signal \"%s\" already exists in the `%s' %s",
+                 name,
+                 g_type_name (node->itype),
+                 G_TYPE_IS_INTERFACE (node->itype) ? "interface" : "class ancestry");
+      g_free (name);
+      G_UNLOCK (g_signal_mutex);
+      return 0;
+    }
+  if (node && node->itype != itype)
+    {
+      g_warning (G_STRLOC ": signal \"%s\" for type `%s' was previously created for type `%s'",
+                 name,
+                 g_type_name (itype),
+                 g_type_name (node->itype));
+      g_free (name);
+      G_UNLOCK (g_signal_mutex);
+      return 0;
+    }
+  for (i = 0; i < n_params; i++)
+    if (!G_TYPE_IS_VALUE (param_types[i]) ||
+       param_types[i] == G_TYPE_ENUM || param_types[i] == G_TYPE_FLAGS) /* FIXME: kludge */
+      {
+       g_warning (G_STRLOC ": parameter %d of type `%s' for signal \"%s::%s\" is not a value type",
+                  i + 1, g_type_name (param_types[i]), g_type_name (itype), name);
+       g_free (name);
+       G_UNLOCK (g_signal_mutex);
+       return 0;
+      }
+  if (return_type != G_TYPE_NONE && !G_TYPE_IS_VALUE (return_type))
+    {
+      g_warning (G_STRLOC ": return value of type `%s' for signal \"%s::%s\" is not a value type",
+                g_type_name (param_types[i]), g_type_name (itype), name);
+      g_free (name);
+      G_UNLOCK (g_signal_mutex);
+      return 0;
+    }
+  
+  /* setup permanent portion of signal node */
+  if (!node)
+    {
+      SignalKey key;
+      
+      signal_id = g_n_signal_nodes++;
+      node = g_new (SignalNode, 1);
+      node->signal_id = signal_id;
+      g_signal_nodes = g_renew (SignalNode*, g_signal_nodes, g_n_signal_nodes);
+      g_signal_nodes[signal_id] = node;
+      node->itype = itype;
+      node->name = name;
+      key.itype = itype;
+      key.quark = g_quark_from_string (node->name);
+      key.signal_id = signal_id;
+      g_bsearch_array_insert (&g_signal_key_bsa, &key, FALSE);
+      g_strdelimit (node->name, "_", '-');
+      key.quark = g_quark_from_static_string (node->name);
+      g_bsearch_array_insert (&g_signal_key_bsa, &key, FALSE);
+    }
+  node->destroyed = FALSE;
+  
+  /* setup reinitializable portion */
+  node->flags = signal_flags & (G_SIGNAL_RUN_FIRST |
+                                G_SIGNAL_RUN_LAST |
+                               G_SIGNAL_RUN_CLEANUP |
+                                G_SIGNAL_NO_RECURSE |
+                                G_SIGNAL_ACTION |
+                                G_SIGNAL_NO_HOOKS);
+  node->n_params = n_params;
+  node->param_types = g_memdup (param_types, sizeof (GType) * n_params);
+  node->return_type = return_type;
+  node->class_closure = class_closure ? g_closure_ref (class_closure) : NULL;
+  node->accumulator = accumulator;
+  node->c_marshaller = c_marshaller;
+  node->emission_hooks = NULL;
+  if (node->c_marshaller && class_closure && G_CLOSURE_NEEDS_MARSHAL (class_closure))
+    g_closure_set_marshal (class_closure, node->c_marshaller);
+  
+  G_UNLOCK (g_signal_mutex);
+  return signal_id;
+}
+
+static void
+signal_destroy_R (SignalNode *signal_node)
+{
+  SignalNode node = *signal_node;
+  
+  signal_node->destroyed = TRUE;
+  
+  /* reentrancy caution, zero out real contents first */
+  signal_node->n_params = 0;
+  signal_node->param_types = NULL;
+  signal_node->return_type = 0;
+  signal_node->class_closure = NULL;
+  signal_node->accumulator = NULL;
+  signal_node->c_marshaller = NULL;
+  signal_node->emission_hooks = NULL;
+  
+#ifndef G_DISABLE_CHECKS
+  /* check current emissions */
+  {
+    Emission *emission;
+    
+    for (emission = (node.flags & G_SIGNAL_NO_RECURSE) ? g_restart_emissions : g_recursive_emissions;
+         emission; emission = emission->next)
+      if (emission->signal_id == node.signal_id)
+        g_critical (G_STRLOC ": signal \"%s\" being destroyed is currently in emission (instance `%p')",
+                    node.name, emission->instance);
+  }
+#endif
+  
+  /* free contents that need to
+   */
+  G_UNLOCK (g_signal_mutex);
+  g_free (node.param_types);
+  g_closure_unref (node.class_closure);
+  if (node.emission_hooks)
+    {
+      g_hook_list_clear (node.emission_hooks);
+      g_free (node.emission_hooks);
+    }
+  G_LOCK (g_signal_mutex);
+}
+
+guint
+g_signal_connect_closure (gpointer  instance,
+                         guint     signal_id,
+                         GClosure *closure,
+                         gboolean  after)
+{
+  SignalNode *node;
+  guint handler_id = 0;
+  
+  g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
+  g_return_val_if_fail (signal_id > 0, 0);
+  g_return_val_if_fail (closure != NULL, 0);
+  
+  G_LOCK (g_signal_mutex);
+  node = LOOKUP_SIGNAL_NODE (signal_id);
+  if (node && g_type_conforms_to (G_TYPE_FROM_INSTANCE (instance), node->itype))
+    {
+      Handler *handler = handler_new (after);
+      
+      handler_id = handler->id;
+      handler->closure = g_closure_ref (closure);
+      handler_insert (signal_id, instance, handler);
+      if (node->c_marshaller && G_CLOSURE_NEEDS_MARSHAL (closure))
+       g_closure_set_marshal (closure, node->c_marshaller);
+    }
+  else
+    g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance);
+  G_UNLOCK (g_signal_mutex);
+  
+  return handler_id;
+}
+
+void
+g_signal_handler_disconnect (gpointer instance,
+                             guint    handler_id)
+{
+  Handler *handler;
+  guint signal_id;
+  
+  g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
+  g_return_if_fail (handler_id > 0);
+  
+  G_LOCK (g_signal_mutex);
+  handler = handler_lookup (instance, handler_id, &signal_id);
+  if (handler)
+    {
+      handler->id = 0;
+      handler->block_count = 1;
+      handler_unref_R (signal_id, instance, handler);
+    }
+  else
+    g_warning ("%s: instance `%p' has no handler with id `%u'", G_STRLOC, instance, handler_id);
+  G_UNLOCK (g_signal_mutex);
+}
+
+void
+g_signal_handlers_destroy (gpointer instance)
+{
+  GBSearchArray *hlbsa;
+  
+  g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
+  
+  G_LOCK (g_signal_mutex);
+  hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
+  if (hlbsa)
+    {
+      guint i;
+      
+      /* reentrancy caution, delete instance trace first */
+      g_hash_table_remove (g_handler_list_bsa_ht, instance);
+
+      for (i = 0; i < hlbsa->n_nodes; i++)
+        {
+          HandlerList *hlist = g_bsearch_array_get_nth (hlbsa, i);
+          Handler *handler = hlist->handlers;
+         
+          while (handler)
+            {
+              Handler *tmp = handler;
+             
+              handler = tmp->next;
+              tmp->block_count = 1;
+              /* cruel unlink, this works because _all_ handlers vanish */
+              tmp->next = NULL;
+              tmp->prev = tmp;
+              if (tmp->id)
+               {
+                 tmp->id = 0;
+                 handler_unref_R (0, NULL, tmp);
+               }
+            }
+        }
+      g_free (hlbsa->nodes);
+      g_generic_node_free (&g_bsa_ts, hlbsa);
+    }
+  G_UNLOCK (g_signal_mutex);
+}
+
+void
+g_signal_handler_block (gpointer instance,
+                        guint    handler_id)
+{
+  Handler *handler;
+  
+  g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
+  g_return_if_fail (handler_id > 0);
+  
+  G_LOCK (g_signal_mutex);
+  handler = handler_lookup (instance, handler_id, NULL);
+  if (handler)
+    {
+#ifndef G_DISABLE_CHECKS
+      if (handler->block_count >= HANDLER_MAX_BLOCK_COUNT - 1)
+        g_error (G_STRLOC ": handler block_count overflow, %s", REPORT_BUG);
+#endif
+      
+      handler->block_count += 1;
+    }
+  else
+    g_warning ("%s: instance `%p' has no handler with id `%u'", G_STRLOC, instance, handler_id);
+  G_UNLOCK (g_signal_mutex);
+}
+
+void
+g_signal_handler_unblock (gpointer instance,
+                          guint    handler_id)
+{
+  Handler *handler;
+  
+  g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
+  g_return_if_fail (handler_id > 0);
+  
+  G_LOCK (g_signal_mutex);
+  handler = handler_lookup (instance, handler_id, NULL);
+  if (handler)
+    {
+      if (handler->block_count)
+        handler->block_count -= 1;
+      else
+        g_warning (G_STRLOC ": handler `%u' of instance `%p' is not blocked", handler_id, instance);
+    }
+  else
+    g_warning ("%s: instance `%p' has no handler with id `%u'", G_STRLOC, instance, handler_id);
+  G_UNLOCK (g_signal_mutex);
+}
+
+guint
+g_signal_handler_find (gpointer         instance,
+                       GSignalMatchType mask,
+                       guint            signal_id,
+                       GClosure        *closure,
+                       gpointer         func,
+                       gpointer         data)
+{
+  Handler *handler = NULL;
+  guint handler_id;
+  
+  g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
+  
+  G_LOCK (g_signal_mutex);
+  handler = handler_find (instance, mask, signal_id, closure, func, data);
+  handler_id = handler ? handler->id : 0;
+  G_UNLOCK (g_signal_mutex);
+  
+  return handler_id;
+}
+
+gboolean
+g_signal_handler_pending (gpointer instance,
+                          guint    signal_id,
+                          gboolean may_be_blocked)
+{
+  Handler *handler = NULL;
+  
+  g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), FALSE);
+  g_return_val_if_fail (signal_id > 0, FALSE);
+  
+  G_LOCK (g_signal_mutex);
+  handler = handler_find (instance, G_SIGNAL_MATCH_ID, signal_id, NULL, NULL, NULL);
+  if (!may_be_blocked)
+    for (; handler; handler = handler->next)
+      if (!handler->block_count)
+        break;
+  G_UNLOCK (g_signal_mutex);
+  
+  return handler != NULL;
+}
+
+void
+g_signal_emitv (const GValue *instance_and_params,
+               guint         signal_id,
+               GValue       *return_value)
+{
+  SignalNode *node;
+  gpointer instance;
+  const GValue *param_values;
+  guint i;
+  
+  g_return_if_fail (instance_and_params != NULL);
+  instance = g_value_get_as_pointer (instance_and_params);
+  g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
+  g_return_if_fail (signal_id > 0);
+
+  param_values = instance_and_params + 1;
+  
+  G_LOCK (g_signal_mutex);
+  node = LOOKUP_SIGNAL_NODE (signal_id);
+#ifndef G_DISABLE_CHECKS
+  if (!node || !g_type_conforms_to (G_TYPE_FROM_INSTANCE (instance), node->itype))
+    g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance);
+  for (i = 0; i < node->n_params; i++)
+    if (!G_VALUE_HOLDS (param_values + i, node->param_types[i]))
+      {
+       g_critical (G_STRLOC ": value for `%s' parameter %u for signal \"%s\" is of type `%s'",
+                   g_type_name (node->param_types[i]),
+                   i,
+                   node->name,
+                   G_VALUE_TYPE_NAME (param_values + i));
+       G_UNLOCK (g_signal_mutex);
+       return;
+      }
+  if (node->return_type != G_TYPE_NONE)
+    {
+      if (!return_value)
+       {
+         g_critical (G_STRLOC ": return value `%s' for signal \"%s\" is (NULL)",
+                     g_type_name (node->return_type),
+                     node->name);
+         G_UNLOCK (g_signal_mutex);
+         return;
+       }
+      else if (!node->accumulator && !G_VALUE_HOLDS (return_value, node->return_type))
+       {
+         g_critical (G_STRLOC ": return value `%s' for signal \"%s\" is of type `%s'",
+                     g_type_name (node->return_type),
+                     node->name,
+                     G_VALUE_TYPE_NAME (return_value));
+         G_UNLOCK (g_signal_mutex);
+         return;
+       }
+    }
+  else
+    return_value = NULL;
+#endif /* !G_DISABLE_CHECKS */
+  
+  signal_emit_R (node, instance, return_value, instance_and_params);
+  
+  G_UNLOCK (g_signal_mutex);
+}
+
+static void
+signal_emit_R (SignalNode   *node,
+              gpointer      instance,
+              GValue       *return_value,
+              const GValue *instance_and_params)
+{
+  EmissionState emission_state = 0;
+  GSignalAccumulator accumulator;
+  GClosure *class_closure;
+  HandlerList *hlist;
+  Handler *handlers;
+  GValue accu;
+  gboolean accu_used = FALSE;
+  guint signal_id = node->signal_id;
+  
+  if (node->flags & G_SIGNAL_NO_RECURSE)
+    {
+      Emission *emission = emission_find (g_restart_emissions, signal_id, instance);
+      
+      if (emission)
+       {
+         *emission->state_p = EMISSION_RESTART;
+         return;
+       }
+    }
+  accumulator = node->accumulator;
+  if (accumulator)
+    {
+      G_UNLOCK (g_signal_mutex);
+      g_value_init (&accu, node->return_type);
+      G_LOCK (g_signal_mutex);
+    }
+  emission_push ((node->flags & G_SIGNAL_NO_RECURSE) ? &g_restart_emissions : &g_recursive_emissions,
+                signal_id, instance, &emission_state);
+  class_closure = node->class_closure;
+  hlist = handler_list_lookup (signal_id, instance);
+  handlers = hlist ? hlist->handlers : NULL;
+  if (handlers)
+    handler_ref (handlers);
+  
+ EMIT_RESTART:
+  
+  if ((node->flags & G_SIGNAL_RUN_FIRST) && class_closure)
+    {
+      emission_state = EMISSION_RUN;
+      
+      G_UNLOCK (g_signal_mutex);
+      if (accumulator)
+       {
+         if (accu_used)
+           g_value_reset (&accu);
+         g_closure_invoke (class_closure,
+                           (signal_id << 8) | G_SIGNAL_RUN_FIRST,
+                           &accu,
+                           node->n_params + 1,
+                           instance_and_params);
+         if (!accumulator (signal_id, return_value, &accu) &&
+             emission_state == EMISSION_RUN)
+           emission_state = EMISSION_STOP;
+         accu_used = TRUE;
+       }
+      else
+       g_closure_invoke (class_closure,
+                         (signal_id << 8) | G_SIGNAL_RUN_FIRST,
+                         return_value,
+                         node->n_params + 1,
+                         instance_and_params);
+      G_LOCK (g_signal_mutex);
+      
+      if (emission_state == EMISSION_STOP)
+       goto EMIT_CLEANUP;
+      else if (emission_state == EMISSION_RESTART)
+       goto EMIT_RESTART;
+    }
+  
+  if (node->emission_hooks)
+    {
+      emission_state = EMISSION_HOOK;
+      
+      G_UNLOCK (g_signal_mutex);
+      g_print ("emission_hooks()\n");
+      G_LOCK (g_signal_mutex);
+      
+      if (emission_state == EMISSION_RESTART)
+       goto EMIT_RESTART;
+    }
+  
+  if (handlers)
+    {
+      Handler *handler = handlers;
+      
+      emission_state = EMISSION_RUN;
+      
+      handler_ref (handler);
+      do
+       {
+         Handler *tmp;
+         
+         if (!handler->after && !handler->block_count)
+           {
+             G_UNLOCK (g_signal_mutex);
+             if (accumulator)
+               {
+                 if (accu_used)
+                   g_value_reset (&accu);
+                 g_closure_invoke (handler->closure,
+                                   (signal_id << 8) | G_SIGNAL_RUN_FIRST,
+                                   &accu,
+                                   node->n_params + 1,
+                                   instance_and_params);
+                 if (!accumulator (signal_id, return_value, &accu) &&
+                     emission_state == EMISSION_RUN)
+                   emission_state = EMISSION_STOP;
+                 accu_used = TRUE;
+               }
+             else
+               g_closure_invoke (handler->closure,
+                                 (signal_id << 8) | G_SIGNAL_RUN_FIRST,
+                                 return_value,
+                                 node->n_params + 1,
+                                 instance_and_params);
+             G_LOCK (g_signal_mutex);
+             
+             tmp = emission_state == EMISSION_RUN ? handler->next : NULL;
+           }
+         else
+           tmp = handler->next;
+         
+         if (tmp)
+           handler_ref (tmp);
+         handler_unref_R (signal_id, instance, handler);
+         handler = tmp;
+       }
+      while (handler);
+      
+      if (emission_state == EMISSION_STOP)
+       goto EMIT_CLEANUP;
+      else if (emission_state == EMISSION_RESTART)
+       goto EMIT_RESTART;
+    }
+  
+  if ((node->flags & G_SIGNAL_RUN_LAST) && class_closure)
+    {
+      emission_state = EMISSION_RUN;
+      
+      G_UNLOCK (g_signal_mutex);
+      if (accumulator)
+       {
+         if (accu_used)
+           g_value_reset (&accu);
+         g_closure_invoke (class_closure,
+                           (signal_id << 8) | G_SIGNAL_RUN_LAST,
+                           &accu,
+                           node->n_params + 1,
+                           instance_and_params);
+          if (!accumulator (signal_id, return_value, &accu) &&
+             emission_state == EMISSION_RUN)
+           emission_state = EMISSION_STOP;
+         accu_used = TRUE;
+       }
+      else
+       g_closure_invoke (class_closure,
+                         (signal_id << 8) | G_SIGNAL_RUN_LAST,
+                         return_value,
+                         node->n_params + 1,
+                         instance_and_params);
+      G_LOCK (g_signal_mutex);
+      
+      if (emission_state == EMISSION_STOP)
+       goto EMIT_CLEANUP;
+      else if (emission_state == EMISSION_RESTART)
+       goto EMIT_RESTART;
+    }
+  
+  if (handlers)
+    {
+      Handler *handler = handlers;
+      
+      emission_state = EMISSION_RUN;
+      
+      handler_ref (handler);
+      do
+       {
+         Handler *tmp;
+         
+         if (handler->after && !handler->block_count)
+           {
+             G_UNLOCK (g_signal_mutex);
+              if (accumulator)
+               {
+                 if (accu_used)
+                   g_value_reset (&accu);
+                 g_closure_invoke (handler->closure,
+                                   (signal_id << 8) | G_SIGNAL_RUN_LAST,
+                                   &accu,
+                                   node->n_params + 1,
+                                   instance_and_params);
+                 if (!accumulator (signal_id, return_value, &accu) &&
+                     emission_state == EMISSION_RUN)
+                   emission_state = EMISSION_STOP;
+                 accu_used = TRUE;
+               }
+             else
+               g_closure_invoke (handler->closure,
+                                 (signal_id << 8) | G_SIGNAL_RUN_LAST,
+                                 return_value,
+                                 node->n_params + 1,
+                                 instance_and_params);
+             G_LOCK (g_signal_mutex);
+             
+             tmp = emission_state == EMISSION_RUN ? handler->next : NULL;
+           }
+         else
+           tmp = handler->next;
+         
+         if (tmp)
+           handler_ref (tmp);
+         handler_unref_R (signal_id, instance, handler);
+         handler = tmp;
+       }
+      while (handler);
+      
+      if (emission_state == EMISSION_STOP)
+       goto EMIT_CLEANUP;
+      else if (emission_state == EMISSION_RESTART)
+       goto EMIT_RESTART;
+    }
+  
+ EMIT_CLEANUP:
+  
+  if ((node->flags & G_SIGNAL_RUN_CLEANUP) && class_closure)
+    {
+      emission_state = EMISSION_STOP;
+      
+      G_UNLOCK (g_signal_mutex);
+      if (node->return_type != G_TYPE_NONE)
+       {
+         if (!accumulator)
+           g_value_init (&accu, node->return_type);
+         else if (accu_used)
+           g_value_reset (&accu);
+         accu_used = TRUE;
+       }
+      g_closure_invoke (class_closure,
+                       (signal_id << 8) | G_SIGNAL_RUN_CLEANUP,
+                       node->return_type != G_TYPE_NONE ? &accu : NULL,
+                       node->n_params + 1,
+                       instance_and_params);
+      if (node->return_type != G_TYPE_NONE && !accumulator)
+       g_value_unset (&accu);
+      G_LOCK (g_signal_mutex);
+
+      if (emission_state == EMISSION_RESTART)
+       goto EMIT_RESTART;
+    }
+  
+  if (handlers)
+    handler_unref_R (signal_id, instance, handlers);
+  
+  emission_pop ((node->flags & G_SIGNAL_NO_RECURSE) ? &g_restart_emissions : &g_recursive_emissions);
+  if (accumulator)
+    {
+      G_UNLOCK (g_signal_mutex);
+      g_value_unset (&accu);
+      G_LOCK (g_signal_mutex);
+    }
+}
diff --git a/gobject/gsignal.h b/gobject/gsignal.h
new file mode 100644 (file)
index 0000000..f2be46f
--- /dev/null
@@ -0,0 +1,142 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 2000 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_SIGNAL_H__
+#define __G_SIGNAL_H__
+
+
+#include       <gobject/gclosure.h>
+#include       <gobject/gvalue.h>
+#include       <gobject/gparam.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* --- macros --- */
+#define        G_SIGNAL_HINT_ID(hint)          ((hint) >> 8) 
+#define        G_SIGNAL_HINT_RUN_TYPE(hint)    ((hint) & 0xff)
+
+
+/* --- run & match types --- */
+typedef enum
+{
+  G_SIGNAL_RUN_FIRST   = 1 << 0,
+  G_SIGNAL_RUN_LAST    = 1 << 1,
+  G_SIGNAL_RUN_CLEANUP = 1 << 2,
+  G_SIGNAL_NO_RECURSE  = 1 << 3,
+  G_SIGNAL_ACTION      = 1 << 4,
+  G_SIGNAL_NO_HOOKS    = 1 << 5
+} GSignalType;
+typedef enum
+{
+  G_SIGNAL_MATCH_ID       = 1 << 0,
+  G_SIGNAL_MATCH_CLOSURE   = 1 << 1,
+  G_SIGNAL_MATCH_FUNC     = 1 << 2,
+  G_SIGNAL_MATCH_DATA     = 1 << 3,
+  G_SIGNAL_MATCH_UNBLOCKED = 1 << 4,
+  G_SIGNAL_MATCH_MASK     = 0x1f
+} GSignalMatchType;
+
+
+/* --- signal queries --- */
+typedef struct _GSignalQuery GSignalQuery;
+struct _GSignalQuery
+{
+  guint                signal_id;
+  const gchar  *signal_name;
+  GType                itype;
+  GSignalType  signal_flags;
+  GType                return_type;
+  guint                n_params;
+  const GType  *param_types;
+};
+
+
+/* --- function types --- */
+typedef gboolean  (*GSignalEmissionHook)       (guint          signal_id,
+                                                guint          n_values,
+                                                const GValue  *values);
+typedef gboolean  (*GSignalAccumulator)                (guint          signal_id,
+                                                GValue        *return_accu,
+                                                const GValue  *return_value);
+typedef        GClosureMarshal                 GSignalCMarshaller;
+
+
+/* --- signals --- */
+guint  g_signal_newv                   (const gchar            *signal_name,
+                                        GType                   itype,
+                                        GSignalType             signal_flags,
+                                        GClosure               *class_closure,
+                                        GSignalAccumulator      accumulator,
+                                        GSignalCMarshaller      c_marshaller,
+                                        GType                   return_type,
+                                        guint                   n_params,
+                                        GType                  *param_types);
+void   g_signal_emitv                  (const GValue           *instance_and_params,
+                                        guint                   signal_id,
+                                        GValue                 *return_value);
+guint  g_signal_lookup                 (const gchar            *name,
+                                        GType                   itype);
+gchar* g_signal_name                   (guint                   signal_id);
+void   g_signal_query                  (guint                   signal_id,
+                                        GSignalQuery           *query);
+
+
+/* --- signal handlers --- */
+guint   g_signal_connect_closure       (gpointer                instance,
+                                        guint                   signal_id,
+                                        GClosure               *closure,
+                                        gboolean                after);
+void    g_signal_handler_disconnect    (gpointer                instance,
+                                        guint                   handler_id);
+void    g_signal_handler_block         (gpointer                instance,
+                                        guint                   handler_id);
+void    g_signal_handler_unblock       (gpointer                instance,
+                                        guint                   handler_id);
+guint   g_signal_handler_find          (gpointer                instance,
+                                        GSignalMatchType        mask,
+                                        guint                   signal_id,
+                                        GClosure               *closure,
+                                        gpointer                func,
+                                        gpointer                data);
+gboolean g_signal_has_handler_pending  (gpointer                instance,
+                                        guint                   signal_id,
+                                        gboolean                may_be_blocked);
+
+
+/* --- signal emissions --- */
+void   g_signal_stop_emission          (gpointer                instance,
+                                        guint                   signal_id);
+guint  g_signal_add_emission_hook_full (guint                   signal_id,
+                                        GClosure               *closure);
+void   g_signal_remove_emission_hook   (guint                   signal_id,
+                                        guint                   hook_id);
+
+/*< private >*/
+void   g_signal_handlers_destroy       (gpointer               instance);
+void   g_signals_destroy               (GType                  itype);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __G_SIGNAL_H__ */
index a4818cc6d6b39aaae5d17fdafcfdf51187875919..f202886a22104d9263adaaed997c07956325878a 100644 (file)
  * TODO:
  * - g_type_from_name() should do an ordered array lookup after fetching the
  *   the quark, instead of a second hashtable lookup.
+ * - speedup checks for virtual types, steal a bit somewhere
  *
  * FIXME:
  * - force interface initialization for already existing classes
+ * - make things threadsafe
  */
 
-#define G_TYPE_FLAG_MASK       (G_TYPE_FLAG_CLASSED | \
-                                G_TYPE_FLAG_INSTANTIATABLE | \
-                                G_TYPE_FLAG_DERIVABLE | \
-                                G_TYPE_FLAG_DEEP_DERIVABLE)
+#define TYPE_FUNDAMENTAL_FLAG_MASK (G_TYPE_FLAG_CLASSED | \
+                                   G_TYPE_FLAG_INSTANTIATABLE | \
+                                   G_TYPE_FLAG_DERIVABLE | \
+                                   G_TYPE_FLAG_DEEP_DERIVABLE)
+#define        TYPE_FLAG_MASK             (G_TYPE_FLAG_ABSTRACT)
+
 #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,v)       ((p)->vtable->complete_type_info ((p), (t), (i), (v)))
 #define        g_type_plugin_complete_interface_info(p,f,t,i)  ((p)->vtable->complete_interface_info ((p), (f), (t), (i)))
 
+
+/* --- typedefs --- */
 typedef struct _TypeNode        TypeNode;
 typedef struct _CommonData      CommonData;
 typedef struct _IFaceData       IFaceData;
@@ -58,6 +64,8 @@ typedef struct _IFaceHolder   IFaceHolder;
 
 /* --- prototypes --- */
 static inline GTypeFundamentalInfo*    type_node_fundamental_info      (TypeNode               *node);
+static       void                      type_add_flags                  (TypeNode               *node,
+                                                                        GTypeFlags              flags);
 static       void                      type_data_make                  (TypeNode               *node,
                                                                         const GTypeInfo        *info,
                                                                         const GTypeValueTable  *value_table);
@@ -69,6 +77,10 @@ static             void                      type_data_last_unref            (GType                   type,
 
 
 /* --- structures --- */
+struct _GValue /* kludge, keep in sync with gvalue.h */
+{
+  GType g_type;
+};
 struct _TypeNode
 {
   GTypePlugin *plugin;
@@ -159,11 +171,12 @@ typedef struct {
 /* --- variables --- */
 static guint           n_class_cache_funcs = 0;
 static ClassCacheFunc *class_cache_funcs = NULL;
+static GType           last_fundamental_id = 0;
+static GQuark          quark_type_flags = 0;
 
 
 /* --- externs --- */
 const char  *g_log_domain_gobject = "GLib-Object";
-static GType last_fundamental_id = 0;
 
 
 /* --- type nodes --- */
@@ -187,11 +200,11 @@ LOOKUP_TYPE_NODE (register GType utype)
 #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)
+type_node_any_new (TypeNode              *pnode,
+                  GType                  ftype,
+                  const gchar           *name,
+                  GTypePlugin           *plugin,
+                  GTypeFundamentalFlags  type_flags)
 {
   guint branch_last, n_supers = pnode ? pnode->n_supers + 1 : 0;
   GType type;
@@ -204,11 +217,11 @@ type_node_any_new (TypeNode    *pnode,
     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 info */
-  node_size += SIZEOF_BASE_TYPE_NODE ();        /* TypeNode structure */
+    node_size += sizeof (GTypeFundamentalInfo);              /* fundamental type info */
+  node_size += SIZEOF_BASE_TYPE_NODE ();             /* TypeNode structure */
   node_size += (sizeof (GType) * (1 + n_supers + 1)); /* self + ancestors + 0 for ->supers[] */
   node = g_malloc0 (node_size);
-  if (!pnode)                                   /* fundamental type */
+  if (!pnode)                                        /* offset fundamental types */
     node = G_STRUCT_MEMBER_P (node, sizeof (GTypeFundamentalInfo));
   g_type_nodes[ftype][branch_last] = node;
 
@@ -280,9 +293,9 @@ type_node_fundamental_info (TypeNode *node)
 }
 
 static TypeNode*
-type_node_fundamental_new (GType        ftype,
-                          const gchar *name,
-                          GTypeFlags   type_flags)
+type_node_fundamental_new (GType                 ftype,
+                          const gchar          *name,
+                          GTypeFundamentalFlags type_flags)
 {
   GTypeFundamentalInfo *finfo;
   TypeNode *node;
@@ -290,7 +303,7 @@ type_node_fundamental_new (GType        ftype,
   
   g_assert (ftype == G_TYPE_FUNDAMENTAL (ftype));
   
-  type_flags &= G_TYPE_FLAG_MASK;
+  type_flags &= TYPE_FUNDAMENTAL_FLAG_MASK;
 
   last_fundamental_id = MAX (last_fundamental_id, ftype + 1);
   if (last_fundamental_id > flast)
@@ -495,6 +508,7 @@ check_value_table (const gchar           *type_name,
   else if (value_table->value_init == NULL)
     {
       if (value_table->value_free || value_table->value_copy ||
+         value_table->value_peek_pointer ||
          value_table->collect_type || value_table->collect_value ||
          value_table->lcopy_type || value_table->lcopy_value)
        g_warning ("cannot handle uninitializable values of type `%s'",
@@ -695,6 +709,25 @@ check_interface_info (TypeNode             *iface,
 
 
 /* --- type info (type node data) --- */
+static void
+type_add_flags (TypeNode  *node,
+               GTypeFlags flags)
+{
+  guint dflags;
+
+  g_return_if_fail ((flags & ~TYPE_FLAG_MASK) == 0);
+  g_return_if_fail (node != NULL);
+
+  if (!quark_type_flags)
+    quark_type_flags = g_quark_from_static_string ("GTypeFlags");
+  if ((flags & G_TYPE_FLAG_ABSTRACT) && node->is_classed &&
+      node->data && node->data->class.class)
+    g_warning ("tagging type `%s' as abstract after class initialization", NODE_NAME (node));
+  dflags = GPOINTER_TO_UINT (g_type_get_qdata (NODE_TYPE (node), quark_type_flags));
+  dflags |= flags;
+  g_type_set_qdata (NODE_TYPE (node), quark_type_flags, GUINT_TO_POINTER (dflags));
+}
+
 static void
 type_data_make (TypeNode              *node,
                const GTypeInfo       *info,
@@ -856,10 +889,10 @@ type_node_add_iface_entry (TypeNode *node,
 }
 
 static void
-type_add_interface (TypeNode       *node,
-                   TypeNode       *iface,
-                   GInterfaceInfo *info,
-                   GTypePlugin    *plugin)
+type_add_interface (TypeNode             *node,
+                   TypeNode             *iface,
+                   const GInterfaceInfo *info,
+                   GTypePlugin          *plugin)
 {
   IFaceHolder *iholder = g_new0 (IFaceHolder, 1);
   
@@ -943,6 +976,12 @@ g_type_create_instance (GType type)
                 type_descriptive_name (type));
       return NULL;
     }
+  if (G_TYPE_IS_ABSTRACT (type))
+    {
+      g_warning ("cannot create instance of abstract (non-instantiatable) type `%s'",
+                type_descriptive_name (type));
+      return NULL;
+    }
   
   class = g_type_class_ref (type);
   
@@ -992,8 +1031,15 @@ g_type_free_instance (GTypeInstance *instance)
                 type_descriptive_name (class->g_type));
       return;
     }
+  if (G_TYPE_IS_ABSTRACT (NODE_TYPE (node)))
+    {
+      g_warning ("cannot free instance of abstract (non-instantiatable) type `%s'",
+                NODE_NAME (node));
+      return;
+    }
 
   instance->g_class = NULL;
+  memset (instance, 0xaa, node->data->instance.instance_size); // FIXME
   if (node->data->instance.n_preallocs)
     g_chunk_free (instance, node->data->instance.mem_chunk);
   else
@@ -1282,7 +1328,8 @@ GType
 g_type_register_fundamental (GType                       type_id,
                             const gchar                *type_name,
                             const GTypeInfo            *info,
-                            const GTypeFundamentalInfo *finfo)
+                            const GTypeFundamentalInfo *finfo,
+                            GTypeFlags                  flags)
 {
   GTypeFundamentalInfo *node_finfo;
   TypeNode *node;
@@ -1318,6 +1365,7 @@ g_type_register_fundamental (GType                       type_id,
 
   node = type_node_fundamental_new (type_id, type_name, finfo->type_flags);
   node_finfo = type_node_fundamental_info (node);
+  type_add_flags (node, flags);
 
   if (!check_type_info (NULL, G_TYPE_FUNDAMENTAL (NODE_TYPE (node)), type_name, info))
     return NODE_TYPE (node);
@@ -1330,7 +1378,8 @@ g_type_register_fundamental (GType                       type_id,
 GType
 g_type_register_static (GType            parent_type,
                        const gchar     *type_name,
-                       const GTypeInfo *info)
+                       const GTypeInfo *info,
+                       GTypeFlags       flags)
 {
   TypeNode *pnode, *node;
   GType type;
@@ -1351,12 +1400,13 @@ g_type_register_static (GType            parent_type,
     return 0;
   if (info->class_finalize)
     {
-      g_warning ("class destructor specified for static type `%s'",
+      g_warning ("class finalizer specified for static type `%s'",
                 type_name);
       return 0;
     }
 
   node = type_node_new (pnode, type_name, NULL);
+  type_add_flags (node, flags);
   type = NODE_TYPE (node);
   type_data_make (node, info,
                  check_value_table (type_name, info->value_table) ? info->value_table : NULL);
@@ -1367,7 +1417,8 @@ g_type_register_static (GType            parent_type,
 GType
 g_type_register_dynamic (GType        parent_type,
                         const gchar *type_name,
-                        GTypePlugin *plugin)
+                        GTypePlugin *plugin,
+                        GTypeFlags   flags)
 {
   TypeNode *pnode, *node;
   GType type;
@@ -1385,15 +1436,16 @@ g_type_register_dynamic (GType        parent_type,
   pnode = LOOKUP_TYPE_NODE (parent_type);
 
   node = type_node_new (pnode, type_name, plugin);
+  type_add_flags (node, flags);
   type = NODE_TYPE (node);
 
   return type;
 }
 
 void
-g_type_add_interface_static (GType           instance_type,
-                            GType           interface_type,
-                            GInterfaceInfo *info)
+g_type_add_interface_static (GType                 instance_type,
+                            GType                 interface_type,
+                            const GInterfaceInfo *info)
 {
   TypeNode *node;
   TypeNode *iface;
@@ -1674,11 +1726,7 @@ g_type_conforms_to (GType type,
        }
     }
   else
-    {
-      TypeNode *node = LOOKUP_TYPE_NODE (type);
-
-      return node && (node->is_iface || node->is_instantiatable);
-    }
+    return LOOKUP_TYPE_NODE (type) != NULL;
 
   return FALSE;
 }
@@ -1839,20 +1887,34 @@ g_type_set_qdata (GType    type,
 
 /* --- implementation details --- */
 gboolean
-g_type_check_flags (GType      type,
-                   GTypeFlags flags)
+g_type_check_flags (GType type,
+                   guint flags)
 {
   TypeNode *node = LOOKUP_TYPE_NODE (type);
-  
-  flags &= G_TYPE_FLAG_MASK;
+  gboolean result = FALSE;
+
   if (node)
     {
-      GTypeFundamentalInfo *finfo = type_node_fundamental_info (node);
+      guint fflags = flags & TYPE_FUNDAMENTAL_FLAG_MASK;
+      guint tflags = flags & TYPE_FLAG_MASK;
+
+      if (fflags)
+       {
+         GTypeFundamentalInfo *finfo = type_node_fundamental_info (node);
+         
+         fflags = (finfo->type_flags & fflags) == fflags;
+       }
+      else
+       fflags = TRUE;
+      
+      if (tflags)
+       tflags = (tflags & GPOINTER_TO_UINT (g_type_get_qdata (type, quark_type_flags))) == tflags;
+      else
+       tflags = TRUE;
       
-      return (finfo->type_flags & flags) != 0;
+      result = tflags && fflags;
     }
-  
-  return FALSE;
+  return result;
 }
 
 GTypePlugin*
@@ -1874,6 +1936,7 @@ g_type_instance_conforms_to (GTypeInstance *type_instance,
                             GType          iface_type)
 {
   return (type_instance && type_instance->g_class &&
+         G_TYPE_IS_INSTANTIATABLE (type_instance->g_class->g_type) &&
          g_type_conforms_to (type_instance->g_class->g_type, iface_type));
 }
 
@@ -1881,7 +1944,35 @@ 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));
+  return (type_class && G_TYPE_IS_CLASSED (type_class->g_type) &&
+         g_type_is_a (type_class->g_type, is_a_type));
+}
+
+gboolean
+g_type_value_conforms_to (GValue *value,
+                         GType   type)
+{
+  TypeNode *node;
+  
+  if (!value)
+    return FALSE;
+  node = LOOKUP_TYPE_NODE (value->g_type);
+#if 0
+  if (!G_TYPE_IS_FUNDAMENTAL (value->g_type) && !node || !node->data)
+    node = LOOKUP_TYPE_NODE (G_TYPE_FUNDAMENTAL (value->g_type));
+#endif
+  if (!node || !node->data || node->data->common.ref_count < 1 ||
+      !node->data->common.value_table->value_init ||
+      !g_type_conforms_to (value->g_type, type))
+    return FALSE;
+  
+  return TRUE;
+}
+
+gboolean
+g_type_check_value (GValue *value)
+{
+  return value && g_type_value_conforms_to (value, value->g_type);
 }
 
 GTypeInstance*
@@ -1900,9 +1991,9 @@ g_type_check_instance_cast (GTypeInstance *type_instance,
                 type_descriptive_name (iface_type));
       return type_instance;
     }
-  if (!G_TYPE_IS_CLASSED (type_instance->g_class->g_type))
+  if (!G_TYPE_IS_INSTANTIATABLE (type_instance->g_class->g_type))
     {
-      g_warning ("invalid unclassed type `%s' in cast to `%s'",
+      g_warning ("invalid uninstantiatable type `%s' in cast to `%s'",
                 type_descriptive_name (type_instance->g_class->g_type),
                 type_descriptive_name (iface_type));
       return type_instance;
@@ -1946,13 +2037,47 @@ g_type_check_class_cast (GTypeClass *type_class,
   return type_class;
 }
 
+gboolean
+g_type_check_instance (GTypeInstance *type_instance)
+{
+  /* this function is just here to make the signal system
+   * conveniently elaborated on instance checks
+   */
+  if (!type_instance)
+    {
+      g_warning ("instance is invalid (NULL) pointer");
+      return FALSE;
+    }
+  if (!type_instance->g_class)
+    {
+      g_warning ("instance with invalid (NULL) class pointer");
+      return FALSE;
+    }
+  if (!G_TYPE_IS_CLASSED (type_instance->g_class->g_type))
+    {
+      g_warning ("instance of invalid unclassed type `%s'",
+                type_descriptive_name (type_instance->g_class->g_type));
+      return FALSE;
+    }
+  if (!G_TYPE_IS_INSTANTIATABLE (type_instance->g_class->g_type))
+    {
+      g_warning ("instance of invalid non-instantiatable type `%s'",
+                type_descriptive_name (type_instance->g_class->g_type));
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
 
 /* --- foreign prototypes --- */
 extern void    g_value_types_init      (void); /* sync with gvaluetypes.c */
 extern void    g_enum_types_init       (void); /* sync with genums.c */
 extern void     g_param_type_init       (void);        /* sync with gparam.c */
+extern void     g_boxed_type_init       (void);        /* sync with gboxed.c */
 extern void     g_object_type_init      (void);        /* sync with gobject.c */
 extern void    g_param_spec_types_init (void); /* sync with gparamspecs.c */
+extern void    g_signal_init           (void); /* sync with gsignal.c */
 
 
 /* --- initialization --- */
@@ -2004,6 +2129,10 @@ g_type_init (void)
    */
   g_param_type_init ();
 
+  /* G_TYPE_PARAM
+   */
+  g_boxed_type_init ();
+
   /* G_TYPE_OBJECT
    */
   g_object_type_init ();
@@ -2011,4 +2140,8 @@ g_type_init (void)
   /* G_TYPE_PARAM_* pspec types
    */
   g_param_spec_types_init ();
+
+  /* Signal system
+   */
+  g_signal_init ();
 }
index 60086e8b12245e38d0f50a5221d23423efb742a6..1c8e0b40b7abf20fb823310194dda340547b3a03 100644 (file)
@@ -60,11 +60,11 @@ typedef enum    /*< skip >*/
   G_TYPE_DOUBLE,
   G_TYPE_STRING,
   G_TYPE_PARAM,
+  G_TYPE_BOXED,
+  G_TYPE_POINTER,
   G_TYPE_OBJECT,
 
   /* the following reserved ids should vanish soon */
-  G_TYPE_GTK_BOXED,
-  G_TYPE_GTK_POINTER,
   G_TYPE_GTK_SIGNAL,
 
   /* reserved fundamental type ids,
@@ -99,12 +99,15 @@ typedef enum    /*< skip >*/
 
 /* Type Checking Macros
  */
+#define G_TYPE_IS_FUNDAMENTAL(type)             (G_TYPE_BRANCH_SEQNO (type) == 0)
 #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_ABSTRACT(type)                (g_type_check_flags ((type), G_TYPE_FLAG_ABSTRACT))
 #define G_TYPE_IS_PARAM(type)                   (G_TYPE_FUNDAMENTAL (type) == G_TYPE_PARAM)
+#define G_TYPE_IS_VALUE_TYPE(type)              (g_type_value_table_peek (type) != NULL)
 
 
 /* Typedefs
@@ -143,13 +146,20 @@ struct _GTypeInterface
 };
 
 
-/* Casts, Checks And Convenience Macros For Structured Types
+/* Casts, checks and accessors for structured types
+ * usage of these macros is reserved to type implementations only
+ * 
  */
+/*< protected >*/
+#define G_TYPE_CHECK_INSTANCE(instance)                                (_G_TYPE_CHI ((GTypeInstance*) (instance)))
 #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_INSTANCE_GET_INTERFACE(instance, g_type, c_type) (_G_TYPE_IGI ((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_CLASS_TYPE(g_class, g_type)                (_G_TYPE_CCT ((g_class), (g_type)))
+#define G_TYPE_CHECK_VALUE(value)                              (_G_TYPE_CHV ((value)))
+#define G_TYPE_CHECK_VALUE_TYPE(value, g_type)                 (_G_TYPE_CVT ((value), (g_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)
 #define G_TYPE_FROM_INTERFACE(g_iface)                          (((GTypeInterface*) (g_iface))->g_type)
@@ -229,6 +239,10 @@ typedef enum    /*< skip >*/
   G_TYPE_FLAG_INSTANTIATABLE    = (1 << 1),
   G_TYPE_FLAG_DERIVABLE         = (1 << 2),
   G_TYPE_FLAG_DEEP_DERIVABLE    = (1 << 3)
+} GTypeFundamentalFlags;
+typedef enum    /*< skip >*/
+{
+  G_TYPE_FLAG_ABSTRACT          = (1 << 4)
 } GTypeFlags;
 struct _GTypeInfo
 {
@@ -253,7 +267,7 @@ struct _GTypeInfo
 };
 struct _GTypeFundamentalInfo
 {
-  GTypeFlags             type_flags;
+  GTypeFundamentalFlags  type_flags;
 };
 struct _GInterfaceInfo
 {
@@ -263,61 +277,72 @@ struct _GInterfaceInfo
 };
 struct _GTypeValueTable
 {
-  void   (*value_init)    (GValue       *value);
-  void   (*value_free)    (GValue       *value);
-  void   (*value_copy)    (const GValue *src_value,
-                          GValue       *dest_value);
+  void     (*value_init)         (GValue       *value);
+  void     (*value_free)         (GValue       *value);
+  void     (*value_copy)         (const GValue *src_value,
+                                 GValue       *dest_value);
   /* varargs functionality (optional) */
-  guint    collect_type;
-  gchar* (*collect_value) (GValue       *value,
-                          guint         nth_value,
-                          GType        *collect_type,
-                          GTypeCValue  *collect_value);
-  guint    lcopy_type;
-  gchar* (*lcopy_value)   (const GValue *value,
-                          guint         nth_value,
-                          GType        *collect_type,
-                          GTypeCValue  *collect_value);
+  gpointer (*value_peek_pointer) (const GValue *value);
+  guint      collect_type;
+  gchar*   (*collect_value)      (GValue       *value,
+                                 guint         nth_value,
+                                 GType        *collect_type,
+                                 GTypeCValue  *collect_value);
+  guint      lcopy_type;
+  gchar*   (*lcopy_value)        (const GValue *value,
+                                 guint         nth_value,
+                                 GType        *collect_type,
+                                 GTypeCValue  *collect_value);
 };
 GType g_type_register_static       (GType                       parent_type,
                                     const gchar                *type_name,
-                                    const GTypeInfo            *info);
+                                    const GTypeInfo            *info,
+                                   GTypeFlags                  flags);
 GType g_type_register_dynamic      (GType                       parent_type,
                                     const gchar                *type_name,
-                                    GTypePlugin                *plugin);
+                                    GTypePlugin                *plugin,
+                                   GTypeFlags                  flags);
 GType g_type_register_fundamental  (GType                       type_id,
                                     const gchar                *type_name,
                                     const GTypeInfo            *info,
-                                    const GTypeFundamentalInfo *finfo);
+                                    const GTypeFundamentalInfo *finfo,
+                                   GTypeFlags                  flags);
 void  g_type_add_interface_static  (GType                       instance_type,
                                     GType                       interface_type,
-                                    GInterfaceInfo             *info);
+                                    const 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);
+/* --- protected (for fundamental type implementations) --- */
+GTypePlugin*    g_type_get_plugin              (GType               type);
+GType           g_type_fundamental_last        (void);
 gboolean         g_type_check_flags             (GType               type,
-                                                GTypeFlags          flags);
+                                                guint               flags);
 GTypeInstance*   g_type_create_instance         (GType               type);
 void             g_type_free_instance           (GTypeInstance      *instance);
-GTypeValueTable* g_type_value_table_peek        (GType              type);
 void            g_type_add_class_cache_func    (gpointer            cache_data,
                                                 GTypeClassCacheFunc cache_func);
 void            g_type_remove_class_cache_func (gpointer            cache_data,
                                                 GTypeClassCacheFunc cache_func);
 void             g_type_class_unref_uncached    (gpointer            g_class);
-GTypePlugin*    g_type_get_plugin              (GType               type);
-GType           g_type_fundamental_last        (void);
+
+
+/*< private >*/
+GTypeClass*      g_type_check_class_cast        (GTypeClass         *g_class,
+                                                GType               is_a_type);
+gboolean         g_type_class_is_a              (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_value             (GValue             *value);
+gboolean        g_type_value_conforms_to       (GValue             *value,
+                                                GType               type);
+gboolean        g_type_check_instance          (GTypeInstance      *instance);
+GTypeValueTable* g_type_value_table_peek        (GType              type);
 
 
 #ifndef G_DISABLE_CAST_CHECKS
@@ -329,9 +354,14 @@ GType               g_type_fundamental_last        (void);
 #  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_CHI(ip)                        (g_type_check_instance ((GTypeInstance*) ip))
 #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))
+#define _G_TYPE_CVT(vl, gt)             (g_type_value_conforms_to ((GValue*) vl, gt))
+#define _G_TYPE_CHV(vl)                        (g_type_check_value ((GValue*) vl))
+#define _G_TYPE_IGC(ip, ct)             ((ct*) (((GTypeInstance*) ip)->g_class))
+#define _G_TYPE_IGI(ip, gt, ct)         ((ct*) g_type_interface_peek (((GTypeInstance*) ip)->g_class, gt))
+
 
 #ifdef __cplusplus
 }
index bdc0a9c9f023dedf79b4e2dbb057fddc76eee51d..40938009e28b0512b1b4907630e918e9692275f8 100644 (file)
@@ -61,11 +61,13 @@ void
 g_value_copy (const GValue *src_value,
              GValue       *dest_value)
 {
-  GTypeValueTable *value_table = g_type_value_table_peek (G_VALUE_TYPE (dest_value));
+  GTypeValueTable *value_table;
   
   g_return_if_fail (G_IS_VALUE (src_value));
   g_return_if_fail (G_IS_VALUE (dest_value));
   g_return_if_fail (g_type_is_a (G_VALUE_TYPE (src_value), G_VALUE_TYPE (dest_value)));
+
+  value_table = g_type_value_table_peek (G_VALUE_TYPE (dest_value));
   if (!value_table)
     g_return_if_fail (g_type_value_table_peek (G_VALUE_TYPE (dest_value)) != NULL);
   
@@ -78,6 +80,36 @@ g_value_copy (const GValue *src_value,
     }
 }
 
+gboolean
+g_value_fits_pointer (const GValue *value)
+{
+  GTypeValueTable *value_table;
+
+  g_return_val_if_fail (G_IS_VALUE (value), FALSE);
+
+  value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
+  if (!value_table)
+    g_return_val_if_fail (g_type_value_table_peek (G_VALUE_TYPE (value)) != NULL, FALSE);
+
+  return value_table->value_peek_pointer != NULL;
+}
+
+gpointer
+g_value_get_as_pointer (const GValue *value)
+{
+  GTypeValueTable *value_table;
+
+  g_return_val_if_fail (G_IS_VALUE (value), NULL);
+
+  value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
+  if (!value_table)
+    g_return_val_if_fail (g_type_value_table_peek (G_VALUE_TYPE (value)) != NULL, NULL);
+  if (!value_table->value_peek_pointer)
+    g_return_val_if_fail (g_value_fits_pointer (value) == TRUE, NULL);
+
+  return value_table->value_peek_pointer (value);
+}
+
 void
 g_value_unset (GValue *value)
 {
@@ -189,8 +221,8 @@ g_value_register_exchange_func (GType          value_type1,
 {
   ExchangeEntry entry;
   
-  g_return_if_fail (G_TYPE_IS_VALUE (value_type1));
-  g_return_if_fail (G_TYPE_IS_VALUE (value_type2));
+  g_return_if_fail (g_type_name (value_type1) != NULL);
+  g_return_if_fail (g_type_name (value_type2) != NULL);
   g_return_if_fail (func != NULL);
   
   entry.value_type1 = MIN (value_type1, value_type2);
@@ -218,7 +250,7 @@ gboolean
 g_value_types_exchangable (GType value_type1,
                           GType value_type2)
 {
-  g_return_val_if_fail (G_TYPE_IS_VALUE (value_type1), FALSE);
+  g_return_val_if_fail (G_TYPE_IS_VALUE (value_type1), FALSE); /* these might bite us, think G_TYPE_ENUM */
   g_return_val_if_fail (G_TYPE_IS_VALUE (value_type2), FALSE);
   
   return exchange_func_lookup (value_type1, value_type2, NULL) != NULL;
index fb41ffa422b469df290a0cefce0da0a5cfba6deb..d095657ea3ab010cd098c6f8e7dab9c70b882025 100644 (file)
@@ -31,8 +31,9 @@ extern "C" {
 
 /* --- type macros --- */
 #define        G_TYPE_IS_VALUE(type)           (g_type_value_table_peek (type) != NULL)
-#define        G_IS_VALUE(value)               (G_TYPE_IS_VALUE (G_VALUE_TYPE (value))) /* FIXME */
-#define        G_VALUE_TYPE(value)             (G_TYPE_FROM_CLASS (value))
+#define        G_IS_VALUE(value)               (G_TYPE_CHECK_VALUE (value))
+#define        G_VALUE_HOLDS(value, g_type)    (G_TYPE_CHECK_VALUE_TYPE ((value), (g_type)))
+#define        G_VALUE_TYPE(value)             (((GValue*) (value))->g_type)
 #define        G_VALUE_TYPE_NAME(value)        (g_type_name (G_VALUE_TYPE (value)))
 
 
@@ -66,6 +67,8 @@ gboolean      g_value_convert         (const GValue *src_value,
                                         GValue       *dest_value);
 void            g_value_reset          (GValue       *value);
 void            g_value_unset          (GValue       *value);
+gboolean       g_value_fits_pointer    (const GValue *value);
+gpointer       g_value_get_as_pointer  (const GValue *value);
 
 
 /* --- implementation details --- */
index d27171c8f6abc5a960661606cd6e24df0a1d9931..8f5d6175a59c3173c1f28243941ae793e407808c 100644 (file)
@@ -260,6 +260,54 @@ value_string_lcopy_value (const GValue *value,
   return NULL;
 }
 
+static void
+value_pointer_init (GValue *value)
+{
+  value->data[0].v_pointer = 0;
+}
+
+static void
+value_pointer_copy (const GValue *src_value,
+                   GValue       *dest_value)
+{
+  dest_value->data[0].v_pointer = src_value->data[0].v_pointer;
+}
+
+static gpointer
+value_pointer_peek_pointer (const GValue *value)
+{
+  return value->data[0].v_pointer;
+}
+
+static gchar*
+value_pointer_collect_value (GValue      *value,
+                            guint        nth_value,
+                            GType       *collect_type,
+                            GTypeCValue *collect_value)
+{
+  value->data[0].v_pointer = collect_value->v_pointer;
+
+  *collect_type = 0;
+  return NULL;
+}
+
+static gchar*
+value_pointer_lcopy_value (const GValue *value,
+                          guint         nth_value,
+                          GType        *collect_type,
+                          GTypeCValue  *collect_value)
+{
+  gpointer *pointer_p = collect_value->v_pointer;
+
+  if (!pointer_p)
+    return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
+
+  *pointer_p = value->data[0].v_pointer;
+
+  *collect_type = 0;
+  return NULL;
+}
+
 
 /* --- type initialization --- */
 void
@@ -287,15 +335,16 @@ g_value_types_init (void)  /* sync with gtype.c */
       value_long0_init,                /* value_init */
       NULL,                    /* value_free */
       value_long0_copy,                /* value_copy */
+      NULL,                    /* value_peek_pointer */
       G_VALUE_COLLECT_INT,     /* collect_type */
       value_int_collect_value, /* collect_value */
       G_VALUE_COLLECT_POINTER, /* lcopy_type */
       value_char_lcopy_value,  /* lcopy_value */
     };
     info.value_table = &value_table;
-    type = g_type_register_fundamental (G_TYPE_CHAR, "gchar", &info, &finfo);
+    type = g_type_register_fundamental (G_TYPE_CHAR, "gchar", &info, &finfo, 0);
     g_assert (type == G_TYPE_CHAR);
-    type = g_type_register_fundamental (G_TYPE_UCHAR, "guchar", &info, &finfo);
+    type = g_type_register_fundamental (G_TYPE_UCHAR, "guchar", &info, &finfo, 0);
     g_assert (type == G_TYPE_UCHAR);
   }
 
@@ -306,13 +355,14 @@ g_value_types_init (void)  /* sync with gtype.c */
       value_long0_init,                 /* value_init */
       NULL,                     /* value_free */
       value_long0_copy,                 /* value_copy */
+      NULL,                      /* value_peek_pointer */
       G_VALUE_COLLECT_INT,      /* collect_type */
       value_int_collect_value,  /* collect_value */
       G_VALUE_COLLECT_POINTER,  /* lcopy_type */
       value_boolean_lcopy_value, /* lcopy_value */
     };
     info.value_table = &value_table;
-    type = g_type_register_fundamental (G_TYPE_BOOLEAN, "gboolean", &info, &finfo);
+    type = g_type_register_fundamental (G_TYPE_BOOLEAN, "gboolean", &info, &finfo, 0);
     g_assert (type == G_TYPE_BOOLEAN);
   }
   
@@ -323,15 +373,16 @@ g_value_types_init (void)  /* sync with gtype.c */
       value_long0_init,                /* value_init */
       NULL,                    /* value_free */
       value_long0_copy,                /* value_copy */
+      NULL,                     /* value_peek_pointer */
       G_VALUE_COLLECT_INT,     /* collect_type */
       value_int_collect_value, /* collect_value */
       G_VALUE_COLLECT_POINTER, /* lcopy_type */
       value_int_lcopy_value,   /* lcopy_value */
     };
     info.value_table = &value_table;
-    type = g_type_register_fundamental (G_TYPE_INT, "gint", &info, &finfo);
+    type = g_type_register_fundamental (G_TYPE_INT, "gint", &info, &finfo, 0);
     g_assert (type == G_TYPE_INT);
-    type = g_type_register_fundamental (G_TYPE_UINT, "guint", &info, &finfo);
+    type = g_type_register_fundamental (G_TYPE_UINT, "guint", &info, &finfo, 0);
     g_assert (type == G_TYPE_UINT);
   }
 
@@ -342,15 +393,16 @@ g_value_types_init (void)  /* sync with gtype.c */
       value_long0_init,                /* value_init */
       NULL,                    /* value_free */
       value_long0_copy,                /* value_copy */
+      NULL,                     /* value_peek_pointer */
       G_VALUE_COLLECT_LONG,    /* collect_type */
       value_long_collect_value,        /* collect_value */
       G_VALUE_COLLECT_POINTER, /* lcopy_type */
       value_long_lcopy_value,  /* lcopy_value */
     };
     info.value_table = &value_table;
-    type = g_type_register_fundamental (G_TYPE_LONG, "glong", &info, &finfo);
+    type = g_type_register_fundamental (G_TYPE_LONG, "glong", &info, &finfo, 0);
     g_assert (type == G_TYPE_LONG);
-    type = g_type_register_fundamental (G_TYPE_ULONG, "gulong", &info, &finfo);
+    type = g_type_register_fundamental (G_TYPE_ULONG, "gulong", &info, &finfo, 0);
     g_assert (type == G_TYPE_ULONG);
   }
   
@@ -361,13 +413,14 @@ g_value_types_init (void)  /* sync with gtype.c */
       value_float_init,                 /* value_init */
       NULL,                     /* value_free */
       value_float_copy,                 /* value_copy */
+      NULL,                      /* value_peek_pointer */
       G_VALUE_COLLECT_DOUBLE,   /* collect_type */
       value_float_collect_value, /* collect_value */
       G_VALUE_COLLECT_POINTER,  /* lcopy_type */
       value_float_lcopy_value,  /* lcopy_value */
     };
     info.value_table = &value_table;
-    type = g_type_register_fundamental (G_TYPE_FLOAT, "gfloat", &info, &finfo);
+    type = g_type_register_fundamental (G_TYPE_FLOAT, "gfloat", &info, &finfo, 0);
     g_assert (type == G_TYPE_FLOAT);
   }
   
@@ -378,13 +431,14 @@ g_value_types_init (void)  /* sync with gtype.c */
       value_double_init,         /* value_init */
       NULL,                      /* value_free */
       value_double_copy,         /* value_copy */
+      NULL,                       /* value_peek_pointer */
       G_VALUE_COLLECT_DOUBLE,    /* collect_type */
       value_double_collect_value, /* collect_value */
       G_VALUE_COLLECT_POINTER,   /* lcopy_type */
       value_double_lcopy_value,          /* lcopy_value */
     };
     info.value_table = &value_table;
-    type = g_type_register_fundamental (G_TYPE_DOUBLE, "gdouble", &info, &finfo);
+    type = g_type_register_fundamental (G_TYPE_DOUBLE, "gdouble", &info, &finfo, 0);
     g_assert (type == G_TYPE_DOUBLE);
   }
 
@@ -395,15 +449,34 @@ g_value_types_init (void)  /* sync with gtype.c */
       value_string_init,         /* value_init */
       value_string_free_value,   /* value_free */
       value_string_copy_value,   /* value_copy */
+      value_pointer_peek_pointer, /* value_peek_pointer */
       G_VALUE_COLLECT_POINTER,   /* collect_type */
       value_string_collect_value, /* collect_value */
       G_VALUE_COLLECT_POINTER,   /* lcopy_type */
       value_string_lcopy_value,          /* lcopy_value */
     };
     info.value_table = &value_table;
-    type = g_type_register_fundamental (G_TYPE_STRING, "gstring", &info, &finfo);
+    type = g_type_register_fundamental (G_TYPE_STRING, "gstring", &info, &finfo, 0);
     g_assert (type == G_TYPE_STRING);
   }
+
+  /* G_TYPE_POINTER
+   */
+  {
+    static const GTypeValueTable value_table = {
+      value_pointer_init,          /* value_init */
+      NULL,                        /* value_free */
+      value_pointer_copy,          /* value_copy */
+      value_pointer_peek_pointer,  /* value_peek_pointer */
+      G_VALUE_COLLECT_POINTER,     /* collect_type */
+      value_pointer_collect_value, /* collect_value */
+      G_VALUE_COLLECT_POINTER,     /* lcopy_type */
+      value_pointer_lcopy_value,   /* lcopy_value */
+    };
+    info.value_table = &value_table;
+    type = g_type_register_fundamental (G_TYPE_POINTER, "gpointer", &info, &finfo, 0);
+    g_assert (type == G_TYPE_POINTER);
+  }
 }
 
 
@@ -418,7 +491,7 @@ g_value_set_char (GValue *value,
 }
 
 gint8
-g_value_get_char (GValue *value)
+g_value_get_char (const GValue *value)
 {
   g_return_val_if_fail (G_IS_VALUE_CHAR (value), 0);
   
@@ -435,7 +508,7 @@ g_value_set_uchar (GValue *value,
 }
 
 guint8
-g_value_get_uchar (GValue *value)
+g_value_get_uchar (const GValue *value)
 {
   g_return_val_if_fail (G_IS_VALUE_UCHAR (value), 0);
   
@@ -452,7 +525,7 @@ g_value_set_boolean (GValue  *value,
 }
 
 gboolean
-g_value_get_boolean (GValue *value)
+g_value_get_boolean (const GValue *value)
 {
   g_return_val_if_fail (G_IS_VALUE_BOOLEAN (value), 0);
   
@@ -469,7 +542,7 @@ g_value_set_int (GValue *value,
 }
 
 gint
-g_value_get_int (GValue *value)
+g_value_get_int (const GValue *value)
 {
   g_return_val_if_fail (G_IS_VALUE_INT (value), 0);
   
@@ -486,7 +559,7 @@ g_value_set_uint (GValue *value,
 }
 
 guint
-g_value_get_uint (GValue *value)
+g_value_get_uint (const GValue *value)
 {
   g_return_val_if_fail (G_IS_VALUE_UINT (value), 0);
   
@@ -503,7 +576,7 @@ g_value_set_long (GValue *value,
 }
 
 glong
-g_value_get_long (GValue *value)
+g_value_get_long (const GValue *value)
 {
   g_return_val_if_fail (G_IS_VALUE_LONG (value), 0);
   
@@ -520,7 +593,7 @@ g_value_set_ulong (GValue *value,
 }
 
 gulong
-g_value_get_ulong (GValue *value)
+g_value_get_ulong (const GValue *value)
 {
   g_return_val_if_fail (G_IS_VALUE_ULONG (value), 0);
   
@@ -537,7 +610,7 @@ g_value_set_float (GValue *value,
 }
 
 gfloat
-g_value_get_float (GValue *value)
+g_value_get_float (const GValue *value)
 {
   g_return_val_if_fail (G_IS_VALUE_FLOAT (value), 0);
   
@@ -554,7 +627,7 @@ g_value_set_double (GValue *value,
 }
 
 gdouble
-g_value_get_double (GValue *value)
+g_value_get_double (const GValue *value)
 {
   g_return_val_if_fail (G_IS_VALUE_DOUBLE (value), 0);
   
@@ -572,7 +645,7 @@ g_value_set_string (GValue  *value,
 }
 
 gchar*
-g_value_get_string (GValue *value)
+g_value_get_string (const GValue *value)
 {
   g_return_val_if_fail (G_IS_VALUE_STRING (value), NULL);
   
@@ -580,9 +653,26 @@ g_value_get_string (GValue *value)
 }
 
 gchar*
-g_value_dup_string (GValue *value)
+g_value_dup_string (const 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_pointer (GValue  *value,
+                    gpointer v_pointer)
+{
+  g_return_if_fail (G_IS_VALUE_POINTER (value));
+
+  value->data[0].v_pointer = v_pointer;
+}
+
+gpointer
+g_value_get_pointer (GValue *value)
+{
+  g_return_val_if_fail (G_IS_VALUE_POINTER (value), NULL);
+
+  return value->data[0].v_pointer;
+}
index f1429671d63e421df80d48d162b56e632645e0ea..f91329140866d87ecd9587dffbb1a315f2ef82d0 100644 (file)
@@ -8,7 +8,7 @@
  *
  * 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
+ * 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
@@ -22,7 +22,7 @@
 #define __G_VALUETYPES_H__
 
 
-#include        <gobject/gvalue.h>
+#include       <gobject/gvalue.h>
 
 
 #ifdef __cplusplus
@@ -31,50 +31,54 @@ extern "C" {
 
 
 /* --- type macros --- */
-#define G_IS_VALUE_CHAR(value)          (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_CHAR))
-#define G_IS_VALUE_UCHAR(value)         (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_UCHAR))
-#define G_IS_VALUE_BOOLEAN(value)       (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_BOOLEAN))
-#define G_IS_VALUE_INT(value)           (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_INT))
-#define G_IS_VALUE_UINT(value)          (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_UINT))
-#define G_IS_VALUE_LONG(value)          (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_LONG))
-#define G_IS_VALUE_ULONG(value)         (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_ULONG))
-#define G_IS_VALUE_FLOAT(value)         (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_FLOAT))
-#define G_IS_VALUE_DOUBLE(value)        (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_DOUBLE))
-#define G_IS_VALUE_STRING(value)        (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_STRING))
+#define G_IS_VALUE_CHAR(value)         (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_CHAR))
+#define G_IS_VALUE_UCHAR(value)                (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_UCHAR))
+#define G_IS_VALUE_BOOLEAN(value)      (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_BOOLEAN))
+#define G_IS_VALUE_INT(value)          (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_INT))
+#define G_IS_VALUE_UINT(value)         (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_UINT))
+#define G_IS_VALUE_LONG(value)         (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_LONG))
+#define G_IS_VALUE_ULONG(value)                (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_ULONG))
+#define G_IS_VALUE_FLOAT(value)                (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_FLOAT))
+#define G_IS_VALUE_DOUBLE(value)       (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_DOUBLE))
+#define G_IS_VALUE_STRING(value)       (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_STRING))
+#define G_IS_VALUE_POINTER(value)      (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_POINTER))
 
 
 /* --- 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_boolean     (GValue         *value,
-                                         gboolean        v_boolean);
-gboolean        g_value_get_boolean     (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_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_char        (GValue         *value,
+                                        gint8           v_char);
+gint8          g_value_get_char        (const GValue   *value);
+void           g_value_set_uchar       (GValue         *value,
+                                        guint8          v_uchar);
+guint8         g_value_get_uchar       (const GValue   *value);
+void           g_value_set_boolean     (GValue         *value,
+                                        gboolean        v_boolean);
+gboolean       g_value_get_boolean     (const GValue   *value);
+void           g_value_set_int         (GValue         *value,
+                                        gint            v_int);
+gint           g_value_get_int         (const GValue   *value);
+void           g_value_set_uint        (GValue         *value,
+                                        guint           v_uint);
+guint          g_value_get_uint        (const GValue   *value);
+void           g_value_set_long        (GValue         *value,
+                                        glong           v_long);
+glong          g_value_get_long        (const GValue   *value);
+void           g_value_set_ulong       (GValue         *value,
+                                        gulong          v_ulong);
+gulong         g_value_get_ulong       (const GValue   *value);
+void           g_value_set_float       (GValue         *value,
+                                        gfloat          v_float);
+gfloat         g_value_get_float       (const GValue   *value);
+void           g_value_set_double      (GValue         *value,
+                                        gdouble         v_double);
+gdouble                g_value_get_double      (const GValue   *value);
+void           g_value_set_string      (GValue         *value,
+                                        const gchar    *v_string);
+gchar*         g_value_get_string      (const GValue   *value);
+gchar*         g_value_dup_string      (const GValue   *value);
+void            g_value_set_pointer     (GValue         *value,
+                                        gpointer        v_pointer);
+gpointer        g_value_get_pointer     (GValue         *value);