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