summaryrefslogtreecommitdiff
path: root/gobject
diff options
context:
space:
mode:
authorTim Janik <timj@gtk.org>2000-10-25 20:36:35 +0000
committerTim Janik <timj@src.gnome.org>2000-10-25 20:36:35 +0000
commitee23c09e83d06a0d131ebd234c132f1c3602c019 (patch)
treeb24f3cdd0758fed1a483abc645936ebae963b898 /gobject
parentb13320f78ba3b484a26b6430152b35aaac24ff10 (diff)
added newly added gobject/ headers.
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.
Diffstat (limited to 'gobject')
-rw-r--r--gobject/ChangeLog87
-rw-r--r--gobject/Makefile.am46
-rw-r--r--gobject/gboxed.c316
-rw-r--r--gobject/gboxed.h64
-rw-r--r--gobject/gbsearcharray.c164
-rw-r--r--gobject/gbsearcharray.h134
-rw-r--r--gobject/gclosure.c534
-rw-r--r--gobject/gclosure.h185
-rw-r--r--gobject/genums.c187
-rw-r--r--gobject/genums.h8
-rw-r--r--gobject/glib-genmarshal.1196
-rw-r--r--gobject/glib-genmarshal.c693
-rw-r--r--gobject/gobject-query.c2
-rw-r--r--gobject/gobject.c144
-rw-r--r--gobject/gobject.h73
-rw-r--r--gobject/gparam.c90
-rw-r--r--gobject/gparam.h66
-rw-r--r--gobject/gparamspecs.c205
-rw-r--r--gobject/gsignal.c1335
-rw-r--r--gobject/gsignal.h142
-rw-r--r--gobject/gtype.c221
-rw-r--r--gobject/gtype.h106
-rw-r--r--gobject/gvalue.c40
-rw-r--r--gobject/gvalue.h7
-rw-r--r--gobject/gvaluetypes.c132
-rw-r--r--gobject/gvaluetypes.h90
26 files changed, 4813 insertions, 454 deletions
diff --git a/gobject/ChangeLog b/gobject/ChangeLog
index eddfe3f6d..5b0bb74b6 100644
--- a/gobject/ChangeLog
+++ b/gobject/ChangeLog
@@ -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.
diff --git a/gobject/Makefile.am b/gobject/Makefile.am
index 88e563418..7e2b34a94 100644
--- a/gobject/Makefile.am
+++ b/gobject/Makefile.am
@@ -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
index 000000000..c78612cdd
--- /dev/null
+++ b/gobject/gboxed.c
@@ -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
index 000000000..edd51b06e
--- /dev/null
+++ b/gobject/gboxed.h
@@ -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
index 000000000..9aa1f450f
--- /dev/null
+++ b/gobject/gbsearcharray.c
@@ -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
index 000000000..aadaac828
--- /dev/null
+++ b/gobject/gbsearcharray.h
@@ -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
index 000000000..31cdca669
--- /dev/null
+++ b/gobject/gclosure.c
@@ -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
index 000000000..423ccebb4
--- /dev/null
+++ b/gobject/gclosure.h
@@ -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__ */
diff --git a/gobject/genums.c b/gobject/genums.c
index f18db25cf..e60ec2048 100644
--- a/gobject/genums.c
+++ b/gobject/genums.c
@@ -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;
}
diff --git a/gobject/genums.h b/gobject/genums.h
index f04b7d60f..7fc48ba95 100644
--- a/gobject/genums.h
+++ b/gobject/genums.h
@@ -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
index 000000000..d68ff6b1a
--- /dev/null
+++ b/gobject/glib-genmarshal.1
@@ -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
index 000000000..34081f70f
--- /dev/null
+++ b/gobject/glib-genmarshal.c
@@ -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");
+ }
+}
diff --git a/gobject/gobject-query.c b/gobject/gobject-query.c
index 3e0b37d53..b80709adc 100644
--- a/gobject/gobject-query.c
+++ b/gobject/gobject-query.c
@@ -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>
diff --git a/gobject/gobject.c b/gobject/gobject.c
index 5a703cebb..e5519107c 100644
--- a/gobject/gobject.c
+++ b/gobject/gobject.c
@@ -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;
+}
diff --git a/gobject/gobject.h b/gobject/gobject.h
index 68657abb0..492646888 100644
--- a/gobject/gobject.h
+++ b/gobject/gobject.h
@@ -16,12 +16,13 @@
* 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__ */
diff --git a/gobject/gparam.c b/gobject/gparam.c
index e74787851..9ce72c379 100644
--- a/gobject/gparam.c
+++ b/gobject/gparam.c
@@ -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);
+}
diff --git a/gobject/gparam.h b/gobject/gparam.h
index 370fb4ff9..8b1f3f1cf 100644
--- a/gobject/gparam.h
+++ b/gobject/gparam.h
@@ -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
diff --git a/gobject/gparamspecs.c b/gobject/gparamspecs.c
index d78689f0a..10b8ab3c6 100644
--- a/gobject/gparamspecs.c
+++ b/gobject/gparamspecs.c
@@ -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
index 000000000..5006ebfed
--- /dev/null
+++ b/gobject/gsignal.c
@@ -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
index 000000000..f2be46f63
--- /dev/null
+++ b/gobject/gsignal.h
@@ -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__ */
diff --git a/gobject/gtype.c b/gobject/gtype.c
index a4818cc6d..f202886a2 100644
--- a/gobject/gtype.c
+++ b/gobject/gtype.c
@@ -32,20 +32,26 @@
* 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'",
@@ -696,6 +710,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,
const GTypeValueTable *value_table)
@@ -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 ();
}
diff --git a/gobject/gtype.h b/gobject/gtype.h
index 60086e8b1..1c8e0b40b 100644
--- a/gobject/gtype.h
+++ b/gobject/gtype.h
@@ -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
}
diff --git a/gobject/gvalue.c b/gobject/gvalue.c
index bdc0a9c9f..40938009e 100644
--- a/gobject/gvalue.c
+++ b/gobject/gvalue.c
@@ -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;
diff --git a/gobject/gvalue.h b/gobject/gvalue.h
index fb41ffa42..d095657ea 100644
--- a/gobject/gvalue.h
+++ b/gobject/gvalue.h
@@ -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 --- */
diff --git a/gobject/gvaluetypes.c b/gobject/gvaluetypes.c
index d27171c8f..8f5d6175a 100644
--- a/gobject/gvaluetypes.c
+++ b/gobject/gvaluetypes.c
@@ -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;
+}
diff --git a/gobject/gvaluetypes.h b/gobject/gvaluetypes.h
index f1429671d..f91329140 100644
--- a/gobject/gvaluetypes.h
+++ b/gobject/gvaluetypes.h
@@ -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);