added newly added gobject/ headers.

Tue Oct 24 22:09:14 2000  Tim Janik  <timj@gtk.org>

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

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

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

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

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

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

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

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

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

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

        * genum.c: macro cleanups.

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

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

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

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

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

        * many const corrections over the place.

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

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

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

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

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

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

        * gbsearcharray.[hc]: long standing needed generic implementation
        of a binary searchable, sorted and dynamically sized array.
This commit is contained in:
Tim Janik
2000-10-25 20:36:35 +00:00
committed by Tim Janik
parent b13320f78b
commit ee23c09e83
46 changed files with 5349 additions and 521 deletions

View File

@@ -1,3 +1,9 @@
Tue Oct 24 22:09:14 2000 Tim Janik <timj@gtk.org>
* glib-object.h: added newly added gobject/ headers.
* gmesage.c: print g_message() output to stderr instead of stdout.
2000-10-23 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* configure.in: Use one = instead of two, which is plainly wrong.

View File

@@ -1,3 +1,9 @@
Tue Oct 24 22:09:14 2000 Tim Janik <timj@gtk.org>
* glib-object.h: added newly added gobject/ headers.
* gmesage.c: print g_message() output to stderr instead of stdout.
2000-10-23 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* configure.in: Use one = instead of two, which is plainly wrong.

View File

@@ -1,3 +1,9 @@
Tue Oct 24 22:09:14 2000 Tim Janik <timj@gtk.org>
* glib-object.h: added newly added gobject/ headers.
* gmesage.c: print g_message() output to stderr instead of stdout.
2000-10-23 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* configure.in: Use one = instead of two, which is plainly wrong.

View File

@@ -1,3 +1,9 @@
Tue Oct 24 22:09:14 2000 Tim Janik <timj@gtk.org>
* glib-object.h: added newly added gobject/ headers.
* gmesage.c: print g_message() output to stderr instead of stdout.
2000-10-23 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* configure.in: Use one = instead of two, which is plainly wrong.

View File

@@ -1,3 +1,9 @@
Tue Oct 24 22:09:14 2000 Tim Janik <timj@gtk.org>
* glib-object.h: added newly added gobject/ headers.
* gmesage.c: print g_message() output to stderr instead of stdout.
2000-10-23 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* configure.in: Use one = instead of two, which is plainly wrong.

View File

@@ -1,3 +1,9 @@
Tue Oct 24 22:09:14 2000 Tim Janik <timj@gtk.org>
* glib-object.h: added newly added gobject/ headers.
* gmesage.c: print g_message() output to stderr instead of stdout.
2000-10-23 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* configure.in: Use one = instead of two, which is plainly wrong.

View File

@@ -1,3 +1,9 @@
Tue Oct 24 22:09:14 2000 Tim Janik <timj@gtk.org>
* glib-object.h: added newly added gobject/ headers.
* gmesage.c: print g_message() output to stderr instead of stdout.
2000-10-23 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* configure.in: Use one = instead of two, which is plainly wrong.

View File

@@ -1,3 +1,9 @@
Tue Oct 24 22:09:14 2000 Tim Janik <timj@gtk.org>
* glib-object.h: added newly added gobject/ headers.
* gmesage.c: print g_message() output to stderr instead of stdout.
2000-10-23 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* configure.in: Use one = instead of two, which is plainly wrong.

View File

@@ -1,9 +1,45 @@
<!-- ##### MACRO popen ##### -->
<para>
</para>
<!-- ##### MACRO pclose ##### -->
<para>
</para>
<!-- ##### MACRO lseek ##### -->
<para>
</para>
<!-- ##### MACRO getpid ##### -->
<para>
</para>
<!-- ##### MACRO close ##### -->
<para>
</para>
<!-- ##### MACRO fdopen ##### -->
<para>
</para>
<!-- ##### MACRO getcwd ##### -->
<para>
</para>
<!-- ##### USER_FUNCTION GSearchFunc ##### -->
<para>
Specifies the type of function passed to g_tree_search().
@@ -15,31 +51,13 @@ Specifies the type of function passed to g_tree_search().
desired key comes before @key in the sort order of the #GTree, or a positive
value if the desired key comes after @key.
<!-- ##### FUNCTION g_node_insert_after ##### -->
<para>
Inserts a #GNode beneath the parent after the given sibling.
</para>
@parent: the #GNode to place @node under.
@sibling: the sibling #GNode to place @node after. If sibling is NULL,
the node is inserted as the first child of @parent.
@node: the #GNode to insert.
@Returns: the inserted #GNode.
<!-- ##### FUNCTION g_convert_error_quark ##### -->
<para>
</para>
@Returns:
<!-- ##### MACRO write ##### -->
<para>
</para>
<!-- ##### MACRO pclose ##### -->
<!-- ##### MACRO access ##### -->
<para>
</para>
@@ -52,17 +70,18 @@ Turns the argument into a string literal by using the '#' stringizing operator.
@x: text to convert to a literal string.
<!-- ##### MACRO popen ##### -->
<!-- ##### MACRO read ##### -->
<para>
</para>
<!-- ##### MACRO access ##### -->
<!-- ##### FUNCTION g_convert_error_quark ##### -->
<para>
</para>
@Returns:
<!-- ##### MACRO open ##### -->
<para>
@@ -70,33 +89,3 @@ Turns the argument into a string literal by using the '#' stringizing operator.
</para>
<!-- ##### MACRO getpid ##### -->
<para>
</para>
<!-- ##### MACRO fdopen ##### -->
<para>
</para>
<!-- ##### MACRO close ##### -->
<para>
</para>
<!-- ##### MACRO getcwd ##### -->
<para>
</para>
<!-- ##### MACRO read ##### -->
<para>
</para>

View File

@@ -39,6 +39,20 @@ only one statement is expected by the compiler.
<!-- ##### MACRO G_BEGIN_DECLS ##### -->
<para>
</para>
<!-- ##### MACRO G_END_DECLS ##### -->
<para>
</para>
<!-- ##### MACRO G_N_ELEMENTS ##### -->
<para>
@@ -52,6 +66,7 @@ only one statement is expected by the compiler.
Portable way to copy <type>va_list</type> variables.
</para>
<!-- # Unused Parameters # -->
@ap1: the <type>va_list</type> variable to place a copy of @ap2 in.
@ap2: a <type>va_list</type>.
@@ -101,6 +116,13 @@ It avoids possible compiler warnings. See the GNU C documentation for details.
<!-- ##### MACRO G_GNUC_PURE ##### -->
<para>
</para>
<!-- ##### MACRO G_GNUC_PRINTF ##### -->
<para>
Expands to the GNU C format function attribute if the compiler is GNU C.

View File

@@ -98,6 +98,14 @@ If @mem is NULL it simply returns.
@mem: the memory to free.
<!-- ##### MACRO g_alloca ##### -->
<para>
</para>
@size:
<!-- ##### MACRO g_memmove ##### -->
<para>
Copies a block of memory @n bytes long, from @s to @d.

View File

@@ -40,22 +40,107 @@ produce highly random lower bits too, but it is common not to rely on
that, so choosing @a to be from 4 to 31 might be wise.
</para>
<!-- ##### SECTION See_Also ##### -->
<para>
</para>
<!-- ##### STRUCT GRand ##### -->
<para>
The #GRand struct is an opaque data structure. It should only be
accessed through the g_rand_* functions.
</para>
<!-- ##### FUNCTION g_rand_new_with_seed ##### -->
@seed:
@Returns:
<!-- ##### FUNCTION g_rand_new ##### -->
@Returns:
<!-- ##### FUNCTION g_rand_free ##### -->
@rand:
<!-- ##### FUNCTION g_rand_set_seed ##### -->
@rand:
@seed:
<!-- ##### FUNCTION g_rand_int ##### -->
@rand:
@Returns:
<!-- ##### FUNCTION g_rand_int_range ##### -->
@rand:
@min:
@max:
@Returns:
<!-- ##### FUNCTION g_rand_double ##### -->
@rand:
@Returns:
<!-- ##### FUNCTION g_rand_double_range ##### -->
@rand:
@min:
@max:
@Returns:
<!-- ##### FUNCTION g_random_set_seed ##### -->
@seed:
<!-- ##### FUNCTION g_random_int ##### -->
@Returns:
<!-- ##### FUNCTION g_random_int_range ##### -->
@min:
@max:
@Returns:
<!-- ##### FUNCTION g_random_double ##### -->
@Returns:
<!-- ##### FUNCTION g_random_double_range ##### -->
@min:
@max:
@Returns:

View File

@@ -113,6 +113,18 @@ the node is inserted as the last child of @parent.
@Returns: the inserted #GNode.
<!-- ##### FUNCTION g_node_insert_after ##### -->
<para>
Inserts a #GNode beneath the parent after the given sibling.
</para>
@parent: the #GNode to place @node under.
@sibling: the sibling #GNode to place @node after. If sibling is NULL,
the node is inserted as the first child of @parent.
@node: the #GNode to insert.
@Returns: the inserted #GNode.
<!-- ##### MACRO g_node_append ##### -->
<para>
Inserts a #GNode as the last child of the given parent.

View File

@@ -80,9 +80,9 @@ GType
@G_TYPE_DOUBLE:
@G_TYPE_STRING:
@G_TYPE_PARAM:
@G_TYPE_BOXED:
@G_TYPE_POINTER:
@G_TYPE_OBJECT:
@G_TYPE_GTK_BOXED:
@G_TYPE_GTK_POINTER:
@G_TYPE_GTK_SIGNAL:
@G_TYPE_BSE_PROCEDURE:
@G_TYPE_BSE_TIME:
@@ -213,6 +213,7 @@ GType
@value_init:
@value_free:
@value_copy:
@value_peek_pointer:
@collect_type:
@collect_value:
@lcopy_type:
@@ -571,10 +572,7 @@ GType
</para>
@G_TYPE_FLAG_CLASSED:
@G_TYPE_FLAG_INSTANTIATABLE:
@G_TYPE_FLAG_DERIVABLE:
@G_TYPE_FLAG_DEEP_DERIVABLE:
@G_TYPE_FLAG_ABSTRACT:
<!-- ##### FUNCTION g_type_register_static ##### -->
<para>
@@ -584,6 +582,7 @@ GType
@parent_type:
@type_name:
@info:
@flags:
@Returns:
@@ -595,6 +594,7 @@ GType
@parent_type:
@type_name:
@plugin:
@flags:
@Returns:
@@ -607,6 +607,7 @@ GType
@type_name:
@info:
@finfo:
@flags:
@Returns:

View File

@@ -20,13 +20,16 @@
#define __GLIB_GOBJECT_H__
/* topmost include file for GObject header files */
#include <gobject/gtype.h>
#include <gobject/gboxed.h>
#include <gobject/gbsearcharray.h>
#include <gobject/genums.h>
#include <gobject/gvalue.h>
#include <gobject/gvaluetypes.h>
#include <gobject/gobject.h>
#include <gobject/gparam.h>
#include <gobject/gparamspecs.h>
#include <gobject/gobject.h>
#include <gobject/gsignal.h>
#include <gobject/gtype.h>
#include <gobject/gvalue.h>
#include <gobject/gvaluetypes.h>
#endif /* __GLIB_GOBJECT_H__ */

164
glib/gbsearcharray.c Normal file
View File

@@ -0,0 +1,164 @@
/* GObject - GLib Type, Object, Parameter and Signal Library
* Copyright (C) 2000 Tim Janik
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#define G_IMPLEMENT_INLINES 1
#define __G_BSEARCHARRAY_C__
#include "gbsearcharray.h"
#include <string.h>
/* --- structures --- */
static inline guint
upper_power2 (guint number)
{
return number ? 1 << g_bit_storage (number - 1) : 0;
}
static inline gpointer
bsearch_array_insert (GBSearchArray *barray,
gconstpointer key_node,
gboolean replace)
{
gint sizeof_node;
guint8 *check;
sizeof_node = barray->sizeof_node;
if (barray->n_nodes == 0)
{
guint new_size = barray->sizeof_node;
if (barray->flags & G_BSEARCH_ALIGN_POWER2)
new_size = upper_power2 (new_size);
barray->nodes = g_realloc (barray->nodes, new_size);
barray->n_nodes = 1;
check = barray->nodes;
replace = TRUE;
}
else
{
GBSearchCompareFunc cmp_func = barray->cmp_func;
guint n_nodes = barray->n_nodes;
guint8 *nodes = barray->nodes;
gint cmp;
guint i;
nodes -= sizeof_node;
do
{
i = (n_nodes + 1) >> 1;
check = nodes + i * sizeof_node;
cmp = cmp_func (key_node, check);
if (cmp > 0)
{
n_nodes -= i;
nodes = check;
}
else if (cmp < 0)
n_nodes = i - 1;
else /* if (cmp == 0) */
goto SKIP_GROW;
}
while (n_nodes);
/* grow */
if (cmp > 0)
check += sizeof_node;
i = (check - ((guint8*) barray->nodes)) / sizeof_node;
n_nodes = barray->n_nodes++;
if (barray->flags & G_BSEARCH_ALIGN_POWER2)
{
guint new_size = upper_power2 (barray->n_nodes * sizeof_node);
guint old_size = upper_power2 (n_nodes * sizeof_node);
if (new_size != old_size)
barray->nodes = g_realloc (barray->nodes, new_size);
}
else
barray->nodes = g_realloc (barray->nodes, barray->n_nodes * sizeof_node);
check = barray->nodes + i * sizeof_node;
g_memmove (check + sizeof_node, check, (n_nodes - i) * sizeof_node);
replace = TRUE;
SKIP_GROW:
}
if (replace)
memcpy (check, key_node, sizeof_node);
return check;
}
gpointer
g_bsearch_array_insert (GBSearchArray *barray,
gconstpointer key_node,
gboolean replace_existing)
{
g_return_val_if_fail (barray != NULL, NULL);
g_return_val_if_fail (key_node != NULL, NULL);
return bsearch_array_insert (barray, key_node, replace_existing);
}
void
g_bsearch_array_remove_node (GBSearchArray *barray,
gpointer _node_in_array)
{
guint8 *nodes, *bound, *node_in_array = _node_in_array;
guint old_size;
g_return_if_fail (barray != NULL);
nodes = barray->nodes;
old_size = barray->sizeof_node;
old_size *= barray->n_nodes; /* beware of int widths */
bound = nodes + old_size;
g_return_if_fail (node_in_array >= nodes && node_in_array < bound);
bound -= barray->sizeof_node;
barray->n_nodes -= 1;
g_memmove (node_in_array, node_in_array + barray->sizeof_node, (bound - node_in_array) / barray->sizeof_node);
if ((barray->flags & G_BSEARCH_DEFER_SHRINK) == 0)
{
guint new_size = bound - nodes; /* old_size - barray->sizeof_node */
if (barray->flags & G_BSEARCH_ALIGN_POWER2)
{
new_size = upper_power2 (new_size);
old_size = upper_power2 (old_size);
if (old_size != new_size)
barray->nodes = g_realloc (barray->nodes, new_size);
}
else
barray->nodes = g_realloc (barray->nodes, new_size);
}
}
void
g_bsearch_array_remove (GBSearchArray *barray,
gconstpointer key_node)
{
gpointer node_in_array;
g_return_if_fail (barray != NULL);
node_in_array = g_bsearch_array_lookup (barray, key_node);
if (!node_in_array)
g_warning (G_STRLOC ": unable to remove unexistant node");
else
g_bsearch_array_remove_node (barray, node_in_array);
}

134
glib/gbsearcharray.h Normal file
View File

@@ -0,0 +1,134 @@
/* GObject - GLib Type, Object, Parameter and Signal Library
* Copyright (C) 2000 Tim Janik
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* gbsearcharray.h: binary searchable sorted array maintenance
*/
#ifndef __G_BSEARCH_ARRAY_H__
#define __G_BSEARCH_ARRAY_H__
#include <gobject/gtype.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* helper macro to avoid signed overflow for value comparisions */
#define G_BSEARCH_ARRAY_CMP(v1,v2) ((v1) < (v2) ? -1 : (v1) > (v2) ? 1 : 0)
/* --- typedefs --- */
typedef struct _GBSearchArray GBSearchArray;
typedef gint (*GBSearchCompareFunc) (gconstpointer bsearch_node1,
gconstpointer bsearch_node2);
typedef enum
{
G_BSEARCH_ALIGN_POWER2 = 1 << 0,
G_BSEARCH_DEFER_SHRINK = 1 << 1
} GBSearchFlags;
/* --- structures --- */
struct _GBSearchArray
{
GBSearchCompareFunc cmp_func;
guint16 sizeof_node;
guint16 flags;
guint n_nodes;
gpointer nodes;
};
/* --- prototypes --- */
gpointer g_bsearch_array_insert (GBSearchArray *barray,
gconstpointer key_node,
gboolean replace_existing);
void g_bsearch_array_remove (GBSearchArray *barray,
gconstpointer key_node);
void g_bsearch_array_remove_node (GBSearchArray *barray,
gpointer node_in_array);
G_INLINE_FUNC
gpointer g_bsearch_array_lookup (GBSearchArray *barray,
gconstpointer key_node);
G_INLINE_FUNC
gpointer g_bsearch_array_get_nth (GBSearchArray *barray,
guint n);
/* --- implementation details --- */
#if defined (G_CAN_INLINE) || defined (__G_BSEARCHARRAY_C__)
G_INLINE_FUNC gpointer
g_bsearch_array_lookup (GBSearchArray *barray,
gconstpointer key_node)
{
if (barray->n_nodes > 0)
{
GBSearchCompareFunc cmp_func = barray->cmp_func;
gint sizeof_node = barray->sizeof_node;
guint n_nodes = barray->n_nodes;
guint8 *nodes = barray->nodes;
nodes -= sizeof_node;
do
{
guint8 *check;
guint i;
register gint cmp;
i = (n_nodes + 1) >> 1;
check = nodes + i * sizeof_node;
cmp = cmp_func (key_node, check);
if (cmp == 0)
return check;
else if (cmp > 0)
{
n_nodes -= i;
nodes = check;
}
else /* if (cmp < 0) */
n_nodes = i - 1;
}
while (n_nodes);
}
return NULL;
}
G_INLINE_FUNC gpointer
g_bsearch_array_get_nth (GBSearchArray *barray,
guint n)
{
if (n < barray->n_nodes)
{
guint8 *nodes = barray->nodes;
return nodes + n * barray->sizeof_node;
}
else
return NULL;
}
#endif /* G_CAN_INLINE && __G_BSEARCHARRAY_C__ */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __G_BSEARCH_ARRAY_H__ */

View File

@@ -20,13 +20,16 @@
#define __GLIB_GOBJECT_H__
/* topmost include file for GObject header files */
#include <gobject/gtype.h>
#include <gobject/gboxed.h>
#include <gobject/gbsearcharray.h>
#include <gobject/genums.h>
#include <gobject/gvalue.h>
#include <gobject/gvaluetypes.h>
#include <gobject/gobject.h>
#include <gobject/gparam.h>
#include <gobject/gparamspecs.h>
#include <gobject/gobject.h>
#include <gobject/gsignal.h>
#include <gobject/gtype.h>
#include <gobject/gvalue.h>
#include <gobject/gvaluetypes.h>
#endif /* __GLIB_GOBJECT_H__ */

View File

@@ -471,7 +471,7 @@ g_log_default_handler (const gchar *log_domain,
*/
fd = stdout;
#else
fd = (log_level >= G_LOG_LEVEL_MESSAGE) ? 1 : 2;
fd = (log_level > G_LOG_LEVEL_MESSAGE) ? 1 : 2;
#endif
g_mutex_lock (g_messages_lock);

View File

@@ -471,7 +471,7 @@ g_log_default_handler (const gchar *log_domain,
*/
fd = stdout;
#else
fd = (log_level >= G_LOG_LEVEL_MESSAGE) ? 1 : 2;
fd = (log_level > G_LOG_LEVEL_MESSAGE) ? 1 : 2;
#endif
g_mutex_lock (g_messages_lock);

View File

@@ -1,3 +1,86 @@
Wed Oct 25 20:27:02 2000 Tim Janik <timj@gtk.org>
* gtype.c (g_type_free_instance): for the moment, freeing object
structures will fill their memory portion with 0xAA. there's a
FIXME there, remove this line at a later point.
Tue Oct 24 23:10:26 2000 Tim Janik <timj@gtk.org>
* glib-genmarshal.1:
* glib-genmarshal.c: added publically installed marshaller generator.
* gtype.h: added G_TYPE_INSTANCE_GET_INTERFACE() to retrive a certain
interface VTable from instances.
Mon Oct 23 08:28:15 2000 Tim Janik <timj@gtk.org>
* gobject.[hc]: new functions for closure maintenance:
(g_object_watch_closure): maintain validity of the object and
the closure for objects that are used as data part of a closure.
(g_cclosure_new_object): convenience function to create C closures
that have an object as data argument.
(g_closure_new_object): convenience function to create closures
that have an object as data argument.
* gclosure.[hc]: implementation of GClosure mechanism.
a closure is basically an encapsulation of a callback function
and its environment. ideally, most places supporting callback
functions will simply take a GClosure* pointer and thus unify
callback environments wrg destroy notification etc.
GClosure provides destroy notifiers for arbitrary data pointers,
reference counting, invalidation notification (it can be invalidated
which is merely a deactivate state) and a marshallinbg abstraction.
GCClosure is also provided in these files, they present a specialized
GClosure implementation for C language callbacks.
* genum.c: macro cleanups.
* gboxed.[hc]: new files, for boxed type abstraction.
(g_boxed_copy): copy a boxed structure
(g_boxed_free): free a boxed structure
(g_value_set_boxed):
(g_value_get_boxed): standard GValue functions for boxed types
(g_boxed_type_register_static): convenience function for easy
introduction of new G_TYPE_BOXED derivatives.
* gparam.[hc]: introduced g_param_type_register_static(), a short hand
for creation of new GParamSpec derived types.
* gtype.[hc]: many fixes, introduced ability to flag individual
type nodes as ABSTRACT upon registration, added value_peek_pointer()
to the value table to peek at GValue contents as a pointer for types
that support this. fixed up GValue checks.
* gvalue.[hc]: added g_value_fits_pointer() and g_value_get_as_pointer()
to peek at the value contents as pointer.
* *.[hc]: adaptions to type macro fixes and changes in the type
registration API.
* many const corrections over the place.
Sat Oct 21 02:49:56 2000 Tim Janik <timj@gtk.org>
* gtype.c (g_type_conforms_to): this function basically behaves like
and is_a check, except that it _additionally_ features interfaces
for instantiatable types. enforce this in the second branch as well
(`type' conforms_to `type') even if `type' is not an interface type.
Fri Oct 20 15:31:04 2000 Tim Janik <timj@gtk.org>
* gvaluetypes.[hc]: added G_TYPE_POINTER implementation from jrb.
* gtype.[hc]:
* gobject.c:
* gvaluetypes.c: added GTypeValueTable.value_peek_pointer and
suitable implementations of this for G_TYPE_STRING, G_TYPE_OBJECT
and G_TYPE_POINTER.
Mon Aug 21 04:13:37 2000 Tim Janik <timj@gtk.org>
* gbsearcharray.[hc]: long standing needed generic implementation
of a binary searchable, sorted and dynamically sized array.
2000-10-15 Raja R Harinath <harinath@cs.umn.edu>
* Makefile.am (BUILT_EXTRA_DIST): New variable.
@@ -255,9 +338,5 @@ Sun Apr 2 04:54:36 2000 Tim Janik <timj@gtk.org>
* glib-genums.[hc]: enum/flags type implementation, based on
bseenum.[hc].
* glib-extra.[hc]: GLib additions, including 1.3 compatibility
routines and various other functions, from string manipulation
over list manipulation up to a unix signal GSource.
* glib-gtype.[hc]: GLib Type System implementation, heavily
based on BSE's dynamic type system.

View File

@@ -3,7 +3,8 @@
#
## Process this file with automake to produce Makefile.in
INCLUDES = -I$(top_srcdir) -I$(top_builddir) -I. @GLIB_DEBUG_FLAGS@
SUBDIRS =
INCLUDES = -I$(top_srcdir) -I$(top_builddir) @GLIB_DEBUG_FLAGS@
# libraries to compile and install
lib_LTLIBRARIES = libgobject-1.3.la
@@ -22,28 +23,38 @@ libgobject_1_3_la_LIBADD = # $(libglib)
# setup source file variables
#
# GObject header files for public installation (non-generated)
gobject_public_h_sources = \
gvalue.h \
gvaluetypes.h \
gparam.h \
gparamspecs.h \
gobject_public_h_sources = @STRIP_BEGIN@ \
gboxed.h \
gbsearcharray.h \
gclosure.h \
genums.h \
gobject.h \
gparam.h \
gparamspecs.h \
gsignal.h \
gtype.h \
gvaluecollector.h
gvalue.h \
gvaluecollector.h \
gvaluetypes.h \
@STRIP_END@
# private GObject header files
gobject_private_h_sources =
# GObject C sources to build the library from
gobject_c_sources = \
gvalue.c \
gvaluetypes.c \
gparam.c \
gparamspecs.c \
gobject_c_sources = @STRIP_BEGIN@ \
gboxed.c \
gbsearcharray.c \
gclosure.c \
genums.c \
gobject.c \
gtype.c
gparam.c \
gparamspecs.c \
gsignal.c \
gtype.c \
gvalue.c \
gvaluetypes.c \
@STRIP_END@
# non-header sources (headers should be specified in the above variables)
# that don't serve as direct make target sources, i.e. they don't have
@@ -66,12 +77,19 @@ EXTRA_DIST += $(gobject_extra_sources)
#
# programs to compile and install
#
bin_PROGRAMS = gobject-query
bin_PROGRAMS = gobject-query glib-genmarshal
# source files
gobject_query_SOURCES = gobject-query.c
glib_genmarshal_SOURCES = glib-genmarshal.c
# link programs against libgobject
progs_LDADD = ../libglib-1.3.la libgobject-1.3.la
gobject_query_LDADD = $(progs_LDADD)
glib_genmarshal_LDADD = $(progs_LDADD)
#
# manual pages to install
#
man_MANS = glib-genmarshal.1
#
# auxillary files

316
gobject/gboxed.c Normal file
View File

@@ -0,0 +1,316 @@
/* GObject - GLib Type, Object, Parameter and Signal Library
* Copyright (C) 2000 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "gboxed.h"
#include "gbsearcharray.h"
#include "gvalue.h"
#include "gvaluecollector.h"
/* --- typedefs & structures --- */
typedef struct
{
GType type;
GBoxedCopyFunc copy;
GBoxedFreeFunc free;
} BoxedNode;
/* --- prototypes --- */
static gint boxed_nodes_cmp (gconstpointer p1,
gconstpointer p2);
/* --- variables --- */
static GBSearchArray boxed_bsa = { boxed_nodes_cmp, sizeof (BoxedNode), 0, 0, NULL };
/* --- functions --- */
static gint
boxed_nodes_cmp (gconstpointer p1,
gconstpointer p2)
{
const BoxedNode *node1 = p1, *node2 = p2;
return G_BSEARCH_ARRAY_CMP (node1->type, node2->type);
}
void
g_boxed_type_init (void) /* sync with gtype.c */
{
static const GTypeInfo info = {
0, /* class_size */
NULL, /* base_init */
NULL, /* base_destroy */
NULL, /* class_init */
NULL, /* class_destroy */
NULL, /* class_data */
0, /* instance_size */
0, /* n_preallocs */
NULL, /* instance_init */
NULL, /* value_table */
};
const GTypeFundamentalInfo finfo = { G_TYPE_FLAG_DERIVABLE, };
GType type;
/* G_TYPE_BOXED
*/
type = g_type_register_fundamental (G_TYPE_BOXED, "GBoxed", &info, &finfo, G_TYPE_FLAG_ABSTRACT);
g_assert (type == G_TYPE_BOXED);
}
static void
boxed_proxy_value_init (GValue *value)
{
value->data[0].v_pointer = 0;
}
static void
boxed_proxy_value_free (GValue *value)
{
if (value->data[0].v_pointer)
{
BoxedNode key, *node;
key.type = value->g_type;
node = g_bsearch_array_lookup (&boxed_bsa, &key);
node->free (value->data[0].v_pointer);
}
}
static void
boxed_proxy_value_copy (const GValue *src_value,
GValue *dest_value)
{
if (src_value->data[0].v_pointer)
{
BoxedNode key, *node;
key.type = src_value->g_type;
node = g_bsearch_array_lookup (&boxed_bsa, &key);
dest_value->data[0].v_pointer = node->copy (src_value->data[0].v_pointer);
}
else
dest_value->data[0].v_pointer = src_value->data[0].v_pointer;
}
static gpointer
boxed_proxy_value_peek_pointer (const GValue *value)
{
return value->data[0].v_pointer;
}
static gchar*
boxed_proxy_collect_value (GValue *value,
guint nth_value,
GType *collect_type,
GTypeCValue *collect_value)
{
BoxedNode key, *node;
key.type = value->g_type;
node = g_bsearch_array_lookup (&boxed_bsa, &key);
value->data[0].v_pointer = node->copy (collect_value->v_pointer);
*collect_type = 0;
return NULL;
}
static gchar*
boxed_proxy_lcopy_value (const GValue *value,
guint nth_value,
GType *collect_type,
GTypeCValue *collect_value)
{
BoxedNode key, *node;
gpointer *boxed_p = collect_value->v_pointer;
if (!boxed_p)
return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
key.type = value->g_type;
node = g_bsearch_array_lookup (&boxed_bsa, &key);
*boxed_p = node->copy (value->data[0].v_pointer);
*collect_type = 0;
return NULL;
}
GType
g_boxed_type_register_static (const gchar *name,
GBoxedCopyFunc boxed_copy,
GBoxedFreeFunc boxed_free)
{
static const GTypeValueTable vtable = {
boxed_proxy_value_init,
boxed_proxy_value_free,
boxed_proxy_value_copy,
boxed_proxy_value_peek_pointer,
G_VALUE_COLLECT_POINTER,
boxed_proxy_collect_value,
G_VALUE_COLLECT_POINTER,
boxed_proxy_lcopy_value,
};
static const GTypeInfo type_info = {
0, /* class_size */
NULL, /* base_init */
NULL, /* base_finalize */
NULL, /* class_init */
NULL, /* class_finalize */
NULL, /* class_data */
0, /* instance_size */
0, /* n_preallocs */
NULL, /* instance_init */
&vtable, /* value_table */
};
GType type;
g_return_val_if_fail (name != NULL, 0);
g_return_val_if_fail (boxed_copy != NULL, 0);
g_return_val_if_fail (boxed_free != NULL, 0);
g_return_val_if_fail (g_type_from_name (name) == 0, 0);
type = g_type_register_static (G_TYPE_BOXED, name, &type_info, 0);
/* install proxy functions upon successfull registration */
if (type)
{
BoxedNode key;
key.type = type;
key.copy = boxed_copy;
key.free = boxed_free;
g_bsearch_array_insert (&boxed_bsa, &key, TRUE);
}
return type;
}
GBoxed*
g_boxed_copy (GType boxed_type,
gpointer src_boxed)
{
GTypeValueTable *value_table;
g_return_val_if_fail (G_TYPE_IS_BOXED (boxed_type), NULL);
g_return_val_if_fail (G_TYPE_IS_ABSTRACT (boxed_type) == FALSE, NULL);
g_return_val_if_fail (src_boxed != NULL, NULL);
value_table = g_type_value_table_peek (boxed_type);
if (!value_table)
g_return_val_if_fail (G_TYPE_IS_VALUE_TYPE (boxed_type), NULL);
/* check if our proxying implementation is used, we can short-cut here */
if (value_table->value_copy == boxed_proxy_value_copy)
{
BoxedNode key, *node;
key.type = boxed_type;
node = g_bsearch_array_lookup (&boxed_bsa, &key);
src_boxed = node->copy (src_boxed);
}
else
{
GValue src_value, dest_value;
/* we heavil rely on the gvalue.c implementation here */
memset (&src_value.data, 0, sizeof (src_value.data));
memset (&dest_value.data, 0, sizeof (dest_value.data));
dest_value.g_type = boxed_type;
src_value.g_type = boxed_type;
src_value.data[0].v_pointer = src_boxed;
value_table->value_copy (&src_value, &dest_value);
if (dest_value.data[1].v_ulong ||
dest_value.data[2].v_ulong ||
dest_value.data[3].v_ulong)
g_warning ("the copy_value() implementation of type `%s' seems to make use of reserved GValue fields",
g_type_name (boxed_type));
src_boxed = dest_value.data[0].v_pointer;
}
return src_boxed;
}
void
g_boxed_free (GType boxed_type,
gpointer boxed)
{
GTypeValueTable *value_table;
g_return_if_fail (G_TYPE_IS_BOXED (boxed_type));
g_return_if_fail (G_TYPE_IS_ABSTRACT (boxed_type) == FALSE);
g_return_if_fail (boxed != NULL);
value_table = g_type_value_table_peek (boxed_type);
if (!value_table)
g_return_if_fail (G_TYPE_IS_VALUE_TYPE (boxed_type));
/* check if our proxying implementation is used, we can short-cut here */
if (value_table->value_free == boxed_proxy_value_free)
{
BoxedNode key, *node;
key.type = boxed_type;
node = g_bsearch_array_lookup (&boxed_bsa, &key);
node->free (boxed);
}
else
{
GValue value;
/* we heavil rely on the gvalue.c implementation here */
memset (&value.data, 0, sizeof (value.data));
value.g_type = boxed_type;
value.data[0].v_pointer = boxed;
value_table->value_free (&value);
}
}
void
g_value_set_boxed (GValue *value,
gpointer boxed)
{
g_return_if_fail (G_IS_VALUE_BOXED (value));
g_return_if_fail (G_TYPE_IS_VALUE (G_VALUE_TYPE (value)));
if (value->data[0].v_pointer)
g_boxed_free (G_VALUE_TYPE (value), value->data[0].v_pointer);
value->data[0].v_pointer = boxed ? g_boxed_copy (G_VALUE_TYPE (value), boxed) : NULL;
}
gpointer
g_value_get_boxed (GValue *value)
{
g_return_val_if_fail (G_IS_VALUE_BOXED (value), NULL);
g_return_val_if_fail (G_TYPE_IS_VALUE (G_VALUE_TYPE (value)), NULL);
return value->data[0].v_pointer;
}
gpointer
g_value_dup_boxed (GValue *value)
{
g_return_val_if_fail (G_IS_VALUE_BOXED (value), NULL);
g_return_val_if_fail (G_TYPE_IS_VALUE (G_VALUE_TYPE (value)), NULL);
return value->data[0].v_pointer ? g_boxed_copy (G_VALUE_TYPE (value), value->data[0].v_pointer) : NULL;
}

64
gobject/gboxed.h Normal file
View File

@@ -0,0 +1,64 @@
/* GObject - GLib Type, Object, Parameter and Signal Library
* Copyright (C) 2000 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __G_BOXED_H__
#define __G_BOXED_H__
#include <gobject/gtype.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* --- type macros --- */
#define G_TYPE_IS_BOXED(type) (G_TYPE_FUNDAMENTAL (type) == G_TYPE_BOXED)
#define G_IS_VALUE_BOXED(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_BOXED))
/* --- typedefs --- */
typedef struct _GBoxed GBoxed;
typedef gpointer (*GBoxedCopyFunc) (gpointer boxed);
typedef void (*GBoxedFreeFunc) (gpointer boxed);
/* --- prototypes --- */
GBoxed* g_boxed_copy (GType boxed_type,
gpointer src_boxed);
void g_boxed_free (GType boxed_type,
gpointer boxed);
void g_value_set_boxed (GValue *value,
gpointer boxed);
gpointer g_value_get_boxed (GValue *value);
gpointer g_value_dup_boxed (GValue *value);
/* --- convenience --- */
GType g_boxed_type_register_static (const gchar *name,
GBoxedCopyFunc boxed_copy,
GBoxedFreeFunc boxed_free);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __G_BOXED_H__ */

164
gobject/gbsearcharray.c Normal file
View File

@@ -0,0 +1,164 @@
/* GObject - GLib Type, Object, Parameter and Signal Library
* Copyright (C) 2000 Tim Janik
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#define G_IMPLEMENT_INLINES 1
#define __G_BSEARCHARRAY_C__
#include "gbsearcharray.h"
#include <string.h>
/* --- structures --- */
static inline guint
upper_power2 (guint number)
{
return number ? 1 << g_bit_storage (number - 1) : 0;
}
static inline gpointer
bsearch_array_insert (GBSearchArray *barray,
gconstpointer key_node,
gboolean replace)
{
gint sizeof_node;
guint8 *check;
sizeof_node = barray->sizeof_node;
if (barray->n_nodes == 0)
{
guint new_size = barray->sizeof_node;
if (barray->flags & G_BSEARCH_ALIGN_POWER2)
new_size = upper_power2 (new_size);
barray->nodes = g_realloc (barray->nodes, new_size);
barray->n_nodes = 1;
check = barray->nodes;
replace = TRUE;
}
else
{
GBSearchCompareFunc cmp_func = barray->cmp_func;
guint n_nodes = barray->n_nodes;
guint8 *nodes = barray->nodes;
gint cmp;
guint i;
nodes -= sizeof_node;
do
{
i = (n_nodes + 1) >> 1;
check = nodes + i * sizeof_node;
cmp = cmp_func (key_node, check);
if (cmp > 0)
{
n_nodes -= i;
nodes = check;
}
else if (cmp < 0)
n_nodes = i - 1;
else /* if (cmp == 0) */
goto SKIP_GROW;
}
while (n_nodes);
/* grow */
if (cmp > 0)
check += sizeof_node;
i = (check - ((guint8*) barray->nodes)) / sizeof_node;
n_nodes = barray->n_nodes++;
if (barray->flags & G_BSEARCH_ALIGN_POWER2)
{
guint new_size = upper_power2 (barray->n_nodes * sizeof_node);
guint old_size = upper_power2 (n_nodes * sizeof_node);
if (new_size != old_size)
barray->nodes = g_realloc (barray->nodes, new_size);
}
else
barray->nodes = g_realloc (barray->nodes, barray->n_nodes * sizeof_node);
check = barray->nodes + i * sizeof_node;
g_memmove (check + sizeof_node, check, (n_nodes - i) * sizeof_node);
replace = TRUE;
SKIP_GROW:
}
if (replace)
memcpy (check, key_node, sizeof_node);
return check;
}
gpointer
g_bsearch_array_insert (GBSearchArray *barray,
gconstpointer key_node,
gboolean replace_existing)
{
g_return_val_if_fail (barray != NULL, NULL);
g_return_val_if_fail (key_node != NULL, NULL);
return bsearch_array_insert (barray, key_node, replace_existing);
}
void
g_bsearch_array_remove_node (GBSearchArray *barray,
gpointer _node_in_array)
{
guint8 *nodes, *bound, *node_in_array = _node_in_array;
guint old_size;
g_return_if_fail (barray != NULL);
nodes = barray->nodes;
old_size = barray->sizeof_node;
old_size *= barray->n_nodes; /* beware of int widths */
bound = nodes + old_size;
g_return_if_fail (node_in_array >= nodes && node_in_array < bound);
bound -= barray->sizeof_node;
barray->n_nodes -= 1;
g_memmove (node_in_array, node_in_array + barray->sizeof_node, (bound - node_in_array) / barray->sizeof_node);
if ((barray->flags & G_BSEARCH_DEFER_SHRINK) == 0)
{
guint new_size = bound - nodes; /* old_size - barray->sizeof_node */
if (barray->flags & G_BSEARCH_ALIGN_POWER2)
{
new_size = upper_power2 (new_size);
old_size = upper_power2 (old_size);
if (old_size != new_size)
barray->nodes = g_realloc (barray->nodes, new_size);
}
else
barray->nodes = g_realloc (barray->nodes, new_size);
}
}
void
g_bsearch_array_remove (GBSearchArray *barray,
gconstpointer key_node)
{
gpointer node_in_array;
g_return_if_fail (barray != NULL);
node_in_array = g_bsearch_array_lookup (barray, key_node);
if (!node_in_array)
g_warning (G_STRLOC ": unable to remove unexistant node");
else
g_bsearch_array_remove_node (barray, node_in_array);
}

134
gobject/gbsearcharray.h Normal file
View File

@@ -0,0 +1,134 @@
/* GObject - GLib Type, Object, Parameter and Signal Library
* Copyright (C) 2000 Tim Janik
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* gbsearcharray.h: binary searchable sorted array maintenance
*/
#ifndef __G_BSEARCH_ARRAY_H__
#define __G_BSEARCH_ARRAY_H__
#include <gobject/gtype.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* helper macro to avoid signed overflow for value comparisions */
#define G_BSEARCH_ARRAY_CMP(v1,v2) ((v1) < (v2) ? -1 : (v1) > (v2) ? 1 : 0)
/* --- typedefs --- */
typedef struct _GBSearchArray GBSearchArray;
typedef gint (*GBSearchCompareFunc) (gconstpointer bsearch_node1,
gconstpointer bsearch_node2);
typedef enum
{
G_BSEARCH_ALIGN_POWER2 = 1 << 0,
G_BSEARCH_DEFER_SHRINK = 1 << 1
} GBSearchFlags;
/* --- structures --- */
struct _GBSearchArray
{
GBSearchCompareFunc cmp_func;
guint16 sizeof_node;
guint16 flags;
guint n_nodes;
gpointer nodes;
};
/* --- prototypes --- */
gpointer g_bsearch_array_insert (GBSearchArray *barray,
gconstpointer key_node,
gboolean replace_existing);
void g_bsearch_array_remove (GBSearchArray *barray,
gconstpointer key_node);
void g_bsearch_array_remove_node (GBSearchArray *barray,
gpointer node_in_array);
G_INLINE_FUNC
gpointer g_bsearch_array_lookup (GBSearchArray *barray,
gconstpointer key_node);
G_INLINE_FUNC
gpointer g_bsearch_array_get_nth (GBSearchArray *barray,
guint n);
/* --- implementation details --- */
#if defined (G_CAN_INLINE) || defined (__G_BSEARCHARRAY_C__)
G_INLINE_FUNC gpointer
g_bsearch_array_lookup (GBSearchArray *barray,
gconstpointer key_node)
{
if (barray->n_nodes > 0)
{
GBSearchCompareFunc cmp_func = barray->cmp_func;
gint sizeof_node = barray->sizeof_node;
guint n_nodes = barray->n_nodes;
guint8 *nodes = barray->nodes;
nodes -= sizeof_node;
do
{
guint8 *check;
guint i;
register gint cmp;
i = (n_nodes + 1) >> 1;
check = nodes + i * sizeof_node;
cmp = cmp_func (key_node, check);
if (cmp == 0)
return check;
else if (cmp > 0)
{
n_nodes -= i;
nodes = check;
}
else /* if (cmp < 0) */
n_nodes = i - 1;
}
while (n_nodes);
}
return NULL;
}
G_INLINE_FUNC gpointer
g_bsearch_array_get_nth (GBSearchArray *barray,
guint n)
{
if (n < barray->n_nodes)
{
guint8 *nodes = barray->nodes;
return nodes + n * barray->sizeof_node;
}
else
return NULL;
}
#endif /* G_CAN_INLINE && __G_BSEARCHARRAY_C__ */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __G_BSEARCH_ARRAY_H__ */

534
gobject/gclosure.c Normal file
View File

@@ -0,0 +1,534 @@
/* GObject - GLib Type, Object, Parameter and Signal Library
* Copyright (C) 2000 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "gclosure.h"
#include "gvalue.h"
/* FIXME: need caching allocators
*/
#define CLOSURE_MAX_REF_COUNT ((1 << 15) - 1)
#define CLOSURE_MAX_N_GUARDS ((1 << 1) - 1)
#define CLOSURE_MAX_N_FNOTIFIERS ((1 << 2) - 1)
#define CLOSURE_MAX_N_INOTIFIERS ((1 << 8) - 1)
#define CLOSURE_N_MFUNCS(cl) ((cl)->meta_marshal + \
((cl)->n_guards << 1L))
#define CLOSURE_N_NOTIFIERS(cl) (CLOSURE_N_MFUNCS (cl) + \
(cl)->n_fnotifiers + \
(cl)->n_inotifiers)
enum {
FNOTIFY,
INOTIFY,
PRE_NOTIFY,
POST_NOTIFY
};
/* --- functions --- */
GClosure*
g_closure_new_simple (guint sizeof_closure,
gpointer data)
{
GClosure *closure;
g_return_val_if_fail (sizeof_closure >= sizeof (GClosure), NULL);
closure = g_malloc (sizeof_closure);
closure->ref_count = 1;
closure->meta_marshal = 0;
closure->n_guards = 0;
closure->n_fnotifiers = 0;
closure->n_inotifiers = 0;
closure->in_inotify = FALSE;
closure->floating = TRUE;
closure->derivative_flag = 0;
closure->in_marshal = FALSE;
closure->is_invalid = FALSE;
closure->marshal = NULL;
closure->data = data;
closure->notifiers = NULL;
memset (G_STRUCT_MEMBER_P (closure, sizeof (*closure)), 0, sizeof_closure - sizeof (*closure));
return closure;
}
static inline void
closure_invoke_notifiers (GClosure *closure,
guint notify_type)
{
/* notifier layout:
* meta_marshal n_guards n_guards n_fnotif. n_inotifiers
* ->[[meta_marshal][pre_guards][post_guards][fnotifers][inotifiers]]
*
* CLOSURE_N_MFUNCS(cl) = meta_marshal + n_guards + n_guards;
* CLOSURE_N_NOTIFIERS(cl) = CLOSURE_N_MFUNCS(cl) + n_fnotifiers + n_inotifiers
*
* constrains/catches:
* - closure->notifiers may be reloacted during callback
* - closure->n_fnotifiers and closure->n_inotifiers may change during callback
* - i.e. callbacks can be removed/added during invocation
* - have to prepare for callback removal during invocation (->marshal & ->data)
* - have to distinguish (->marshal & ->data) for INOTIFY/FNOTIFY (->in_inotify)
* + closure->n_guards is const during PRE_NOTIFY & POST_NOTIFY
* + closure->meta_marshal is const for all cases
* + none of the callbacks can cause recursion
* + closure->n_inotifiers is const 0 during FNOTIFY
*/
switch (notify_type)
{
GClosureNotifyData *ndata;
guint i, offs;
case FNOTIFY:
while (closure->n_fnotifiers)
{
register guint n = --closure->n_fnotifiers;
ndata = closure->notifiers + CLOSURE_N_MFUNCS (closure) + n;
closure->marshal = (gpointer) ndata->notify;
closure->data = ndata->data;
ndata->notify (ndata->data, closure);
}
closure->marshal = NULL;
closure->data = NULL;
break;
case INOTIFY:
closure->in_inotify = TRUE;
while (closure->n_inotifiers)
{
register guint n = --closure->n_inotifiers;
ndata = closure->notifiers + CLOSURE_N_MFUNCS (closure) + closure->n_fnotifiers + n;
closure->marshal = (gpointer) ndata->notify;
closure->data = ndata->data;
ndata->notify (ndata->data, closure);
}
closure->marshal = NULL;
closure->data = NULL;
closure->in_inotify = FALSE;
break;
case PRE_NOTIFY:
i = closure->n_guards;
offs = closure->meta_marshal;
while (i--)
{
ndata = closure->notifiers + offs + i;
ndata->notify (ndata->data, closure);
}
break;
case POST_NOTIFY:
i = closure->n_guards;
offs = closure->meta_marshal + i;
while (i--)
{
ndata = closure->notifiers + offs + i;
ndata->notify (ndata->data, closure);
}
break;
}
}
void
g_closure_set_meta_marshal (GClosure *closure,
gpointer marshal_data,
GClosureMarshal meta_marshal)
{
GClosureNotifyData *notifiers;
guint n;
g_return_if_fail (closure != NULL);
g_return_if_fail (meta_marshal != NULL);
g_return_if_fail (closure->is_invalid == FALSE);
g_return_if_fail (closure->in_marshal == FALSE);
g_return_if_fail (closure->meta_marshal == FALSE);
n = CLOSURE_N_NOTIFIERS (closure);
notifiers = closure->notifiers;
closure->notifiers = g_renew (GClosureNotifyData, NULL, CLOSURE_N_NOTIFIERS (closure) + 1);
closure->notifiers[0].data = marshal_data;
closure->notifiers[0].notify = (GClosureNotify) meta_marshal;
if (notifiers)
{
/* usually the meta marshal will be setup right after creation, so the
* memcpy() should be rare-case scenario
*/
memcpy (closure->notifiers + 1, notifiers, CLOSURE_N_NOTIFIERS (closure) * sizeof (notifiers[0]));
g_free (notifiers);
}
closure->meta_marshal = 1;
}
void
g_closure_add_marshal_guards (GClosure *closure,
gpointer pre_marshal_data,
GClosureNotify pre_marshal_notify,
gpointer post_marshal_data,
GClosureNotify post_marshal_notify)
{
guint i;
g_return_if_fail (closure != NULL);
g_return_if_fail (pre_marshal_notify != NULL);
g_return_if_fail (post_marshal_notify != NULL);
g_return_if_fail (closure->is_invalid == FALSE);
g_return_if_fail (closure->in_marshal == FALSE);
g_return_if_fail (closure->n_guards < CLOSURE_MAX_N_GUARDS);
closure->notifiers = g_renew (GClosureNotifyData, closure->notifiers, CLOSURE_N_NOTIFIERS (closure) + 2);
if (closure->n_inotifiers)
closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
closure->n_fnotifiers +
closure->n_inotifiers + 1)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
closure->n_fnotifiers + 0)];
if (closure->n_inotifiers > 1)
closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
closure->n_fnotifiers +
closure->n_inotifiers)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
closure->n_fnotifiers + 1)];
if (closure->n_fnotifiers)
closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
closure->n_fnotifiers + 1)] = closure->notifiers[CLOSURE_N_MFUNCS (closure) + 0];
if (closure->n_fnotifiers > 1)
closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
closure->n_fnotifiers)] = closure->notifiers[CLOSURE_N_MFUNCS (closure) + 1];
if (closure->n_guards)
closure->notifiers[(closure->meta_marshal +
closure->n_guards +
closure->n_guards + 1)] = closure->notifiers[closure->meta_marshal + closure->n_guards];
i = closure->n_guards++;
closure->notifiers[closure->meta_marshal + i].data = pre_marshal_data;
closure->notifiers[closure->meta_marshal + i].notify = pre_marshal_notify;
closure->notifiers[closure->meta_marshal + i + i].data = post_marshal_data;
closure->notifiers[closure->meta_marshal + i + i].notify = post_marshal_notify;
}
void
g_closure_add_fnotify (GClosure *closure,
gpointer notify_data,
GClosureNotify notify_func)
{
guint i;
g_return_if_fail (closure != NULL);
g_return_if_fail (notify_func != NULL);
g_return_if_fail (closure->n_fnotifiers < CLOSURE_MAX_N_FNOTIFIERS);
closure->notifiers = g_renew (GClosureNotifyData, closure->notifiers, CLOSURE_N_NOTIFIERS (closure) + 1);
if (closure->n_inotifiers)
closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
closure->n_fnotifiers +
closure->n_inotifiers)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
closure->n_fnotifiers + 0)];
i = CLOSURE_N_MFUNCS (closure) + closure->n_fnotifiers++;
closure->notifiers[i].data = notify_data;
closure->notifiers[i].notify = notify_func;
}
void
g_closure_add_inotify (GClosure *closure,
gpointer notify_data,
GClosureNotify notify_func)
{
guint i;
g_return_if_fail (closure != NULL);
g_return_if_fail (notify_func != NULL);
g_return_if_fail (closure->is_invalid == FALSE);
g_return_if_fail (closure->n_inotifiers < CLOSURE_MAX_N_INOTIFIERS);
closure->notifiers = g_renew (GClosureNotifyData, closure->notifiers, CLOSURE_N_NOTIFIERS (closure) + 1);
i = CLOSURE_N_MFUNCS (closure) + closure->n_fnotifiers + closure->n_inotifiers++;
closure->notifiers[i].data = notify_data;
closure->notifiers[i].notify = notify_func;
}
static inline gboolean
closure_try_remove_inotify (GClosure *closure,
gpointer notify_data,
GClosureNotify notify_func)
{
GClosureNotifyData *ndata, *nlast;
nlast = closure->notifiers + CLOSURE_N_NOTIFIERS (closure) - 1;
for (ndata = nlast + 1 - closure->n_inotifiers; ndata <= nlast; ndata++)
if (ndata->notify == notify_func && ndata->data == notify_data)
{
closure->n_inotifiers -= 1;
if (ndata < nlast)
*ndata = *nlast;
return TRUE;
}
return FALSE;
}
static inline gboolean
closure_try_remove_fnotify (GClosure *closure,
gpointer notify_data,
GClosureNotify notify_func)
{
GClosureNotifyData *ndata, *nlast;
nlast = closure->notifiers + CLOSURE_N_NOTIFIERS (closure) - closure->n_inotifiers - 1;
for (ndata = nlast + 1 - closure->n_fnotifiers; ndata <= nlast; ndata++)
if (ndata->notify == notify_func && ndata->data == notify_data)
{
closure->n_fnotifiers -= 1;
if (ndata < nlast)
*ndata = *nlast;
if (closure->n_inotifiers)
closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
closure->n_fnotifiers)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
closure->n_fnotifiers +
closure->n_inotifiers)];
return TRUE;
}
return FALSE;
}
GClosure*
g_closure_ref (GClosure *closure)
{
g_return_val_if_fail (closure != NULL, NULL);
g_return_val_if_fail (closure->ref_count > 0, NULL);
g_return_val_if_fail (closure->ref_count < CLOSURE_MAX_REF_COUNT, NULL);
/* floating is basically a kludge to avoid creating closures
* with a ref_count of 0. so the first one doing _ref() will
* own the closure's initial ref_count
*/
if (closure->floating)
closure->floating = FALSE;
else
closure->ref_count += 1;
return closure;
}
void
g_closure_invalidate (GClosure *closure)
{
g_return_if_fail (closure != NULL);
if (!closure->is_invalid)
{
closure->ref_count += 1; /* preserve floating flag */
closure->is_invalid = TRUE;
closure_invoke_notifiers (closure, INOTIFY);
g_closure_unref (closure);
}
}
void
g_closure_unref (GClosure *closure)
{
g_return_if_fail (closure != NULL);
g_return_if_fail (closure->ref_count > 0);
if (closure->ref_count == 1) /* last unref, invalidate first */
g_closure_invalidate (closure);
closure->ref_count -= 1;
if (closure->ref_count == 0)
{
closure_invoke_notifiers (closure, FNOTIFY);
g_free (closure);
}
}
void
g_closure_remove_inotify (GClosure *closure,
gpointer notify_data,
GClosureNotify notify_func)
{
g_return_if_fail (closure != NULL);
g_return_if_fail (notify_func != NULL);
if (closure->is_invalid && closure->in_inotify && /* account removal of notify_func() while its called */
((gpointer) closure->marshal) == ((gpointer) notify_func) && closure->data == notify_data)
closure->marshal = NULL;
else if (!closure_try_remove_inotify (closure, notify_data, notify_func))
g_warning (G_STRLOC ": unable to remove uninstalled invalidation notifier: %p (%p)",
notify_func, notify_data);
}
void
g_closure_remove_fnotify (GClosure *closure,
gpointer notify_data,
GClosureNotify notify_func)
{
g_return_if_fail (closure != NULL);
g_return_if_fail (notify_func != NULL);
if (closure->is_invalid && !closure->in_inotify && /* account removal of notify_func() while its called */
((gpointer) closure->marshal) == ((gpointer) notify_func) && closure->data == notify_data)
closure->marshal = NULL;
else if (!closure_try_remove_fnotify (closure, notify_data, notify_func))
g_warning (G_STRLOC ": unable to remove uninstalled finalization notifier: %p (%p)",
notify_func, notify_data);
}
void
g_closure_invoke (GClosure *closure,
guint invocation_hint,
GValue /*out*/ *return_value,
guint n_param_values,
const GValue *param_values)
{
g_return_if_fail (closure != NULL);
g_return_if_fail (closure->marshal || closure->meta_marshal);
if (!closure->is_invalid)
{
GClosureMarshal marshal;
gpointer marshal_data;
gboolean in_marshal = closure->in_marshal;
closure->ref_count += 1; /* preserve floating flag */
closure->in_marshal = TRUE;
if (closure->meta_marshal)
{
marshal_data = closure->notifiers[0].data;
marshal = (GClosureMarshal) closure->notifiers[0].notify;
}
else
{
marshal_data = NULL;
marshal = closure->marshal;
}
if (!in_marshal)
closure_invoke_notifiers (closure, PRE_NOTIFY);
marshal (closure, invocation_hint,
return_value,
n_param_values, param_values,
marshal_data);
if (!in_marshal)
closure_invoke_notifiers (closure, POST_NOTIFY);
closure->in_marshal = in_marshal;
g_closure_unref (closure);
}
}
void
g_closure_set_marshal (GClosure *closure,
GClosureMarshal marshal)
{
g_return_if_fail (closure != NULL);
g_return_if_fail (marshal != NULL);
if (closure->marshal && closure->marshal != marshal)
g_warning ("attempt to override closure->marshal (%p) with new marshal (%p)",
closure->marshal, marshal);
else
closure->marshal = marshal;
}
GClosure*
g_cclosure_new (GCallback callback_func,
gpointer user_data,
GClosureNotify destroy_data)
{
GClosure *closure;
g_return_val_if_fail (callback_func != NULL, NULL);
closure = g_closure_new_simple (sizeof (GCClosure), user_data);
if (destroy_data)
g_closure_add_fnotify (closure, user_data, destroy_data);
((GCClosure*) closure)->callback = callback_func;
return closure;
}
GClosure*
g_cclosure_new_swap (GCallback callback_func,
gpointer user_data,
GClosureNotify destroy_data)
{
GClosure *closure;
g_return_val_if_fail (callback_func != NULL, NULL);
closure = g_closure_new_simple (sizeof (GCClosure), user_data);
if (destroy_data)
g_closure_add_fnotify (closure, user_data, destroy_data);
((GCClosure*) closure)->callback = callback_func;
closure->derivative_flag = TRUE;
return closure;
}
static void
g_type_class_meta_marshal (GClosure *closure,
guint invocation_hint,
GValue /*out*/ *return_value,
guint n_param_values,
const GValue *param_values,
gpointer marshal_data)
{
GTypeClass *class;
gpointer callback;
/* GType itype = GPOINTER_TO_UINT (closure->data); */
guint offset = GPOINTER_TO_UINT (marshal_data);
class = G_TYPE_INSTANCE_GET_CLASS (g_value_get_as_pointer (param_values + 0), itype, GTypeClass);
callback = G_STRUCT_MEMBER (gpointer, class, offset);
if (callback)
closure->marshal (closure, invocation_hint, return_value,
n_param_values, param_values, callback);
}
static void
g_type_iface_meta_marshal (GClosure *closure,
guint invocation_hint,
GValue /*out*/ *return_value,
guint n_param_values,
const GValue *param_values,
gpointer marshal_data)
{
GTypeClass *class;
gpointer callback;
GType itype = GPOINTER_TO_UINT (closure->data);
guint offset = GPOINTER_TO_UINT (marshal_data);
class = G_TYPE_INSTANCE_GET_INTERFACE (g_value_get_as_pointer (param_values + 0), itype, GTypeClass);
callback = G_STRUCT_MEMBER (gpointer, class, offset);
if (callback)
closure->marshal (closure, invocation_hint, return_value,
n_param_values, param_values, callback);
}
GClosure*
g_signal_type_closure_new (GType itype,
guint struct_offset)
{
GClosure *closure;
g_return_val_if_fail (G_TYPE_IS_CLASSED (itype) || G_TYPE_IS_INTERFACE (itype), NULL);
g_return_val_if_fail (struct_offset >= sizeof (GTypeClass), NULL);
closure = g_closure_new_simple (sizeof (GClosure), GUINT_TO_POINTER (itype));
if (G_TYPE_IS_INTERFACE (itype))
g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_iface_meta_marshal);
else
g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_class_meta_marshal);
return closure;
}

185
gobject/gclosure.h Normal file
View File

@@ -0,0 +1,185 @@
/* GObject - GLib Type, Object, Parameter and Signal Library
* Copyright (C) 2000 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __G_CLOSURE_H__
#define __G_CLOSURE_H__
#include <gobject/gtype.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* --- defines --- */
#define G_CLOSURE_NEEDS_MARSHAL(closure) (((GClosure*) (closure))->marshal == NULL)
#define G_CCLOSURE_SWAP_DATA(cclosure) (((GClosure*) (closure))->derivative_flag)
/* -- typedefs --- */
typedef struct _GClosure GClosure;
typedef struct _GClosureNotifyData GClosureNotifyData;
typedef gpointer GCallback;
typedef void (*GClosureNotify) (gpointer data,
GClosure *closure);
typedef void (*GClosureMarshal) (GClosure *closure,
guint invocation_hint,
GValue *return_value,
guint n_param_values,
const GValue *param_values,
gpointer marshal_data);
typedef struct _GCClosure GCClosure;
/* --- structures --- */
struct _GClosureNotifyData
{
gpointer data;
GClosureNotify notify;
};
struct _GClosure
{
/*< private >*/ guint ref_count : 15;
/*< private >*/ guint meta_marshal : 1;
/*< private >*/ guint n_guards : 1;
/*< private >*/ guint n_fnotifiers : 2; /* finalization notifiers */
/*< private >*/ guint n_inotifiers : 8; /* invalidation notifiers */
/*< private >*/ guint in_inotify : 1;
/*< private >*/ guint floating : 1;
/*< protected >*/ guint derivative_flag : 1;
/*< puplic >*/ guint in_marshal : 1;
/*< public >*/ guint is_invalid : 1;
/*< private >*/ void (*marshal) (GClosure *closure,
guint invocation_hint,
GValue /*out*/ *return_value,
guint n_param_values,
const GValue *param_values,
gpointer marshal_data);
/*< protected >*/ gpointer data;
/*< private >*/ GClosureNotifyData *notifiers;
/* invariants/constrains:
* - ->marshal and ->data are _invalid_ as soon as ->is_invalid==TRUE
* - invocation of all inotifiers occours prior to fnotifiers
* - order of inotifiers is random
* inotifiers may _not_ free/invalidate parameter values (e.g. ->data)
* - order of fnotifiers is random
* - notifiers may only be removed before or during their invocation
* - reference counting may only happen prior to fnotify invocation
* (in that sense, fnotifiers are really finalization handlers)
*/
};
/* closure for C function calls, callback() is the user function
*/
struct _GCClosure
{
GClosure closure;
gpointer callback;
};
/* --- prototypes --- */
GClosure* g_cclosure_new (GCallback callback_func,
gpointer user_data,
GClosureNotify destroy_data);
GClosure* g_cclosure_new_swap (GCallback callback_func,
gpointer user_data,
GClosureNotify destroy_data);
GClosure* g_signal_type_closure_new (GType itype,
guint struct_offset);
/* --- prototypes --- */
GClosure* g_closure_ref (GClosure *closure);
void g_closure_unref (GClosure *closure);
/* intimidating */
GClosure* g_closure_new_simple (guint sizeof_closure,
gpointer data);
void g_closure_add_fnotify (GClosure *closure,
gpointer notify_data,
GClosureNotify notify_func);
void g_closure_remove_fnotify (GClosure *closure,
gpointer notify_data,
GClosureNotify notify_func);
void g_closure_add_inotify (GClosure *closure,
gpointer notify_data,
GClosureNotify notify_func);
void g_closure_remove_inotify (GClosure *closure,
gpointer notify_data,
GClosureNotify notify_func);
void g_closure_add_marshal_guards (GClosure *closure,
gpointer pre_marshal_data,
GClosureNotify pre_marshal_notify,
gpointer post_marshal_data,
GClosureNotify post_marshal_notify);
void g_closure_set_marshal (GClosure *closure,
GClosureMarshal marshal);
void g_closure_set_meta_marshal (GClosure *closure,
gpointer marshal_data,
GClosureMarshal meta_marshal);
void g_closure_invalidate (GClosure *closure);
void g_closure_invoke (GClosure *closure,
guint invocation_hint,
GValue /*out*/ *return_value,
guint n_param_values,
const GValue *param_values);
/*
data_object::destroy -> closure_invalidate();
closure_invalidate() -> disconnect(closure);
disconnect(closure) -> (unlink) closure_unref();
closure_finalize() -> g_free (data_string);
1) need GObject and GType in glib
2) need GParam
3) need to resolve dtor cycles
4) need GSignal move
5) destroy on last caller ref or last data ref?
random remarks:
- don't mandate signals for GObject
- OTOH, don't mandate GObject for GSignal
- need marshaller repo with decent aliasing to base types
- provide marshaller collection, virtually covering anything out there
- at that point, still need GSignalCMarhsaller to g_signal_new() ?
- can we combine varargs collect mechanisms with marshaller stubs?
for out values (i.e. returntypes), that might get rid of the following
point...
- char* return signals with connections ala:
connect({ return "static data that can't work"; }),
connect({ return g_strdup ("properly duplicated string"); })
won't work anymore. CRASH
problems:
- accumulator needs gboolean to indicate EMISSION_STOP
- accumulator needs data
*/
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __G_CLOSURE_H__ */

View File

@@ -30,14 +30,14 @@ static void g_enum_class_init (GEnumClass *class,
gpointer class_data);
static void g_flags_class_init (GFlagsClass *class,
gpointer class_data);
static void g_value_enum_init (GValue *value);
static void g_value_enum_copy_value (const GValue *src_value,
static void value_flags_enum_init (GValue *value);
static void value_flags_enum_copy_value (const GValue *src_value,
GValue *dest_value);
static gchar* g_value_enum_collect_value (GValue *value,
guint nth_value,
GType *collect_type,
GTypeCValue *collect_value);
static gchar* g_value_enum_lcopy_value (const GValue *value,
static gchar* value_flags_enum_collect_value (GValue *value,
guint nth_value,
GType *collect_type,
GTypeCValue *collect_value);
static gchar* value_flags_enum_lcopy_value (const GValue *value,
guint nth_value,
GType *collect_type,
GTypeCValue *collect_value);
@@ -48,57 +48,106 @@ void
g_enum_types_init (void) /* sync with gtype.c */
{
static gboolean initialized = FALSE;
static const GTypeFundamentalInfo finfo = {
G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_DERIVABLE,
static const GTypeValueTable flags_enum_value_table = {
value_flags_enum_init, /* value_init */
NULL, /* value_free */
value_flags_enum_copy_value, /* value_copy */
NULL, /* value_peek_pointer */
G_VALUE_COLLECT_INT, /* collect_type */
value_flags_enum_collect_value, /* collect_value */
G_VALUE_COLLECT_POINTER, /* lcopy_type */
value_flags_enum_lcopy_value, /* lcopy_value */
};
static GTypeInfo info = {
0 /* class_size */,
NULL /* base_init */,
NULL /* base_finalize */,
NULL /* class_init */,
NULL /* class_finalize */,
NULL /* class_data */,
0, /* class_size */
NULL, /* base_init */
NULL, /* base_destroy */
NULL, /* class_init */
NULL, /* class_destroy */
NULL, /* class_data */
0, /* instance_size */
0, /* n_preallocs */
NULL, /* instance_init */
&flags_enum_value_table, /* value_table */
};
static const GTypeValueTable value_table = {
g_value_enum_init, /* value_init */
NULL, /* value_free */
g_value_enum_copy_value, /* value_copy */
G_VALUE_COLLECT_INT, /* collect_type */
g_value_enum_collect_value, /* collect_value */
G_VALUE_COLLECT_POINTER, /* lcopy_type */
g_value_enum_lcopy_value, /* lcopy_value */
static const GTypeFundamentalInfo finfo = {
G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_DERIVABLE,
};
GType type;
g_return_if_fail (initialized == FALSE);
initialized = TRUE;
info.value_table = &value_table;
/* G_TYPE_ENUM
*/
info.class_size = sizeof (GEnumClass);
type = g_type_register_fundamental (G_TYPE_ENUM, "GEnum", &info, &finfo);
type = g_type_register_fundamental (G_TYPE_ENUM, "GEnum", &info, &finfo, G_TYPE_FLAG_ABSTRACT);
g_assert (type == G_TYPE_ENUM);
/* G_TYPE_FLAGS
*/
info.class_size = sizeof (GFlagsClass);
type = g_type_register_fundamental (G_TYPE_FLAGS, "GFlags", &info, &finfo);
type = g_type_register_fundamental (G_TYPE_FLAGS, "GFlags", &info, &finfo, G_TYPE_FLAG_ABSTRACT);
g_assert (type == G_TYPE_FLAGS);
}
static void
value_flags_enum_init (GValue *value)
{
value->data[0].v_long = 0;
}
static void
value_flags_enum_copy_value (const GValue *src_value,
GValue *dest_value)
{
dest_value->data[0].v_long = src_value->data[0].v_long;
}
static gchar*
value_flags_enum_collect_value (GValue *value,
guint nth_value,
GType *collect_type,
GTypeCValue *collect_value)
{
value->data[0].v_long = collect_value->v_int;
*collect_type = 0;
return NULL;
}
static gchar*
value_flags_enum_lcopy_value (const GValue *value,
guint nth_value,
GType *collect_type,
GTypeCValue *collect_value)
{
gint *int_p = collect_value->v_pointer;
if (!int_p)
return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
*int_p = value->data[0].v_long;
*collect_type = 0;
return NULL;
}
GType
g_enum_register_static (const gchar *name,
const GEnumValue *const_static_values)
{
GTypeInfo enum_type_info = {
sizeof (GEnumClass),
NULL /* base_init */,
NULL /* base_finalize */,
sizeof (GEnumClass), /* class_size */
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) g_enum_class_init,
NULL /* class_finalize */,
NULL /* class_data */,
NULL, /* class_finalize */
NULL, /* class_data */
0, /* instance_size */
0, /* n_preallocs */
NULL, /* instance_init */
NULL, /* value_table */
};
GType type;
@@ -107,7 +156,7 @@ g_enum_register_static (const gchar *name,
enum_type_info.class_data = const_static_values;
type = g_type_register_static (G_TYPE_ENUM, name, &enum_type_info);
type = g_type_register_static (G_TYPE_ENUM, name, &enum_type_info, 0);
return type;
}
@@ -117,12 +166,16 @@ g_flags_register_static (const gchar *name,
const GFlagsValue *const_static_values)
{
GTypeInfo flags_type_info = {
sizeof (GFlagsClass),
NULL /* base_init */,
NULL /* base_finalize */,
sizeof (GFlagsClass), /* class_size */
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) g_flags_class_init,
NULL /* class_finalize */,
NULL /* class_data */,
NULL, /* class_finalize */
NULL, /* class_data */
0, /* instance_size */
0, /* n_preallocs */
NULL, /* instance_init */
NULL, /* value_table */
};
GType type;
@@ -131,7 +184,7 @@ g_flags_register_static (const gchar *name,
flags_type_info.class_data = const_static_values;
type = g_type_register_static (G_TYPE_FLAGS, name, &flags_type_info);
type = g_type_register_static (G_TYPE_FLAGS, name, &flags_type_info, 0);
return type;
}
@@ -335,15 +388,15 @@ g_value_set_enum (GValue *value,
gint v_enum)
{
g_return_if_fail (G_IS_VALUE_ENUM (value));
value->data[0].v_long = v_enum;
}
gint
g_value_get_enum (GValue *value)
g_value_get_enum (const GValue *value)
{
g_return_val_if_fail (G_IS_VALUE_ENUM (value), 0);
return value->data[0].v_long;
}
@@ -352,56 +405,14 @@ g_value_set_flags (GValue *value,
guint v_flags)
{
g_return_if_fail (G_IS_VALUE_FLAGS (value));
value->data[0].v_ulong = v_flags;
}
guint
g_value_get_flags (GValue *value)
g_value_get_flags (const GValue *value)
{
g_return_val_if_fail (G_IS_VALUE_FLAGS (value), 0);
return value->data[0].v_ulong;
}
static void
g_value_enum_init (GValue *value)
{
value->data[0].v_long = 0;
}
static void
g_value_enum_copy_value (const GValue *src_value,
GValue *dest_value)
{
dest_value->data[0].v_long = src_value->data[0].v_long;
}
static gchar*
g_value_enum_collect_value (GValue *value,
guint nth_value,
GType *collect_type,
GTypeCValue *collect_value)
{
value->data[0].v_long = collect_value->v_int;
*collect_type = 0;
return NULL;
}
static gchar*
g_value_enum_lcopy_value (const GValue *value,
guint nth_value,
GType *collect_type,
GTypeCValue *collect_value)
{
gint *int_p = collect_value->v_pointer;
if (!int_p)
return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
*int_p = value->data[0].v_long;
*collect_type = 0;
return NULL;
}

View File

@@ -38,8 +38,8 @@ extern "C" {
#define G_IS_FLAGS_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_FLAGS))
#define G_FLAGS_CLASS_TYPE(class) (G_TYPE_FROM_CLASS (class))
#define G_FLAGS_CLASS_TYPE_NAME(class) (g_type_name (G_FLAGS_TYPE (class)))
#define G_IS_VALUE_ENUM(value) (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_ENUM))
#define G_IS_VALUE_FLAGS(value) (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_FLAGS))
#define G_IS_VALUE_ENUM(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_ENUM))
#define G_IS_VALUE_FLAGS(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_FLAGS))
/* --- enum/flag values & classes --- */
@@ -93,10 +93,10 @@ GFlagsValue* g_flags_get_value_by_nick (GFlagsClass *flags_class,
const gchar *nick);
void g_value_set_enum (GValue *value,
gint v_enum);
gint g_value_get_enum (GValue *value);
gint g_value_get_enum (const GValue *value);
void g_value_set_flags (GValue *value,
guint v_flags);
guint g_value_get_flags (GValue *value);
guint g_value_get_flags (const GValue *value);

196
gobject/glib-genmarshal.1 Normal file
View File

@@ -0,0 +1,196 @@
.TH GLIB-GENMARSHAL 1 "18 Oct 2000"
.SH NAME
glib-genmarshal \- C code marshaller generation utility for GLib closures
.SH SYNOPSIS
\fBglib-genmarshal\fP [\fIoptions\fP] [\fIfiles...\fP]
.SH DESCRIPTION
\fBglib-genmarshal\fP is a small utility that generates C code marshallers
for callback functions of the GClosure mechanism in the GObject sublibrary
of GLib. The marshaller functions have a standard signature, they get passed
in the invoking closure, an array of value structures holding the callback
function parameters and a value structure for the return value of the
callback. The marshaller is then responsible to call the respective C code
function of the closure with all the parameters on the stack and to collect
its return value.
.SH INVOCATION
\fBglib-genmarshal\fP takes a list of marshallers to generate as input.
The marshaller list is either read from standard input or from files
passed as additional arguments on the command line.
.SS Options
.TP
\fI--header
Generate header file contents of the marshallers.
.TP
\fI--body
Generate C code file contents of the marshallers.
.TP
\fI--prefix=string, --prefix string
Specify marshaller prefix. The default prefix is `\fIg_cclosure_marshal\fP'.
.TP
\fI--skip-source
Skip source location remarks in generated comments.
.TP
\fI--g-fatal-warnings
Make warnings fatal, that is, exit immediately once a warning occours.
.TP
\fI-h, --help\fP
Print brief help and exit.
.TP
\fI-v, --version\fP
Print version and exit.
.PP
.SS Marshaller list format
.PP
The marshaller lists are processed line by line, a line can contain a
comment in the form of
.RS
.PP
# this is a comment
.PP
.RE
or a marshaller specification of the form
.RS
.PP
\fIRTYPE\fP:\fBPTYPE\fP
.PP
\fIRTYPE\fP:\fBPTYPE\fP,\fBPTYPE\fP
.PP
\fIRTYPE\fP:\fBPTYPE\fP,\fBPTYPE\fP,\fBPTYPE\fP
.PP
# up to 16 \fBPTYPE\fPs may be present
.PP
.RE
The \fIRTYPE\fP part specifies the callback's return type and
the \fBPTYPE\fPs right to the colon specify the callback's
parameter list, except for the first and the last arguments which
are always pointers.
.PP
.SS Parameter types
Currently, the following types are supported:
.TP 12
\fIVOID
indicates no return type, or no extra parameters. if \fIVOID\fP is used as
the parameter list, no additional parameters may be present.
.TP 12
\fIBOOLEAN
for boolean types (gboolean)
.TP 12
\fICHAR
for signed char types (gchar)
.TP 12
\fIUCHAR
for unsigned char types (guchar)
.TP 12
\fIINT
for signed integer types (gint)
.TP 12
\fIUINT
for unsigned integer types (guint)
.TP 12
\fILONG
for signed long integer types (glong)
.TP 12
\fIULONG
for unsigned long integer types (gulong)
.TP 12
\fIENUM
for enumeration types (gint)
.TP 12
\fIFLAGS
for flag enumeration types (guint)
.TP 12
\fIFLOAT
for single-precision float types (gfloat)
.TP 12
\fIDOUBLE
for double-precision float types (gdouble)
.TP 12
\fISTRING
for string types (gchar*)
.TP 12
\fIBOXED
for boxed (anonymous but reference counted) types (GBoxed*)
.TP 12
\fIPOINTER
for anonymous pointer types (gpointer)
.TP 12
\fIOBJECT
for GObject or derived types (GObject*)
.TP 12
\fINONE
deprecated alias for \fIVOID\fP
.TP 12
\fIBOOL
deprecated alias for \fIBOOLEAN\fP
.SH EXAMPLE
To generate marshallers for the following callback functions:
.PP
.RS
.nf
void foo (gpointer data1,
gpointer data2);
void bar (gpointer data1,
gint param1,
gpointer data2);
gfloat baz (gpointer data1,
gboolean param1,
guchar param2,
gpointer data2);
.fi
.RE
.PP
The marshaller list has to look like this:
.PP
.RS
.nf
VOID:VOID
VOID:INT
FLOAT:BOOLEAN,UCHAR
.fi
.RE
.PP
The generated marshallers have the arguments encoded
in their function name. For this particular list, they
are
g_cclosure_marshal_VOID__VOID(),
g_cclosure_marshal_VOID__INT(),
g_cclosure_marshal_FLOAT__BOOLEAN_UCHAR().
.PP
They can be used directly for GClosures or be passed in as
the GSignalCMarshaller c_marshaller; argument upon creation
of signals:
.PP
.nf
GClosure *cc_foo, *cc_bar, *cc_baz;
cc_foo = g_cclosure_new (NULL, foo, NULL);
g_closure_set_marshal (cc_foo, g_cclosure_marshal_VOID__VOID);
cc_bar = g_cclosure_new (NULL, bar, NULL);
g_closure_set_marshal (cc_bar, g_cclosure_marshal_VOID__INT);
cc_baz = g_cclosure_new (NULL, baz, NULL);
g_closure_set_marshal (cc_baz, g_cclosure_marshal_FLOAT__BOOLEAN_UCHAR);
.fi
.PP
.SH SEE ALSO
\fB
glib-config(1)
\fP
.SH BUGS
None known yet.
.SH AUTHOR
.B glib-genmarshal
has been written by Tim Janik <timj@gtk.org>.
.PP
This manual page was provided by Tim Janik <timj@gtk.org>.

693
gobject/glib-genmarshal.c Normal file
View File

@@ -0,0 +1,693 @@
/* GLIB-GenMarshal - Marshaller generator for GObject library
* Copyright (C) 2000 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <glib-object.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
/* --- defines --- */
#define PRG_NAME "glib-genmarshal"
#define PKG_NAME "GLib"
#define PKG_HTTP_HOME "http://www.gtk.org"
/* --- typedefs & structures --- */
typedef struct _Argument Argument;
typedef struct _Signature Signature;
struct _Argument
{
gchar *pname; /* parsed name */
const gchar *sname; /* signature name */
const gchar *func; /* functional extension */
const gchar *cname; /* C name */
};
struct _Signature
{
gchar *ploc;
Argument *rarg;
GList *args; /* of type Argument* */
};
/* --- prototypes --- */
static void parse_args (gint *argc_p,
gchar ***argv_p);
static void print_blurb (FILE *bout,
gboolean print_help);
/* --- variables --- */
static FILE *fout = NULL;
static GScannerConfig scanner_config_template =
{
(
" \t\r" /* "\n" is statement delimiter */
) /* cset_skip_characters */,
(
G_CSET_a_2_z
"_"
G_CSET_A_2_Z
) /* cset_identifier_first */,
(
G_CSET_a_2_z
"_0123456789"
G_CSET_A_2_Z
) /* cset_identifier_nth */,
( "#\n" ) /* cpair_comment_single */,
FALSE /* case_sensitive */,
TRUE /* skip_comment_multi */,
TRUE /* skip_comment_single */,
TRUE /* scan_comment_multi */,
TRUE /* scan_identifier */,
FALSE /* scan_identifier_1char */,
FALSE /* scan_identifier_NULL */,
TRUE /* scan_symbols */,
FALSE /* scan_binary */,
TRUE /* scan_octal */,
TRUE /* scan_float */,
TRUE /* scan_hex */,
FALSE /* scan_hex_dollar */,
TRUE /* scan_string_sq */,
TRUE /* scan_string_dq */,
TRUE /* numbers_2_int */,
FALSE /* int_2_float */,
FALSE /* identifier_2_string */,
TRUE /* char_2_token */,
FALSE /* symbol_2_token */,
FALSE /* scope_0_fallback */,
};
static gchar *marshaller_prefix = "g_cclosure_marshal";
static GHashTable *marshallers = NULL;
static gboolean gen_cheader = FALSE;
static gboolean gen_cbody = FALSE;
static gboolean skip_ploc = FALSE;
/* --- functions --- */
static gboolean
complete_arg (Argument *arg,
gboolean is_return)
{
static const Argument inout_arguments[] = {
/* pname, sname, func, cname */
{ "VOID", "VOID", NULL, "void", },
{ "BOOLEAN", "BOOLEAN", "boolean", "gboolean", },
{ "CHAR", "CHAR", "char", "gchar", },
{ "UCHAR", "UCHAR", "uchar", "guchar", },
{ "INT", "INT", "int", "gint", },
{ "UINT", "UINT", "uint", "guint", },
{ "LONG", "LONG", "long", "glong", },
{ "ULONG", "ULONG", "ulong", "gulong", },
{ "ENUM", "ENUM", "enum", "gint", },
{ "FLAGS", "FLAGS", "flags", "guint", },
{ "FLOAT", "FLOAT", "float", "gfloat", },
{ "DOUBLE", "DOUBLE", "double", "gdouble", },
/* deprecated: */
{ "NONE", "VOID", NULL, "void", },
{ "BOOL", "BOOLEAN", "boolean", "gboolean", },
};
static const Argument in_arguments[] = {
{ "STRING", "POINTER", "as_pointer", "gpointer", },
{ "BOXED", "POINTER", "as_pointer", "gpointer", },
{ "POINTER", "POINTER", "as_pointer", "gpointer", },
{ "OBJECT", "POINTER", "as_pointer", "gpointer", },
};
static const Argument out_arguments[] = {
{ "STRING", "STRING", "string", "gchar*", },
{ "BOXED", "BOXED", "boxed", "gpointer", },
{ "POINTER", "POINTER", "pointer", "gpointer", },
{ "OBJECT", "OBJECT", "object", "GObject*", },
};
const guint n_inout_arguments = sizeof (inout_arguments) / sizeof (inout_arguments[0]);
const guint n_out_arguments = sizeof (out_arguments) / sizeof (out_arguments[0]);
const guint n_in_arguments = sizeof (in_arguments) / sizeof (in_arguments[0]);
const Argument *arguments;
guint i, n_arguments;
g_return_val_if_fail (arg != NULL, FALSE);
arguments = inout_arguments;
n_arguments = n_inout_arguments;
for (i = 0; i < n_arguments; i++)
if (strcmp (arguments[i].pname, arg->pname) == 0)
{
arg->sname = arguments[i].sname;
arg->func = arguments[i].func;
arg->cname = arguments[i].cname;
return TRUE;
}
arguments = is_return ? out_arguments : in_arguments;
n_arguments = is_return ? n_out_arguments : n_in_arguments;
for (i = 0; i < n_arguments; i++)
if (strcmp (arguments[i].pname, arg->pname) == 0)
{
arg->sname = arguments[i].sname;
arg->func = arguments[i].func;
arg->cname = arguments[i].cname;
return TRUE;
}
return FALSE;
}
static const gchar*
pad (const gchar *string)
{
#define PAD_LENGTH 12
static gchar *buffer = NULL;
gint i;
g_return_val_if_fail (string != NULL, NULL);
if (!buffer)
buffer = g_new (gchar, PAD_LENGTH + 1);
/* paranoid check */
if (strlen (string) >= PAD_LENGTH)
{
g_free (buffer);
buffer = g_strdup_printf ("%s ", string);
g_warning ("overfull string (%u bytes) for padspace", strlen (string));
return buffer;
}
for (i = 0; i < PAD_LENGTH; i++)
{
gboolean done = *string == 0;
buffer[i] = done ? ' ' : *string++;
}
buffer[i] = 0;
return buffer;
}
static const gchar*
indent (guint n_spaces)
{
static gchar *buffer;
static guint blength = 0;
if (blength <= n_spaces)
{
blength = n_spaces + 1;
g_free (buffer);
buffer = g_new (gchar, blength);
}
memset (buffer, ' ', n_spaces);
buffer[n_spaces] = 0;
return buffer;
}
static void
generate_marshal (const gchar *signame,
Signature *sig)
{
guint ind, a;
GList *node;
if (g_hash_table_lookup (marshallers, signame))
return;
else
{
gchar *tmp = g_strdup (signame);
g_hash_table_insert (marshallers, tmp, tmp);
}
if (gen_cheader)
{
ind = fprintf (fout, "extern void ");
ind += fprintf (fout, "%s_%s (", marshaller_prefix, signame);
fprintf (fout, "GClosure *closure,\n");
fprintf (fout, "%sguint invocation_hint,\n", indent (ind));
fprintf (fout, "%sGValue *return_value,\n", indent (ind));
fprintf (fout, "%sguint n_param_values,\n", indent (ind));
fprintf (fout, "%sconst GValue *param_values,\n", indent (ind));
fprintf (fout, "%sgpointer marshal_data);\n", indent (ind));
}
if (gen_cbody)
{
/* cfile marhsal header */
fprintf (fout, "void\n");
ind = fprintf (fout, "%s_%s (", marshaller_prefix, signame);
fprintf (fout, "GClosure *closure,\n");
fprintf (fout, "%sguint invocation_hint,\n", indent (ind));
fprintf (fout, "%sGValue *return_value,\n", indent (ind));
fprintf (fout, "%sguint n_param_values,\n", indent (ind));
fprintf (fout, "%sconst GValue *param_values,\n", indent (ind));
fprintf (fout, "%sgpointer marshal_data)\n", indent (ind));
fprintf (fout, "{\n");
/* cfile GSignalFunc typedef */
ind = fprintf (fout, " typedef %s (*GSignalFunc_%s) (", sig->rarg->cname, signame);
fprintf (fout, "%s data1,\n", pad ("gpointer"));
for (a = 1, node = sig->args; node; node = node->next)
{
Argument *arg = node->data;
if (arg->func)
fprintf (fout, "%s%s arg_%d,\n", indent (ind), pad (arg->cname), a++);
}
fprintf (fout, "%s%s data2);\n", indent (ind), pad ("gpointer"));
/* cfile marshal variables */
fprintf (fout, " register GSignalFunc_%s callback;\n", signame);
fprintf (fout, " register GCClosure *cc = (GCClosure*) closure;\n");
fprintf (fout, " register gpointer data1, data2;\n");
if (sig->rarg->func)
fprintf (fout, " %s v_return;\n", sig->rarg->cname);
if (sig->args || sig->rarg->func)
{
fprintf (fout, "\n");
if (sig->rarg->func)
fprintf (fout, " g_return_if_fail (return_value != NULL);\n");
if (sig->args)
{
for (a = 0, node = sig->args; node; node = node->next)
{
Argument *arg = node->data;
if (arg->func)
a++;
}
fprintf (fout, " g_return_if_fail (n_param_values >= %u);\n", 1 + a);
}
}
/* cfile marshal data1, data2 and callback setup */
fprintf (fout, "\n");
fprintf (fout, " if (G_CCLOSURE_SWAP_DATA (closure))\n {\n");
fprintf (fout, " data1 = closure->data;\n");
fprintf (fout, " data2 = g_value_get_as_pointer (param_values + 0);\n");
fprintf (fout, " }\n else\n {\n");
fprintf (fout, " data1 = g_value_get_as_pointer (param_values + 0);\n");
fprintf (fout, " data2 = closure->data;\n");
fprintf (fout, " }\n");
fprintf (fout, " callback = (GSignalFunc_%s) (marshal_data ? marshal_data : cc->callback);\n", signame);
/* cfile marshal callback action */
fprintf (fout, "\n");
ind = fprintf (fout, " %s callback (", sig->rarg->func ? " v_return =" : "");
fprintf (fout, "data1,\n");
for (a = 1, node = sig->args; node; node = node->next)
{
Argument *arg = node->data;
if (arg->func)
fprintf (fout, "%sg_value_get_%s (param_values + %d),\n", indent (ind), arg->func, a++);
}
fprintf (fout, "%sdata2);\n", indent (ind));
/* cfile marshal return value storage */
if (sig->rarg->func)
{
fprintf (fout, "\n");
fprintf (fout, " g_value_set_%s (return_value, v_return);\n", sig->rarg->func);
}
/* cfile marshal footer */
fprintf (fout, "}\n");
}
}
static void
process_signature (Signature *sig)
{
gchar *pname, *sname;
GList *node;
/* lookup and complete info on arguments */
if (!complete_arg (sig->rarg, TRUE))
{
g_warning ("unknown type: %s", sig->rarg->pname);
return;
}
for (node = sig->args; node; node = node->next)
{
Argument *arg = node->data;
if (!complete_arg (arg, FALSE))
{
g_warning ("unknown type: %s", arg->pname);
return;
}
}
/* construct requested marshaller name and technical marshaller name */
pname = g_strconcat (sig->rarg->pname, "_", NULL);
sname = g_strconcat (sig->rarg->sname, "_", NULL);
for (node = sig->args; node; node = node->next)
{
Argument *arg = node->data;
gchar *tmp;
tmp = sname;
sname = g_strconcat (tmp, "_", arg->sname, NULL);
g_free (tmp);
tmp = pname;
pname = g_strconcat (tmp, "_", arg->pname, NULL);
g_free (tmp);
}
/* introductionary comment */
fprintf (fout, "\n/* %s", sig->rarg->pname);
for (node = sig->args; node; node = node->next)
{
Argument *arg = node->data;
fprintf (fout, "%c%s", node->prev ? ',' : ':', arg->pname);
}
if (!skip_ploc)
fprintf (fout, " (%s)", sig->ploc);
fprintf (fout, " */\n");
/* generate signature marshaller */
generate_marshal (sname, sig);
/* put out marshaler alias if required */
if (gen_cheader && !g_hash_table_lookup (marshallers, pname))
{
gchar *tmp = g_strdup (pname);
fprintf (fout, "#define %s_%s\t%s_%s\n", marshaller_prefix, pname, marshaller_prefix, sname);
g_hash_table_insert (marshallers, tmp, tmp);
}
g_free (pname);
g_free (sname);
}
static Argument*
new_arg (const gchar *pname)
{
Argument *arg = g_new0 (Argument, 1);
arg->pname = g_strdup (pname);
return arg;
}
static guint
parse_line (GScanner *scanner,
Signature *sig)
{
/* parse identifier for return value */
if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
return G_TOKEN_IDENTIFIER;
sig->rarg = new_arg (scanner->value.v_identifier);
/* keep a note on the location */
sig->ploc = g_strdup_printf ("%s:%u", scanner->input_name, scanner->line);
/* expect ':' */
if (g_scanner_get_next_token (scanner) != ':')
return ':';
/* parse first argument */
if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
return G_TOKEN_IDENTIFIER;
sig->args = g_list_append (sig->args, new_arg (scanner->value.v_identifier));
/* parse rest of argument list */
while (g_scanner_peek_next_token (scanner) == ',')
{
/* eat comma */
g_scanner_get_next_token (scanner);
/* parse arg identifier */
if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
return G_TOKEN_IDENTIFIER;
sig->args = g_list_append (sig->args, new_arg (scanner->value.v_identifier));
}
/* expect end of line, done */
if (g_scanner_get_next_token (scanner) != '\n')
return '\n';
/* success */
return G_TOKEN_NONE;
}
static gboolean
string_key_destroy (gpointer key,
gpointer value,
gpointer user_data)
{
g_free (key);
return TRUE;
}
int
main (int argc,
char *argv[])
{
GScanner *scanner;
GSList *slist, *files = NULL;
gint i;
/* parse args and do fast exits */
parse_args (&argc, &argv);
/* list input files */
for (i = 1; i < argc; i++)
files = g_slist_prepend (files, argv[i]);
if (files)
files = g_slist_reverse (files);
else
files = g_slist_prepend (files, "/dev/stdin");
/* setup auxillary structs */
scanner = g_scanner_new (&scanner_config_template);
fout = stdout;
marshallers = g_hash_table_new (g_str_hash, g_str_equal);
/* process input files */
for (slist = files; slist; slist = slist->next)
{
gchar *file = slist->data;
gint fd = open (file, O_RDONLY);
if (fd < 0)
{
g_warning ("failed to open \"%s\": %s", file, g_strerror (errno));
continue;
}
/* set file name for error reports */
scanner->input_name = file;
/* parse & process file */
g_scanner_input_file (scanner, fd);
/* scanning loop, we parse the input untill it's end is reached,
* or our sub routine came across invalid syntax
*/
do
{
guint expected_token = G_TOKEN_NONE;
switch (g_scanner_peek_next_token (scanner))
{
case '\n':
/* eat newline and restart */
g_scanner_get_next_token (scanner);
continue;
case G_TOKEN_EOF:
/* done */
break;
default:
/* parse and process signatures */
{
Signature signature = { NULL, NULL, NULL };
GList *node;
expected_token = parse_line (scanner, &signature);
/* once we got a valid signature, process it */
if (expected_token == G_TOKEN_NONE)
process_signature (&signature);
/* clean up signature contents */
g_free (signature.ploc);
if (signature.rarg)
g_free (signature.rarg->pname);
g_free (signature.rarg);
for (node = signature.args; node; node = node->next)
{
Argument *arg = node->data;
g_free (arg->pname);
g_free (arg);
}
g_list_free (signature.args);
}
break;
}
/* bail out on errors */
if (expected_token != G_TOKEN_NONE)
{
g_scanner_unexp_token (scanner, expected_token, "type name", NULL, NULL, NULL, TRUE);
break;
}
g_scanner_peek_next_token (scanner);
}
while (scanner->next_token != G_TOKEN_EOF);
close (fd);
}
/* clean up */
g_slist_free (files);
g_scanner_destroy (scanner);
g_hash_table_foreach_remove (marshallers, string_key_destroy, NULL);
g_hash_table_destroy (marshallers);
return 0;
}
static void
parse_args (gint *argc_p,
gchar ***argv_p)
{
guint argc = *argc_p;
gchar **argv = *argv_p;
guint i, e;
for (i = 1; i < argc; i++)
{
if (strcmp ("--header", argv[i]) == 0)
{
gen_cheader = TRUE;
argv[i] = NULL;
}
else if (strcmp ("--body", argv[i]) == 0)
{
gen_cbody = TRUE;
argv[i] = NULL;
}
else if (strcmp ("--skip-source", argv[i]) == 0)
{
skip_ploc = TRUE;
argv[i] = NULL;
}
else if ((strcmp ("--prefix", argv[i]) == 0) ||
(strncmp ("--prefix=", argv[i], 9) == 0))
{
gchar *equal = argv[i] + 8;
if (*equal == '=')
marshaller_prefix = g_strdup (equal + 1);
else if (i + 1 < argc)
{
marshaller_prefix = g_strdup (argv[i + 1]);
argv[i] = NULL;
i += 1;
}
argv[i] = NULL;
}
else if (strcmp ("-h", argv[i]) == 0 ||
strcmp ("--help", argv[i]) == 0)
{
print_blurb (stderr, TRUE);
argv[i] = NULL;
exit (0);
}
else if (strcmp ("-v", argv[i]) == 0 ||
strcmp ("--version", argv[i]) == 0)
{
print_blurb (stderr, FALSE);
argv[i] = NULL;
exit (0);
}
else if (strcmp (argv[i], "--g-fatal-warnings") == 0)
{
GLogLevelFlags fatal_mask;
fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
g_log_set_always_fatal (fatal_mask);
argv[i] = NULL;
}
}
e = 0;
for (i = 1; i < argc; i++)
{
if (e)
{
if (argv[i])
{
argv[e++] = argv[i];
argv[i] = NULL;
}
}
else if (!argv[i])
e = i;
}
if (e)
*argc_p = e;
}
static void
print_blurb (FILE *bout,
gboolean print_help)
{
if (!print_help)
{
fprintf (bout, "%s version ", PRG_NAME);
fprintf (bout, "%u.%u.%u", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
fprintf (bout, "\n");
fprintf (bout, "%s comes with ABSOLUTELY NO WARRANTY.\n", PRG_NAME);
fprintf (bout, "You may redistribute copies of %s under the terms of\n", PRG_NAME);
fprintf (bout, "the GNU General Public License which can be found in the\n");
fprintf (bout, "%s source package. Sources, examples and contact\n", PKG_NAME);
fprintf (bout, "information are available at %s\n", PKG_HTTP_HOME);
}
else
{
fprintf (bout, "Usage: %s [options] [files...]\n", PRG_NAME);
fprintf (bout, " --header generate C headers\n");
fprintf (bout, " --body generate C code\n");
fprintf (bout, " --prefix=string specify marshaller prefix\n");
fprintf (bout, " --skip-source skip source location comments\n");
fprintf (bout, " -h, --help show this help message\n");
fprintf (bout, " -v, --version print version informations\n");
fprintf (bout, " --g-fatal-warnings make warnings fatal (abort)\n");
}
}

View File

@@ -16,7 +16,7 @@
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "../config.h"
#include <glib-object.h>

View File

@@ -46,6 +46,7 @@ static void g_value_object_init (GValue *value);
static void g_value_object_free_value (GValue *value);
static void g_value_object_copy_value (const GValue *src_value,
GValue *dest_value);
static gpointer g_value_object_peek_pointer (const GValue *value);
static gchar* g_value_object_collect_value (GValue *value,
guint nth_value,
GType *collect_type,
@@ -59,6 +60,7 @@ static gchar* g_value_object_lcopy_value (const GValue *value,
/* --- variables --- */
static GQuark quark_param_id = 0;
static GQuark quark_param_changed_queue = 0;
static GQuark quark_closure_array = 0;
static GHashTable *param_spec_hash_table = NULL;
@@ -122,6 +124,7 @@ g_object_type_init (void) /* sync with gtype.c */
g_value_object_init, /* value_init */
g_value_object_free_value, /* value_free */
g_value_object_copy_value, /* value_copy */
g_value_object_peek_pointer, /* value_peek_pointer */
G_VALUE_COLLECT_POINTER, /* collect_type */
g_value_object_collect_value, /* collect_value */
G_VALUE_COLLECT_POINTER, /* lcopy_type */
@@ -135,7 +138,7 @@ g_object_type_init (void) /* sync with gtype.c */
/* G_TYPE_OBJECT
*/
info.value_table = &value_table;
type = g_type_register_fundamental (G_TYPE_OBJECT, "GObject", &info, &finfo);
type = g_type_register_fundamental (G_TYPE_OBJECT, "GObject", &info, &finfo, 0);
g_assert (type == G_TYPE_OBJECT);
#ifdef DEBUG_OBJECTS
@@ -178,6 +181,7 @@ g_object_do_class_init (GObjectClass *class)
{
quark_param_id = g_quark_from_static_string ("glib-object-param-id");
quark_param_changed_queue = g_quark_from_static_string ("glib-object-param-changed-queue");
quark_closure_array = g_quark_from_static_string ("GObject-closure-array");
param_spec_hash_table = g_param_spec_hash_table_new ();
class->queue_param_changed = g_object_do_queue_param_changed;
@@ -810,6 +814,12 @@ g_value_object_copy_value (const GValue *src_value,
dest_value->data[0].v_pointer = NULL;
}
static gpointer
g_value_object_peek_pointer (const GValue *value)
{
return value->data[0].v_pointer;
}
static gchar*
g_value_object_collect_value (GValue *value,
guint nth_value,
@@ -874,7 +884,7 @@ g_value_set_object (GValue *value,
}
GObject*
g_value_get_object (GValue *value)
g_value_get_object (const GValue *value)
{
g_return_val_if_fail (G_IS_VALUE_OBJECT (value), NULL);
@@ -882,9 +892,137 @@ g_value_get_object (GValue *value)
}
GObject*
g_value_dup_object (GValue *value)
g_value_dup_object (const GValue *value)
{
g_return_val_if_fail (G_IS_VALUE_OBJECT (value), NULL);
return value->data[0].v_pointer ? g_object_ref (value->data[0].v_pointer) : NULL;
}
typedef struct {
GObject *object;
guint n_closures;
GClosure *closures[1]; /* flexible array */
} CArray;
static void
object_remove_closure (gpointer data,
GClosure *closure)
{
GObject *object = data;
CArray *carray = g_object_get_qdata (object, quark_closure_array);
guint i;
for (i = 0; i < carray->n_closures; i++)
if (carray->closures[i] == closure)
{
carray->n_closures--;
if (i < carray->n_closures)
carray->closures[i] = carray->closures[carray->n_closures];
return;
}
g_assert_not_reached ();
}
static void
destroy_closure_array (gpointer data)
{
CArray *carray = data;
GObject *object = carray->object;
guint i, n = carray->n_closures;
for (i = 0; i < n; i++)
{
GClosure *closure = carray->closures[i];
/* removing object_remove_closure() upfront is probably faster than
* letting it fiddle with quark_closure_array which is empty anyways
*/
g_closure_remove_inotify (closure, object, object_remove_closure);
g_closure_invalidate (closure);
}
g_free (carray);
}
void
g_object_watch_closure (GObject *object,
GClosure *closure)
{
CArray *carray;
g_return_if_fail (G_IS_OBJECT (object));
g_return_if_fail (closure != NULL);
g_return_if_fail (closure->is_invalid == FALSE);
g_return_if_fail (closure->in_marshal == FALSE);
g_return_if_fail (object->ref_count > 0); /* this doesn't work on finalizing objects */
g_closure_add_inotify (closure, object, object_remove_closure);
g_closure_add_marshal_guards (closure,
object, (GClosureNotify) g_object_ref,
object, (GClosureNotify) g_object_unref);
carray = g_object_get_qdata (object, quark_closure_array);
if (!carray)
{
carray = g_renew (CArray, NULL, 1);
carray->object = object;
carray->n_closures = 1;
carray->closures[0] = closure;
g_object_set_qdata_full (object, quark_closure_array, carray, destroy_closure_array);
}
else
{
guint i = carray->n_closures++;
carray = g_realloc (carray, sizeof (*carray) + sizeof (carray->closures[0]) * i);
carray->closures[i] = closure;
}
}
GClosure*
g_closure_new_object (guint sizeof_closure,
GObject *object)
{
GClosure *closure;
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
g_return_val_if_fail (object->ref_count > 0, NULL); /* this doesn't work on finalizing objects */
closure = g_closure_new_simple (sizeof_closure, object);
g_object_watch_closure (object, closure);
return closure;
}
GClosure*
g_cclosure_new_object (gpointer _object,
GCallback callback_func)
{
GObject *object = _object;
GClosure *closure;
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
g_return_val_if_fail (object->ref_count > 0, NULL); /* this doesn't work on finalizing objects */
g_return_val_if_fail (callback_func != NULL, NULL);
closure = g_cclosure_new (callback_func, object, NULL);
g_object_watch_closure (object, closure);
return closure;
}
GClosure*
g_cclosure_new_object_swap (gpointer _object,
GCallback callback_func)
{
GObject *object = _object;
GClosure *closure;
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
g_return_val_if_fail (object->ref_count > 0, NULL); /* this doesn't work on finalizing objects */
g_return_val_if_fail (callback_func != NULL, NULL);
closure = g_cclosure_new_swap (callback_func, object, NULL);
g_object_watch_closure (object, closure);
return closure;
}

View File

@@ -16,12 +16,13 @@
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __G_GOBJECT_H__
#define __G_GOBJECT_H__
#ifndef __G_OBJECT_H__
#define __G_OBJECT_H__
#include <gobject/gtype.h>
#include <gobject/gvalue.h>
#include <gobject/gparam.h>
#include <gobject/gclosure.h>
#ifdef __cplusplus
@@ -31,38 +32,35 @@ extern "C" {
/* --- type macros --- */
#define G_TYPE_IS_OBJECT(type) (G_TYPE_FUNDAMENTAL (type) == G_TYPE_OBJECT)
#define G_OBJECT(object) (G_IS_OBJECT (object) ? ((GObject*) (object)) : \
G_TYPE_CHECK_INSTANCE_CAST ((object), G_TYPE_OBJECT, GObject))
#define G_OBJECT_CLASS(class) (G_IS_OBJECT_CLASS (class) ? ((GObjectClass*) (class)) : \
G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_OBJECT, GObjectClass))
#define G_IS_OBJECT(object) (((GObject*) (object)) != NULL && \
G_IS_OBJECT_CLASS (((GTypeInstance*) (object))->g_class))
#define G_IS_OBJECT_CLASS(class) (((GTypeClass*) (class)) != NULL && \
G_TYPE_IS_OBJECT (((GTypeClass*) (class))->g_type))
#define G_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), G_TYPE_OBJECT, GObject))
#define G_OBJECT_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_OBJECT, GObjectClass))
#define G_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), G_TYPE_OBJECT))
#define G_IS_OBJECT_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_OBJECT))
#define G_OBJECT_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), G_TYPE_OBJECT, GObjectClass))
#define G_OBJECT_TYPE(object) (G_TYPE_FROM_INSTANCE (object))
#define G_OBJECT_TYPE_NAME(object) (g_type_name (G_OBJECT_TYPE (object)))
#define G_OBJECT_CLASS_TYPE(class) (G_TYPE_FROM_CLASS (class))
#define G_OBJECT_CLASS_NAME(class) (g_type_name (G_OBJECT_CLASS_TYPE (class)))
#define G_IS_VALUE_OBJECT(value) (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_OBJECT))
#define G_IS_VALUE_OBJECT(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_OBJECT))
#define G_NOTIFY_PRIORITY (G_PRIORITY_HIGH_IDLE + 20)
/* --- typedefs & structures --- */
typedef struct _GObject GObject;
typedef struct _GObjectClass GObjectClass;
typedef void (*GObjectGetParamFunc) (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec,
const gchar *trailer);
typedef void (*GObjectSetParamFunc) (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec,
const gchar *trailer);
typedef void (*GObjectFinalizeFunc) (GObject *object);
typedef struct _GObject GObject;
typedef struct _GObjectClass GObjectClass;
typedef struct _GObjectConstructParam GObjectConstructParam;
typedef void (*GObjectGetParamFunc) (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec,
const gchar *trailer);
typedef void (*GObjectSetParamFunc) (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec,
const gchar *trailer);
typedef void (*GObjectFinalizeFunc) (GObject *object);
struct _GObject
{
GTypeInstance g_type_instance;
@@ -77,7 +75,10 @@ struct _GObjectClass
guint n_param_specs;
GParamSpec **param_specs;
GObject* (*constructor) (GType type, // FIXME!!!
guint n_construct_params,
GObjectConstructParam *construct_params);
void (*get_param) (GObject *object,
guint param_id,
GValue *value,
@@ -85,7 +86,7 @@ struct _GObjectClass
const gchar *trailer);
void (*set_param) (GObject *object,
guint param_id,
GValue *value,
const GValue *value,
GParamSpec *pspec,
const gchar *trailer);
void (*queue_param_changed) (GObject *object,
@@ -95,6 +96,12 @@ struct _GObjectClass
void (*shutdown) (GObject *object);
void (*finalize) (GObject *object);
};
struct _GObjectConstructParam
{
GParamSpec *pspec;
GValue *value;
gchar *trailer;
};
/* --- prototypes --- */
@@ -142,10 +149,18 @@ void g_object_set_qdata_full (GObject *object,
GDestroyNotify destroy);
gpointer g_object_steal_qdata (GObject *object,
GQuark quark);
void g_object_watch_closure (GObject *object,
GClosure *closure);
GClosure* g_cclosure_new_object (gpointer object,
GCallback callback_func);
GClosure* g_cclosure_new_object_swap (gpointer object,
GCallback callback_func);
GClosure* g_closure_new_object (guint sizeof_closure,
GObject *object);
void g_value_set_object (GValue *value,
GObject *v_object);
GObject* g_value_get_object (GValue *value);
GObject* g_value_dup_object (GValue *value);
GObject* g_value_get_object (const GValue *value);
GObject* g_value_dup_object (const GValue *value);
/* --- implementation macros --- */
@@ -168,4 +183,4 @@ G_STMT_START { \
}
#endif /* __cplusplus */
#endif /* __G_GOBJECT_H__ */
#endif /* __G_OBJECT_H__ */

View File

@@ -63,7 +63,7 @@ g_param_type_init (void) /* sync with gtype.c */
};
GType type;
type = g_type_register_fundamental (G_TYPE_PARAM, "GParam", &param_spec_info, &finfo);
type = g_type_register_fundamental (G_TYPE_PARAM, "GParam", &param_spec_info, &finfo, G_TYPE_FLAG_ABSTRACT);
g_assert (type == G_TYPE_PARAM);
}
@@ -380,3 +380,91 @@ g_param_spec_hash_table_lookup (GHashTable *hash_table,
return pspec;
}
/* --- auxillary functions --- */
typedef struct
{
/* class portion */
GType value_type;
void (*finalize) (GParamSpec *pspec);
void (*value_set_default) (GParamSpec *pspec,
GValue *value);
gboolean (*value_validate) (GParamSpec *pspec,
GValue *value);
gint (*values_cmp) (GParamSpec *pspec,
const GValue *value1,
const GValue *value2);
} ParamSpecClassInfo;
static void
param_spec_generic_class_init (gpointer g_class,
gpointer class_data)
{
GParamSpecClass *class = g_class;
ParamSpecClassInfo *info = class_data;
class->value_type = info->value_type;
if (info->finalize)
class->finalize = info->finalize; /* optional */
class->value_set_default = info->value_set_default;
if (info->value_validate)
class->value_validate = info->value_validate; /* optional */
class->values_cmp = info->values_cmp;
g_free (class_data);
}
static void
default_value_set_default (GParamSpec *pspec,
GValue *value)
{
/* value is already zero initialized */
}
static gint
default_values_cmp (GParamSpec *pspec,
const GValue *value1,
const GValue *value2)
{
return memcmp (&value1->data, &value2->data, sizeof (value1->data));
}
GType
g_param_type_register_static (const gchar *name,
const GParamSpecTypeInfo *pspec_info)
{
GTypeInfo info = {
sizeof (GParamSpecClass), /* class_size */
NULL, /* base_init */
NULL, /* base_destroy */
param_spec_generic_class_init, /* class_init */
NULL, /* class_destroy */
NULL, /* class_data */
0, /* instance_size */
16, /* n_preallocs */
NULL, /* instance_init */
};
ParamSpecClassInfo *cinfo;
g_return_val_if_fail (name != NULL, 0);
g_return_val_if_fail (pspec_info != NULL, 0);
g_return_val_if_fail (g_type_from_name (name) == 0, 0);
g_return_val_if_fail (pspec_info->instance_size >= sizeof (GParamSpec), 0);
g_return_val_if_fail (g_type_name (pspec_info->value_type) != NULL, 0);
/* default: g_return_val_if_fail (pspec_info->value_set_default != NULL, 0); */
/* optional: g_return_val_if_fail (pspec_info->value_validate != NULL, 0); */
/* default: g_return_val_if_fail (pspec_info->values_cmp != NULL, 0); */
info.instance_size = pspec_info->instance_size;
info.n_preallocs = pspec_info->n_preallocs;
info.instance_init = (GInstanceInitFunc) pspec_info->instance_init;
cinfo = g_new (ParamSpecClassInfo, 1);
cinfo->value_type = pspec_info->value_type;
cinfo->finalize = pspec_info->finalize;
cinfo->value_set_default = pspec_info->value_set_default ? pspec_info->value_set_default : default_value_set_default;
cinfo->value_validate = pspec_info->value_validate;
cinfo->values_cmp = pspec_info->values_cmp ? pspec_info->values_cmp : default_values_cmp;
info.class_data = cinfo;
return g_type_register_static (G_TYPE_PARAM, name, &info, 0);
}

View File

@@ -113,6 +113,30 @@ gint g_param_values_cmp (GParamSpec *pspec,
const GValue *value2);
/* --- convenience functions --- */
typedef struct _GParamSpecTypeInfo GParamSpecTypeInfo;
struct _GParamSpecTypeInfo
{
/* type system portion */
guint16 instance_size; /* obligatory */
guint16 n_preallocs; /* optional */
void (*instance_init) (GParamSpec *pspec); /* optional */
/* class portion */
GType value_type; /* obligatory */
void (*finalize) (GParamSpec *pspec); /* optional */
void (*value_set_default) (GParamSpec *pspec, /* recommended */
GValue *value);
gboolean (*value_validate) (GParamSpec *pspec, /* optional */
GValue *value);
gint (*values_cmp) (GParamSpec *pspec, /* recommended */
const GValue *value1,
const GValue *value2);
};
GType g_param_type_register_static (const gchar *name,
const GParamSpecTypeInfo *pspec_info);
/* --- private --- */
gpointer g_param_spec_internal (GType param_type,
const gchar *name,
@@ -134,44 +158,18 @@ GParamSpec* g_param_spec_hash_table_lookup (GHashTable *hash_table,
/* contracts:
*
* +++ OUTDATED +++
*
* class functions may not evaluate param->pspec directly,
* instead, pspec will be passed as argument if required.
*
* void param_init (GParam *param, GParamSpec *pspec):
* initialize param's value to default if pspec is given,
* and to zero-equivalent (a value that doesn't need to be
* free()ed later on) otherwise.
*
* void param_free_value (GParam *param):
* free param's value if required, zero-reinitialization
* of the value is not required. (this class function
* may be NULL for param types that don't need to free
* values, such as ints or floats).
*
* gboolean param_validate (GParam *param, GParamSpec *pspec):
* modify param's value in the least destructive way, so
* gboolean value_validate (GParamSpec *pspec,
* GValue *value):
* modify value contents in the least destructive way, so
* that it complies with pspec's requirements (i.e.
* according to minimum/maximum ranges etc...). return
* whether modification was necessary.
*
* gint param_values_cmp (GParam *param1, GParam *param2, GParamSpec*):
* return param1 - param2, i.e. <0 if param1 < param2,
* >0 if param1 > param2, and 0 if they are equal
* (passing pspec is optional, but recommended)
*
* void param_copy_value (GParam *param_src, GParam *param_dest):
* copy value from param_src to param_dest, param_dest is
* already free()d and zero-initialized, so its value can
* simply be overwritten. (may be NULL for memcpy)
*
* gchar* param_collect_value ():
* class function may be NULL.
*
* gchar* param_lcopy_value ():
* class function may be NULL.
*
* gint values_cmp (GParamSpec *pspec,
* const GValue *value1,
* const GValue *value2):
* return value1 - value2, i.e. <0 if value1 < value2,
* >0 if value1 > value2, and 0 otherwise (they are equal)
*/
#ifdef __cplusplus

View File

@@ -20,7 +20,7 @@
#include "gvaluecollector.h"
#include <string.h>
#include "config.h" /* for SIZEOF_LONG */
#include "../config.h" /* for SIZEOF_LONG */
#define G_FLOAT_EPSILON (1e-30)
#define G_DOUBLE_EPSILON (1e-90)
@@ -710,272 +710,229 @@ value_exch_double_float (GValue *value1,
/* --- type initialization --- */
typedef struct {
GType value_type;
void (*finalize) (GParamSpec *pspec);
void (*value_set_default) (GParamSpec *pspec,
GValue *value);
gboolean (*value_validate) (GParamSpec *pspec,
GValue *value);
gint (*values_cmp) (GParamSpec *pspec,
const GValue *value1,
const GValue *value2);
} ParamSpecClassInfo;
static void
param_spec_class_init (gpointer g_class,
gpointer class_data)
{
GParamSpecClass *class = g_class;
ParamSpecClassInfo *info = class_data;
g_assert (info->value_type && !G_TYPE_IS_PARAM (info->value_type));
class->value_type = info->value_type;
if (info->finalize)
class->finalize = info->finalize;
if (info->value_set_default)
class->value_set_default = info->value_set_default;
if (info->value_validate)
class->value_validate = info->value_validate;
if (info->values_cmp)
class->values_cmp = info->values_cmp;
}
void
g_param_spec_types_init (void) /* sync with gtype.c */
{
GTypeInfo info = {
sizeof (GParamSpecClass), /* class_size */
NULL, /* base_init */
NULL, /* base_destroy */
param_spec_class_init, /* class_init */
NULL, /* class_destroy */
NULL, /* class_data */
0, /* instance_size */
16, /* n_preallocs */
NULL, /* instance_init */
};
GType type;
/* G_TYPE_PARAM_CHAR
*/
{
static const ParamSpecClassInfo class_info = {
static const GParamSpecTypeInfo pspec_info = {
sizeof (GParamSpecChar), /* instance_size */
16, /* n_preallocs */
param_spec_char_init, /* instance_init */
G_TYPE_CHAR, /* value_type */
NULL, /* finalize */
param_char_set_default, /* value_set_default */
param_char_validate, /* value_validate */
param_int_values_cmp, /* values_cmp */
};
info.class_data = &class_info;
info.instance_size = sizeof (GParamSpecChar);
info.instance_init = (GInstanceInitFunc) param_spec_char_init;
type = g_type_register_static (G_TYPE_PARAM, "GParamChar", &info);
type = g_param_type_register_static ("GParamChar", &pspec_info);
g_assert (type == G_TYPE_PARAM_CHAR);
}
/* G_TYPE_PARAM_UCHAR
*/
{
static const ParamSpecClassInfo class_info = {
static const GParamSpecTypeInfo pspec_info = {
sizeof (GParamSpecUChar), /* instance_size */
16, /* n_preallocs */
param_spec_uchar_init, /* instance_init */
G_TYPE_UCHAR, /* value_type */
NULL, /* finalize */
param_uchar_set_default, /* value_set_default */
param_uchar_validate, /* value_validate */
param_uint_values_cmp, /* values_cmp */
};
info.class_data = &class_info;
info.instance_size = sizeof (GParamSpecUChar);
info.instance_init = (GInstanceInitFunc) param_spec_uchar_init;
type = g_type_register_static (G_TYPE_PARAM, "GParamUChar", &info);
type = g_param_type_register_static ("GParamUChar", &pspec_info);
g_assert (type == G_TYPE_PARAM_UCHAR);
}
/* G_TYPE_PARAM_BOOLEAN
*/
{
static const ParamSpecClassInfo class_info = {
G_TYPE_BOOLEAN, /* value_type */
NULL, /* finalize */
param_boolean_set_default, /* value_set_default */
param_boolean_validate, /* value_validate */
param_int_values_cmp, /* values_cmp */
static const GParamSpecTypeInfo pspec_info = {
sizeof (GParamSpecBoolean), /* instance_size */
16, /* n_preallocs */
NULL, /* instance_init */
G_TYPE_BOOLEAN, /* value_type */
NULL, /* finalize */
param_boolean_set_default, /* value_set_default */
param_boolean_validate, /* value_validate */
param_int_values_cmp, /* values_cmp */
};
info.class_data = &class_info;
info.instance_size = sizeof (GParamSpecBoolean);
info.instance_init = (GInstanceInitFunc) NULL;
type = g_type_register_static (G_TYPE_PARAM, "GParamBoolean", &info);
type = g_param_type_register_static ("GParamBoolean", &pspec_info);
g_assert (type == G_TYPE_PARAM_BOOLEAN);
}
/* G_TYPE_PARAM_INT
*/
{
static const ParamSpecClassInfo class_info = {
static const GParamSpecTypeInfo pspec_info = {
sizeof (GParamSpecInt), /* instance_size */
16, /* n_preallocs */
param_spec_int_init, /* instance_init */
G_TYPE_INT, /* value_type */
NULL, /* finalize */
param_int_set_default, /* value_set_default */
param_int_validate, /* value_validate */
param_int_values_cmp, /* values_cmp */
};
info.class_data = &class_info;
info.instance_size = sizeof (GParamSpecInt);
info.instance_init = (GInstanceInitFunc) param_spec_int_init;
type = g_type_register_static (G_TYPE_PARAM, "GParamInt", &info);
type = g_param_type_register_static ("GParamInt", &pspec_info);
g_assert (type == G_TYPE_PARAM_INT);
}
/* G_TYPE_PARAM_UINT
*/
{
static const ParamSpecClassInfo class_info = {
static const GParamSpecTypeInfo pspec_info = {
sizeof (GParamSpecUInt), /* instance_size */
16, /* n_preallocs */
param_spec_uint_init, /* instance_init */
G_TYPE_UINT, /* value_type */
NULL, /* finalize */
param_uint_set_default, /* value_set_default */
param_uint_validate, /* value_validate */
param_uint_values_cmp, /* values_cmp */
};
info.class_data = &class_info;
info.instance_size = sizeof (GParamSpecUInt);
info.instance_init = (GInstanceInitFunc) param_spec_uint_init;
type = g_type_register_static (G_TYPE_PARAM, "GParamUInt", &info);
type = g_param_type_register_static ("GParamUInt", &pspec_info);
g_assert (type == G_TYPE_PARAM_UINT);
}
/* G_TYPE_PARAM_LONG
*/
{
static const ParamSpecClassInfo class_info = {
static const GParamSpecTypeInfo pspec_info = {
sizeof (GParamSpecLong), /* instance_size */
16, /* n_preallocs */
param_spec_long_init, /* instance_init */
G_TYPE_LONG, /* value_type */
NULL, /* finalize */
param_long_set_default, /* value_set_default */
param_long_validate, /* value_validate */
param_long_values_cmp, /* values_cmp */
};
info.class_data = &class_info;
info.instance_size = sizeof (GParamSpecLong);
info.instance_init = (GInstanceInitFunc) param_spec_long_init;
type = g_type_register_static (G_TYPE_PARAM, "GParamLong", &info);
type = g_param_type_register_static ("GParamLong", &pspec_info);
g_assert (type == G_TYPE_PARAM_LONG);
}
/* G_TYPE_PARAM_ULONG
*/
{
static const ParamSpecClassInfo class_info = {
static const GParamSpecTypeInfo pspec_info = {
sizeof (GParamSpecULong), /* instance_size */
16, /* n_preallocs */
param_spec_ulong_init, /* instance_init */
G_TYPE_ULONG, /* value_type */
NULL, /* finalize */
param_ulong_set_default, /* value_set_default */
param_ulong_validate, /* value_validate */
param_ulong_values_cmp, /* values_cmp */
};
info.class_data = &class_info;
info.instance_size = sizeof (GParamSpecULong);
info.instance_init = (GInstanceInitFunc) param_spec_ulong_init;
type = g_type_register_static (G_TYPE_PARAM, "GParamULong", &info);
type = g_param_type_register_static ("GParamULong", &pspec_info);
g_assert (type == G_TYPE_PARAM_ULONG);
}
/* G_TYPE_PARAM_ENUM
*/
{
static const ParamSpecClassInfo class_info = {
static const GParamSpecTypeInfo pspec_info = {
sizeof (GParamSpecEnum), /* instance_size */
16, /* n_preallocs */
param_spec_enum_init, /* instance_init */
G_TYPE_ENUM, /* value_type */
param_spec_enum_finalize, /* finalize */
param_enum_set_default, /* value_set_default */
param_enum_validate, /* value_validate */
param_long_values_cmp, /* values_cmp */
};
info.class_data = &class_info;
info.instance_size = sizeof (GParamSpecEnum);
info.instance_init = (GInstanceInitFunc) param_spec_enum_init;
type = g_type_register_static (G_TYPE_PARAM, "GParamEnum", &info);
type = g_param_type_register_static ("GParamEnum", &pspec_info);
g_assert (type == G_TYPE_PARAM_ENUM);
}
/* G_TYPE_PARAM_FLAGS
*/
{
static const ParamSpecClassInfo class_info = {
static const GParamSpecTypeInfo pspec_info = {
sizeof (GParamSpecFlags), /* instance_size */
16, /* n_preallocs */
param_spec_flags_init, /* instance_init */
G_TYPE_FLAGS, /* value_type */
param_spec_flags_finalize,/* finalize */
param_flags_set_default, /* value_set_default */
param_flags_validate, /* value_validate */
param_ulong_values_cmp, /* values_cmp */
};
info.class_data = &class_info;
info.instance_size = sizeof (GParamSpecFlags);
info.instance_init = (GInstanceInitFunc) param_spec_flags_init;
type = g_type_register_static (G_TYPE_PARAM, "GParamFlags", &info);
type = g_param_type_register_static ("GParamFlags", &pspec_info);
g_assert (type == G_TYPE_PARAM_FLAGS);
}
/* G_TYPE_PARAM_FLOAT
*/
{
static const ParamSpecClassInfo class_info = {
static const GParamSpecTypeInfo pspec_info = {
sizeof (GParamSpecFloat), /* instance_size */
16, /* n_preallocs */
param_spec_float_init, /* instance_init */
G_TYPE_FLOAT, /* value_type */
NULL, /* finalize */
param_float_set_default, /* value_set_default */
param_float_validate, /* value_validate */
param_float_values_cmp, /* values_cmp */
};
info.class_data = &class_info;
info.instance_size = sizeof (GParamSpecFloat);
info.instance_init = (GInstanceInitFunc) param_spec_float_init;
type = g_type_register_static (G_TYPE_PARAM, "GParamFloat", &info);
type = g_param_type_register_static ("GParamFloat", &pspec_info);
g_assert (type == G_TYPE_PARAM_FLOAT);
}
/* G_TYPE_PARAM_DOUBLE
*/
{
static const ParamSpecClassInfo class_info = {
G_TYPE_DOUBLE, /* value_type */
NULL, /* finalize */
param_double_set_default, /* value_set_default */
param_double_validate, /* value_validate */
param_double_values_cmp, /* values_cmp */
static const GParamSpecTypeInfo pspec_info = {
sizeof (GParamSpecDouble), /* instance_size */
16, /* n_preallocs */
param_spec_double_init, /* instance_init */
G_TYPE_DOUBLE, /* value_type */
NULL, /* finalize */
param_double_set_default, /* value_set_default */
param_double_validate, /* value_validate */
param_double_values_cmp, /* values_cmp */
};
info.class_data = &class_info;
info.instance_size = sizeof (GParamSpecDouble);
info.instance_init = (GInstanceInitFunc) param_spec_double_init;
type = g_type_register_static (G_TYPE_PARAM, "GParamDouble", &info);
type = g_param_type_register_static ("GParamDouble", &pspec_info);
g_assert (type == G_TYPE_PARAM_DOUBLE);
}
/* G_TYPE_PARAM_STRING
*/
{
static const ParamSpecClassInfo class_info = {
static const GParamSpecTypeInfo pspec_info = {
sizeof (GParamSpecString), /* instance_size */
16, /* n_preallocs */
param_spec_string_init, /* instance_init */
G_TYPE_STRING, /* value_type */
param_spec_string_finalize, /* finalize */
param_string_set_default, /* value_set_default */
param_string_validate, /* value_validate */
param_string_values_cmp, /* values_cmp */
};
info.class_data = &class_info;
info.instance_size = sizeof (GParamSpecString);
info.instance_init = (GInstanceInitFunc) param_spec_string_init;
type = g_type_register_static (G_TYPE_PARAM, "GParamString", &info);
type = g_param_type_register_static ("GParamString", &pspec_info);
g_assert (type == G_TYPE_PARAM_STRING);
}
/* G_TYPE_PARAM_OBJECT
*/
{
static const ParamSpecClassInfo class_info = {
G_TYPE_OBJECT, /* value_type */
NULL, /* finalize */
param_object_set_default, /* value_set_default */
param_object_validate, /* value_validate */
param_object_values_cmp, /* values_cmp */
static const GParamSpecTypeInfo pspec_info = {
sizeof (GParamSpecObject), /* instance_size */
16, /* n_preallocs */
param_spec_object_init, /* instance_init */
G_TYPE_OBJECT, /* value_type */
NULL, /* finalize */
param_object_set_default, /* value_set_default */
param_object_validate, /* value_validate */
param_object_values_cmp, /* values_cmp */
};
info.class_data = &class_info;
info.instance_size = sizeof (GParamSpecObject);
info.instance_init = (GInstanceInitFunc) param_spec_object_init;
type = g_type_register_static (G_TYPE_PARAM, "GParamObject", &info);
type = g_param_type_register_static ("GParamObject", &pspec_info);
g_assert (type == G_TYPE_PARAM_OBJECT);
}

1335
gobject/gsignal.c Normal file

File diff suppressed because it is too large Load Diff

142
gobject/gsignal.h Normal file
View File

@@ -0,0 +1,142 @@
/* GObject - GLib Type, Object, Parameter and Signal Library
* Copyright (C) 2000 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __G_SIGNAL_H__
#define __G_SIGNAL_H__
#include <gobject/gclosure.h>
#include <gobject/gvalue.h>
#include <gobject/gparam.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* --- macros --- */
#define G_SIGNAL_HINT_ID(hint) ((hint) >> 8)
#define G_SIGNAL_HINT_RUN_TYPE(hint) ((hint) & 0xff)
/* --- run & match types --- */
typedef enum
{
G_SIGNAL_RUN_FIRST = 1 << 0,
G_SIGNAL_RUN_LAST = 1 << 1,
G_SIGNAL_RUN_CLEANUP = 1 << 2,
G_SIGNAL_NO_RECURSE = 1 << 3,
G_SIGNAL_ACTION = 1 << 4,
G_SIGNAL_NO_HOOKS = 1 << 5
} GSignalType;
typedef enum
{
G_SIGNAL_MATCH_ID = 1 << 0,
G_SIGNAL_MATCH_CLOSURE = 1 << 1,
G_SIGNAL_MATCH_FUNC = 1 << 2,
G_SIGNAL_MATCH_DATA = 1 << 3,
G_SIGNAL_MATCH_UNBLOCKED = 1 << 4,
G_SIGNAL_MATCH_MASK = 0x1f
} GSignalMatchType;
/* --- signal queries --- */
typedef struct _GSignalQuery GSignalQuery;
struct _GSignalQuery
{
guint signal_id;
const gchar *signal_name;
GType itype;
GSignalType signal_flags;
GType return_type;
guint n_params;
const GType *param_types;
};
/* --- function types --- */
typedef gboolean (*GSignalEmissionHook) (guint signal_id,
guint n_values,
const GValue *values);
typedef gboolean (*GSignalAccumulator) (guint signal_id,
GValue *return_accu,
const GValue *return_value);
typedef GClosureMarshal GSignalCMarshaller;
/* --- signals --- */
guint g_signal_newv (const gchar *signal_name,
GType itype,
GSignalType signal_flags,
GClosure *class_closure,
GSignalAccumulator accumulator,
GSignalCMarshaller c_marshaller,
GType return_type,
guint n_params,
GType *param_types);
void g_signal_emitv (const GValue *instance_and_params,
guint signal_id,
GValue *return_value);
guint g_signal_lookup (const gchar *name,
GType itype);
gchar* g_signal_name (guint signal_id);
void g_signal_query (guint signal_id,
GSignalQuery *query);
/* --- signal handlers --- */
guint g_signal_connect_closure (gpointer instance,
guint signal_id,
GClosure *closure,
gboolean after);
void g_signal_handler_disconnect (gpointer instance,
guint handler_id);
void g_signal_handler_block (gpointer instance,
guint handler_id);
void g_signal_handler_unblock (gpointer instance,
guint handler_id);
guint g_signal_handler_find (gpointer instance,
GSignalMatchType mask,
guint signal_id,
GClosure *closure,
gpointer func,
gpointer data);
gboolean g_signal_has_handler_pending (gpointer instance,
guint signal_id,
gboolean may_be_blocked);
/* --- signal emissions --- */
void g_signal_stop_emission (gpointer instance,
guint signal_id);
guint g_signal_add_emission_hook_full (guint signal_id,
GClosure *closure);
void g_signal_remove_emission_hook (guint signal_id,
guint hook_id);
/*< private >*/
void g_signal_handlers_destroy (gpointer instance);
void g_signals_destroy (GType itype);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __G_SIGNAL_H__ */

View File

@@ -32,20 +32,26 @@
* TODO:
* - g_type_from_name() should do an ordered array lookup after fetching the
* the quark, instead of a second hashtable lookup.
* - speedup checks for virtual types, steal a bit somewhere
*
* FIXME:
* - force interface initialization for already existing classes
* - make things threadsafe
*/
#define G_TYPE_FLAG_MASK (G_TYPE_FLAG_CLASSED | \
G_TYPE_FLAG_INSTANTIATABLE | \
G_TYPE_FLAG_DERIVABLE | \
G_TYPE_FLAG_DEEP_DERIVABLE)
#define TYPE_FUNDAMENTAL_FLAG_MASK (G_TYPE_FLAG_CLASSED | \
G_TYPE_FLAG_INSTANTIATABLE | \
G_TYPE_FLAG_DERIVABLE | \
G_TYPE_FLAG_DEEP_DERIVABLE)
#define TYPE_FLAG_MASK (G_TYPE_FLAG_ABSTRACT)
#define g_type_plugin_ref(p) ((p)->vtable->plugin_ref (p))
#define g_type_plugin_unref(p) ((p)->vtable->plugin_unref (p))
#define g_type_plugin_complete_type_info(p,t,i,v) ((p)->vtable->complete_type_info ((p), (t), (i), (v)))
#define g_type_plugin_complete_interface_info(p,f,t,i) ((p)->vtable->complete_interface_info ((p), (f), (t), (i)))
/* --- typedefs --- */
typedef struct _TypeNode TypeNode;
typedef struct _CommonData CommonData;
typedef struct _IFaceData IFaceData;
@@ -58,6 +64,8 @@ typedef struct _IFaceHolder IFaceHolder;
/* --- prototypes --- */
static inline GTypeFundamentalInfo* type_node_fundamental_info (TypeNode *node);
static void type_add_flags (TypeNode *node,
GTypeFlags flags);
static void type_data_make (TypeNode *node,
const GTypeInfo *info,
const GTypeValueTable *value_table);
@@ -69,6 +77,10 @@ static void type_data_last_unref (GType type,
/* --- structures --- */
struct _GValue /* kludge, keep in sync with gvalue.h */
{
GType g_type;
};
struct _TypeNode
{
GTypePlugin *plugin;
@@ -159,11 +171,12 @@ typedef struct {
/* --- variables --- */
static guint n_class_cache_funcs = 0;
static ClassCacheFunc *class_cache_funcs = NULL;
static GType last_fundamental_id = 0;
static GQuark quark_type_flags = 0;
/* --- externs --- */
const char *g_log_domain_gobject = "GLib-Object";
static GType last_fundamental_id = 0;
/* --- type nodes --- */
@@ -187,11 +200,11 @@ LOOKUP_TYPE_NODE (register GType utype)
#define NODE_NAME(node) (g_quark_to_string (node->qname))
static TypeNode*
type_node_any_new (TypeNode *pnode,
GType ftype,
const gchar *name,
GTypePlugin *plugin,
GTypeFlags type_flags)
type_node_any_new (TypeNode *pnode,
GType ftype,
const gchar *name,
GTypePlugin *plugin,
GTypeFundamentalFlags type_flags)
{
guint branch_last, n_supers = pnode ? pnode->n_supers + 1 : 0;
GType type;
@@ -204,11 +217,11 @@ type_node_any_new (TypeNode *pnode,
g_type_nodes[ftype] = g_renew (TypeNode*, g_type_nodes[ftype], 1 << g_bit_storage (g_branch_seqnos[ftype] - 1));
if (!pnode)
node_size += sizeof (GTypeFundamentalInfo); /* fundamental type info */
node_size += SIZEOF_BASE_TYPE_NODE (); /* TypeNode structure */
node_size += sizeof (GTypeFundamentalInfo); /* fundamental type info */
node_size += SIZEOF_BASE_TYPE_NODE (); /* TypeNode structure */
node_size += (sizeof (GType) * (1 + n_supers + 1)); /* self + ancestors + 0 for ->supers[] */
node = g_malloc0 (node_size);
if (!pnode) /* fundamental type */
if (!pnode) /* offset fundamental types */
node = G_STRUCT_MEMBER_P (node, sizeof (GTypeFundamentalInfo));
g_type_nodes[ftype][branch_last] = node;
@@ -280,9 +293,9 @@ type_node_fundamental_info (TypeNode *node)
}
static TypeNode*
type_node_fundamental_new (GType ftype,
const gchar *name,
GTypeFlags type_flags)
type_node_fundamental_new (GType ftype,
const gchar *name,
GTypeFundamentalFlags type_flags)
{
GTypeFundamentalInfo *finfo;
TypeNode *node;
@@ -290,7 +303,7 @@ type_node_fundamental_new (GType ftype,
g_assert (ftype == G_TYPE_FUNDAMENTAL (ftype));
type_flags &= G_TYPE_FLAG_MASK;
type_flags &= TYPE_FUNDAMENTAL_FLAG_MASK;
last_fundamental_id = MAX (last_fundamental_id, ftype + 1);
if (last_fundamental_id > flast)
@@ -495,6 +508,7 @@ check_value_table (const gchar *type_name,
else if (value_table->value_init == NULL)
{
if (value_table->value_free || value_table->value_copy ||
value_table->value_peek_pointer ||
value_table->collect_type || value_table->collect_value ||
value_table->lcopy_type || value_table->lcopy_value)
g_warning ("cannot handle uninitializable values of type `%s'",
@@ -695,6 +709,25 @@ check_interface_info (TypeNode *iface,
/* --- type info (type node data) --- */
static void
type_add_flags (TypeNode *node,
GTypeFlags flags)
{
guint dflags;
g_return_if_fail ((flags & ~TYPE_FLAG_MASK) == 0);
g_return_if_fail (node != NULL);
if (!quark_type_flags)
quark_type_flags = g_quark_from_static_string ("GTypeFlags");
if ((flags & G_TYPE_FLAG_ABSTRACT) && node->is_classed &&
node->data && node->data->class.class)
g_warning ("tagging type `%s' as abstract after class initialization", NODE_NAME (node));
dflags = GPOINTER_TO_UINT (g_type_get_qdata (NODE_TYPE (node), quark_type_flags));
dflags |= flags;
g_type_set_qdata (NODE_TYPE (node), quark_type_flags, GUINT_TO_POINTER (dflags));
}
static void
type_data_make (TypeNode *node,
const GTypeInfo *info,
@@ -856,10 +889,10 @@ type_node_add_iface_entry (TypeNode *node,
}
static void
type_add_interface (TypeNode *node,
TypeNode *iface,
GInterfaceInfo *info,
GTypePlugin *plugin)
type_add_interface (TypeNode *node,
TypeNode *iface,
const GInterfaceInfo *info,
GTypePlugin *plugin)
{
IFaceHolder *iholder = g_new0 (IFaceHolder, 1);
@@ -943,6 +976,12 @@ g_type_create_instance (GType type)
type_descriptive_name (type));
return NULL;
}
if (G_TYPE_IS_ABSTRACT (type))
{
g_warning ("cannot create instance of abstract (non-instantiatable) type `%s'",
type_descriptive_name (type));
return NULL;
}
class = g_type_class_ref (type);
@@ -992,8 +1031,15 @@ g_type_free_instance (GTypeInstance *instance)
type_descriptive_name (class->g_type));
return;
}
if (G_TYPE_IS_ABSTRACT (NODE_TYPE (node)))
{
g_warning ("cannot free instance of abstract (non-instantiatable) type `%s'",
NODE_NAME (node));
return;
}
instance->g_class = NULL;
memset (instance, 0xaa, node->data->instance.instance_size); // FIXME
if (node->data->instance.n_preallocs)
g_chunk_free (instance, node->data->instance.mem_chunk);
else
@@ -1282,7 +1328,8 @@ GType
g_type_register_fundamental (GType type_id,
const gchar *type_name,
const GTypeInfo *info,
const GTypeFundamentalInfo *finfo)
const GTypeFundamentalInfo *finfo,
GTypeFlags flags)
{
GTypeFundamentalInfo *node_finfo;
TypeNode *node;
@@ -1318,6 +1365,7 @@ g_type_register_fundamental (GType type_id,
node = type_node_fundamental_new (type_id, type_name, finfo->type_flags);
node_finfo = type_node_fundamental_info (node);
type_add_flags (node, flags);
if (!check_type_info (NULL, G_TYPE_FUNDAMENTAL (NODE_TYPE (node)), type_name, info))
return NODE_TYPE (node);
@@ -1330,7 +1378,8 @@ g_type_register_fundamental (GType type_id,
GType
g_type_register_static (GType parent_type,
const gchar *type_name,
const GTypeInfo *info)
const GTypeInfo *info,
GTypeFlags flags)
{
TypeNode *pnode, *node;
GType type;
@@ -1351,12 +1400,13 @@ g_type_register_static (GType parent_type,
return 0;
if (info->class_finalize)
{
g_warning ("class destructor specified for static type `%s'",
g_warning ("class finalizer specified for static type `%s'",
type_name);
return 0;
}
node = type_node_new (pnode, type_name, NULL);
type_add_flags (node, flags);
type = NODE_TYPE (node);
type_data_make (node, info,
check_value_table (type_name, info->value_table) ? info->value_table : NULL);
@@ -1367,7 +1417,8 @@ g_type_register_static (GType parent_type,
GType
g_type_register_dynamic (GType parent_type,
const gchar *type_name,
GTypePlugin *plugin)
GTypePlugin *plugin,
GTypeFlags flags)
{
TypeNode *pnode, *node;
GType type;
@@ -1385,15 +1436,16 @@ g_type_register_dynamic (GType parent_type,
pnode = LOOKUP_TYPE_NODE (parent_type);
node = type_node_new (pnode, type_name, plugin);
type_add_flags (node, flags);
type = NODE_TYPE (node);
return type;
}
void
g_type_add_interface_static (GType instance_type,
GType interface_type,
GInterfaceInfo *info)
g_type_add_interface_static (GType instance_type,
GType interface_type,
const GInterfaceInfo *info)
{
TypeNode *node;
TypeNode *iface;
@@ -1674,11 +1726,7 @@ g_type_conforms_to (GType type,
}
}
else
{
TypeNode *node = LOOKUP_TYPE_NODE (type);
return node && (node->is_iface || node->is_instantiatable);
}
return LOOKUP_TYPE_NODE (type) != NULL;
return FALSE;
}
@@ -1839,20 +1887,34 @@ g_type_set_qdata (GType type,
/* --- implementation details --- */
gboolean
g_type_check_flags (GType type,
GTypeFlags flags)
g_type_check_flags (GType type,
guint flags)
{
TypeNode *node = LOOKUP_TYPE_NODE (type);
flags &= G_TYPE_FLAG_MASK;
gboolean result = FALSE;
if (node)
{
GTypeFundamentalInfo *finfo = type_node_fundamental_info (node);
guint fflags = flags & TYPE_FUNDAMENTAL_FLAG_MASK;
guint tflags = flags & TYPE_FLAG_MASK;
if (fflags)
{
GTypeFundamentalInfo *finfo = type_node_fundamental_info (node);
fflags = (finfo->type_flags & fflags) == fflags;
}
else
fflags = TRUE;
return (finfo->type_flags & flags) != 0;
if (tflags)
tflags = (tflags & GPOINTER_TO_UINT (g_type_get_qdata (type, quark_type_flags))) == tflags;
else
tflags = TRUE;
result = tflags && fflags;
}
return FALSE;
return result;
}
GTypePlugin*
@@ -1874,6 +1936,7 @@ g_type_instance_conforms_to (GTypeInstance *type_instance,
GType iface_type)
{
return (type_instance && type_instance->g_class &&
G_TYPE_IS_INSTANTIATABLE (type_instance->g_class->g_type) &&
g_type_conforms_to (type_instance->g_class->g_type, iface_type));
}
@@ -1881,7 +1944,35 @@ gboolean
g_type_class_is_a (GTypeClass *type_class,
GType is_a_type)
{
return (type_class && g_type_is_a (type_class->g_type, is_a_type));
return (type_class && G_TYPE_IS_CLASSED (type_class->g_type) &&
g_type_is_a (type_class->g_type, is_a_type));
}
gboolean
g_type_value_conforms_to (GValue *value,
GType type)
{
TypeNode *node;
if (!value)
return FALSE;
node = LOOKUP_TYPE_NODE (value->g_type);
#if 0
if (!G_TYPE_IS_FUNDAMENTAL (value->g_type) && !node || !node->data)
node = LOOKUP_TYPE_NODE (G_TYPE_FUNDAMENTAL (value->g_type));
#endif
if (!node || !node->data || node->data->common.ref_count < 1 ||
!node->data->common.value_table->value_init ||
!g_type_conforms_to (value->g_type, type))
return FALSE;
return TRUE;
}
gboolean
g_type_check_value (GValue *value)
{
return value && g_type_value_conforms_to (value, value->g_type);
}
GTypeInstance*
@@ -1900,9 +1991,9 @@ g_type_check_instance_cast (GTypeInstance *type_instance,
type_descriptive_name (iface_type));
return type_instance;
}
if (!G_TYPE_IS_CLASSED (type_instance->g_class->g_type))
if (!G_TYPE_IS_INSTANTIATABLE (type_instance->g_class->g_type))
{
g_warning ("invalid unclassed type `%s' in cast to `%s'",
g_warning ("invalid uninstantiatable type `%s' in cast to `%s'",
type_descriptive_name (type_instance->g_class->g_type),
type_descriptive_name (iface_type));
return type_instance;
@@ -1946,13 +2037,47 @@ g_type_check_class_cast (GTypeClass *type_class,
return type_class;
}
gboolean
g_type_check_instance (GTypeInstance *type_instance)
{
/* this function is just here to make the signal system
* conveniently elaborated on instance checks
*/
if (!type_instance)
{
g_warning ("instance is invalid (NULL) pointer");
return FALSE;
}
if (!type_instance->g_class)
{
g_warning ("instance with invalid (NULL) class pointer");
return FALSE;
}
if (!G_TYPE_IS_CLASSED (type_instance->g_class->g_type))
{
g_warning ("instance of invalid unclassed type `%s'",
type_descriptive_name (type_instance->g_class->g_type));
return FALSE;
}
if (!G_TYPE_IS_INSTANTIATABLE (type_instance->g_class->g_type))
{
g_warning ("instance of invalid non-instantiatable type `%s'",
type_descriptive_name (type_instance->g_class->g_type));
return FALSE;
}
return TRUE;
}
/* --- foreign prototypes --- */
extern void g_value_types_init (void); /* sync with gvaluetypes.c */
extern void g_enum_types_init (void); /* sync with genums.c */
extern void g_param_type_init (void); /* sync with gparam.c */
extern void g_boxed_type_init (void); /* sync with gboxed.c */
extern void g_object_type_init (void); /* sync with gobject.c */
extern void g_param_spec_types_init (void); /* sync with gparamspecs.c */
extern void g_signal_init (void); /* sync with gsignal.c */
/* --- initialization --- */
@@ -2004,6 +2129,10 @@ g_type_init (void)
*/
g_param_type_init ();
/* G_TYPE_PARAM
*/
g_boxed_type_init ();
/* G_TYPE_OBJECT
*/
g_object_type_init ();
@@ -2011,4 +2140,8 @@ g_type_init (void)
/* G_TYPE_PARAM_* pspec types
*/
g_param_spec_types_init ();
/* Signal system
*/
g_signal_init ();
}

View File

@@ -60,11 +60,11 @@ typedef enum /*< skip >*/
G_TYPE_DOUBLE,
G_TYPE_STRING,
G_TYPE_PARAM,
G_TYPE_BOXED,
G_TYPE_POINTER,
G_TYPE_OBJECT,
/* the following reserved ids should vanish soon */
G_TYPE_GTK_BOXED,
G_TYPE_GTK_POINTER,
G_TYPE_GTK_SIGNAL,
/* reserved fundamental type ids,
@@ -99,12 +99,15 @@ typedef enum /*< skip >*/
/* Type Checking Macros
*/
#define G_TYPE_IS_FUNDAMENTAL(type) (G_TYPE_BRANCH_SEQNO (type) == 0)
#define G_TYPE_IS_INTERFACE(type) (G_TYPE_FUNDAMENTAL (type) == G_TYPE_INTERFACE)
#define G_TYPE_IS_CLASSED(type) (g_type_check_flags ((type), G_TYPE_FLAG_CLASSED))
#define G_TYPE_IS_INSTANTIATABLE(type) (g_type_check_flags ((type), G_TYPE_FLAG_INSTANTIATABLE))
#define G_TYPE_IS_DERIVABLE(type) (g_type_check_flags ((type), G_TYPE_FLAG_DERIVABLE))
#define G_TYPE_IS_DEEP_DERIVABLE(type) (g_type_check_flags ((type), G_TYPE_FLAG_DEEP_DERIVABLE))
#define G_TYPE_IS_ABSTRACT(type) (g_type_check_flags ((type), G_TYPE_FLAG_ABSTRACT))
#define G_TYPE_IS_PARAM(type) (G_TYPE_FUNDAMENTAL (type) == G_TYPE_PARAM)
#define G_TYPE_IS_VALUE_TYPE(type) (g_type_value_table_peek (type) != NULL)
/* Typedefs
@@ -143,13 +146,20 @@ struct _GTypeInterface
};
/* Casts, Checks And Convenience Macros For Structured Types
/* Casts, checks and accessors for structured types
* usage of these macros is reserved to type implementations only
*
*/
/*< protected >*/
#define G_TYPE_CHECK_INSTANCE(instance) (_G_TYPE_CHI ((GTypeInstance*) (instance)))
#define G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type) (_G_TYPE_CIC ((instance), (g_type), c_type))
#define G_TYPE_CHECK_CLASS_CAST(g_class, g_type, c_type) (_G_TYPE_CCC ((g_class), (g_type), c_type))
#define G_TYPE_CHECK_INSTANCE_TYPE(instance, g_type) (_G_TYPE_CIT ((instance), (g_type)))
#define G_TYPE_CHECK_CLASS_TYPE(g_class, g_type) (_G_TYPE_CCT ((g_class), (g_type)))
#define G_TYPE_INSTANCE_GET_CLASS(instance, g_type, c_type) (_G_TYPE_IGC ((instance), c_type))
#define G_TYPE_INSTANCE_GET_INTERFACE(instance, g_type, c_type) (_G_TYPE_IGI ((instance), (g_type), c_type))
#define G_TYPE_CHECK_CLASS_CAST(g_class, g_type, c_type) (_G_TYPE_CCC ((g_class), (g_type), c_type))
#define G_TYPE_CHECK_CLASS_TYPE(g_class, g_type) (_G_TYPE_CCT ((g_class), (g_type)))
#define G_TYPE_CHECK_VALUE(value) (_G_TYPE_CHV ((value)))
#define G_TYPE_CHECK_VALUE_TYPE(value, g_type) (_G_TYPE_CVT ((value), (g_type)))
#define G_TYPE_FROM_INSTANCE(instance) (G_TYPE_FROM_CLASS (((GTypeInstance*) (instance))->g_class))
#define G_TYPE_FROM_CLASS(g_class) (((GTypeClass*) (g_class))->g_type)
#define G_TYPE_FROM_INTERFACE(g_iface) (((GTypeInterface*) (g_iface))->g_type)
@@ -229,6 +239,10 @@ typedef enum /*< skip >*/
G_TYPE_FLAG_INSTANTIATABLE = (1 << 1),
G_TYPE_FLAG_DERIVABLE = (1 << 2),
G_TYPE_FLAG_DEEP_DERIVABLE = (1 << 3)
} GTypeFundamentalFlags;
typedef enum /*< skip >*/
{
G_TYPE_FLAG_ABSTRACT = (1 << 4)
} GTypeFlags;
struct _GTypeInfo
{
@@ -253,7 +267,7 @@ struct _GTypeInfo
};
struct _GTypeFundamentalInfo
{
GTypeFlags type_flags;
GTypeFundamentalFlags type_flags;
};
struct _GInterfaceInfo
{
@@ -263,61 +277,72 @@ struct _GInterfaceInfo
};
struct _GTypeValueTable
{
void (*value_init) (GValue *value);
void (*value_free) (GValue *value);
void (*value_copy) (const GValue *src_value,
GValue *dest_value);
void (*value_init) (GValue *value);
void (*value_free) (GValue *value);
void (*value_copy) (const GValue *src_value,
GValue *dest_value);
/* varargs functionality (optional) */
guint collect_type;
gchar* (*collect_value) (GValue *value,
guint nth_value,
GType *collect_type,
GTypeCValue *collect_value);
guint lcopy_type;
gchar* (*lcopy_value) (const GValue *value,
guint nth_value,
GType *collect_type,
GTypeCValue *collect_value);
gpointer (*value_peek_pointer) (const GValue *value);
guint collect_type;
gchar* (*collect_value) (GValue *value,
guint nth_value,
GType *collect_type,
GTypeCValue *collect_value);
guint lcopy_type;
gchar* (*lcopy_value) (const GValue *value,
guint nth_value,
GType *collect_type,
GTypeCValue *collect_value);
};
GType g_type_register_static (GType parent_type,
const gchar *type_name,
const GTypeInfo *info);
const GTypeInfo *info,
GTypeFlags flags);
GType g_type_register_dynamic (GType parent_type,
const gchar *type_name,
GTypePlugin *plugin);
GTypePlugin *plugin,
GTypeFlags flags);
GType g_type_register_fundamental (GType type_id,
const gchar *type_name,
const GTypeInfo *info,
const GTypeFundamentalInfo *finfo);
const GTypeFundamentalInfo *finfo,
GTypeFlags flags);
void g_type_add_interface_static (GType instance_type,
GType interface_type,
GInterfaceInfo *info);
const GInterfaceInfo *info);
void g_type_add_interface_dynamic (GType instance_type,
GType interface_type,
GTypePlugin *plugin);
/* --- implementation details --- */
gboolean g_type_class_is_a (GTypeClass *g_class,
GType is_a_type);
GTypeClass* g_type_check_class_cast (GTypeClass *g_class,
GType is_a_type);
GTypeInstance* g_type_check_instance_cast (GTypeInstance *instance,
GType iface_type);
gboolean g_type_instance_conforms_to (GTypeInstance *instance,
GType iface_type);
/* --- protected (for fundamental type implementations) --- */
GTypePlugin* g_type_get_plugin (GType type);
GType g_type_fundamental_last (void);
gboolean g_type_check_flags (GType type,
GTypeFlags flags);
guint flags);
GTypeInstance* g_type_create_instance (GType type);
void g_type_free_instance (GTypeInstance *instance);
GTypeValueTable* g_type_value_table_peek (GType type);
void g_type_add_class_cache_func (gpointer cache_data,
GTypeClassCacheFunc cache_func);
void g_type_remove_class_cache_func (gpointer cache_data,
GTypeClassCacheFunc cache_func);
void g_type_class_unref_uncached (gpointer g_class);
GTypePlugin* g_type_get_plugin (GType type);
GType g_type_fundamental_last (void);
/*< private >*/
GTypeClass* g_type_check_class_cast (GTypeClass *g_class,
GType is_a_type);
gboolean g_type_class_is_a (GTypeClass *g_class,
GType is_a_type);
GTypeInstance* g_type_check_instance_cast (GTypeInstance *instance,
GType iface_type);
gboolean g_type_instance_conforms_to (GTypeInstance *instance,
GType iface_type);
gboolean g_type_check_value (GValue *value);
gboolean g_type_value_conforms_to (GValue *value,
GType type);
gboolean g_type_check_instance (GTypeInstance *instance);
GTypeValueTable* g_type_value_table_peek (GType type);
#ifndef G_DISABLE_CAST_CHECKS
@@ -329,9 +354,14 @@ GType g_type_fundamental_last (void);
# define _G_TYPE_CIC(ip, gt, ct) ((ct*) ip)
# define _G_TYPE_CCC(cp, gt, ct) ((ct*) cp)
#endif /* G_DISABLE_CAST_CHECKS */
#define _G_TYPE_IGC(ip, ct) ((ct*) (((GTypeInstance*) ip)->g_class))
#define _G_TYPE_CHI(ip) (g_type_check_instance ((GTypeInstance*) ip))
#define _G_TYPE_CIT(ip, gt) (g_type_instance_conforms_to ((GTypeInstance*) ip, gt))
#define _G_TYPE_CCT(cp, gt) (g_type_class_is_a ((GTypeClass*) cp, gt))
#define _G_TYPE_CVT(vl, gt) (g_type_value_conforms_to ((GValue*) vl, gt))
#define _G_TYPE_CHV(vl) (g_type_check_value ((GValue*) vl))
#define _G_TYPE_IGC(ip, ct) ((ct*) (((GTypeInstance*) ip)->g_class))
#define _G_TYPE_IGI(ip, gt, ct) ((ct*) g_type_interface_peek (((GTypeInstance*) ip)->g_class, gt))
#ifdef __cplusplus
}

View File

@@ -61,11 +61,13 @@ void
g_value_copy (const GValue *src_value,
GValue *dest_value)
{
GTypeValueTable *value_table = g_type_value_table_peek (G_VALUE_TYPE (dest_value));
GTypeValueTable *value_table;
g_return_if_fail (G_IS_VALUE (src_value));
g_return_if_fail (G_IS_VALUE (dest_value));
g_return_if_fail (g_type_is_a (G_VALUE_TYPE (src_value), G_VALUE_TYPE (dest_value)));
value_table = g_type_value_table_peek (G_VALUE_TYPE (dest_value));
if (!value_table)
g_return_if_fail (g_type_value_table_peek (G_VALUE_TYPE (dest_value)) != NULL);
@@ -78,6 +80,36 @@ g_value_copy (const GValue *src_value,
}
}
gboolean
g_value_fits_pointer (const GValue *value)
{
GTypeValueTable *value_table;
g_return_val_if_fail (G_IS_VALUE (value), FALSE);
value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
if (!value_table)
g_return_val_if_fail (g_type_value_table_peek (G_VALUE_TYPE (value)) != NULL, FALSE);
return value_table->value_peek_pointer != NULL;
}
gpointer
g_value_get_as_pointer (const GValue *value)
{
GTypeValueTable *value_table;
g_return_val_if_fail (G_IS_VALUE (value), NULL);
value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
if (!value_table)
g_return_val_if_fail (g_type_value_table_peek (G_VALUE_TYPE (value)) != NULL, NULL);
if (!value_table->value_peek_pointer)
g_return_val_if_fail (g_value_fits_pointer (value) == TRUE, NULL);
return value_table->value_peek_pointer (value);
}
void
g_value_unset (GValue *value)
{
@@ -189,8 +221,8 @@ g_value_register_exchange_func (GType value_type1,
{
ExchangeEntry entry;
g_return_if_fail (G_TYPE_IS_VALUE (value_type1));
g_return_if_fail (G_TYPE_IS_VALUE (value_type2));
g_return_if_fail (g_type_name (value_type1) != NULL);
g_return_if_fail (g_type_name (value_type2) != NULL);
g_return_if_fail (func != NULL);
entry.value_type1 = MIN (value_type1, value_type2);
@@ -218,7 +250,7 @@ gboolean
g_value_types_exchangable (GType value_type1,
GType value_type2)
{
g_return_val_if_fail (G_TYPE_IS_VALUE (value_type1), FALSE);
g_return_val_if_fail (G_TYPE_IS_VALUE (value_type1), FALSE); /* these might bite us, think G_TYPE_ENUM */
g_return_val_if_fail (G_TYPE_IS_VALUE (value_type2), FALSE);
return exchange_func_lookup (value_type1, value_type2, NULL) != NULL;

View File

@@ -31,8 +31,9 @@ extern "C" {
/* --- type macros --- */
#define G_TYPE_IS_VALUE(type) (g_type_value_table_peek (type) != NULL)
#define G_IS_VALUE(value) (G_TYPE_IS_VALUE (G_VALUE_TYPE (value))) /* FIXME */
#define G_VALUE_TYPE(value) (G_TYPE_FROM_CLASS (value))
#define G_IS_VALUE(value) (G_TYPE_CHECK_VALUE (value))
#define G_VALUE_HOLDS(value, g_type) (G_TYPE_CHECK_VALUE_TYPE ((value), (g_type)))
#define G_VALUE_TYPE(value) (((GValue*) (value))->g_type)
#define G_VALUE_TYPE_NAME(value) (g_type_name (G_VALUE_TYPE (value)))
@@ -66,6 +67,8 @@ gboolean g_value_convert (const GValue *src_value,
GValue *dest_value);
void g_value_reset (GValue *value);
void g_value_unset (GValue *value);
gboolean g_value_fits_pointer (const GValue *value);
gpointer g_value_get_as_pointer (const GValue *value);
/* --- implementation details --- */

View File

@@ -260,6 +260,54 @@ value_string_lcopy_value (const GValue *value,
return NULL;
}
static void
value_pointer_init (GValue *value)
{
value->data[0].v_pointer = 0;
}
static void
value_pointer_copy (const GValue *src_value,
GValue *dest_value)
{
dest_value->data[0].v_pointer = src_value->data[0].v_pointer;
}
static gpointer
value_pointer_peek_pointer (const GValue *value)
{
return value->data[0].v_pointer;
}
static gchar*
value_pointer_collect_value (GValue *value,
guint nth_value,
GType *collect_type,
GTypeCValue *collect_value)
{
value->data[0].v_pointer = collect_value->v_pointer;
*collect_type = 0;
return NULL;
}
static gchar*
value_pointer_lcopy_value (const GValue *value,
guint nth_value,
GType *collect_type,
GTypeCValue *collect_value)
{
gpointer *pointer_p = collect_value->v_pointer;
if (!pointer_p)
return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
*pointer_p = value->data[0].v_pointer;
*collect_type = 0;
return NULL;
}
/* --- type initialization --- */
void
@@ -287,15 +335,16 @@ g_value_types_init (void) /* sync with gtype.c */
value_long0_init, /* value_init */
NULL, /* value_free */
value_long0_copy, /* value_copy */
NULL, /* value_peek_pointer */
G_VALUE_COLLECT_INT, /* collect_type */
value_int_collect_value, /* collect_value */
G_VALUE_COLLECT_POINTER, /* lcopy_type */
value_char_lcopy_value, /* lcopy_value */
};
info.value_table = &value_table;
type = g_type_register_fundamental (G_TYPE_CHAR, "gchar", &info, &finfo);
type = g_type_register_fundamental (G_TYPE_CHAR, "gchar", &info, &finfo, 0);
g_assert (type == G_TYPE_CHAR);
type = g_type_register_fundamental (G_TYPE_UCHAR, "guchar", &info, &finfo);
type = g_type_register_fundamental (G_TYPE_UCHAR, "guchar", &info, &finfo, 0);
g_assert (type == G_TYPE_UCHAR);
}
@@ -306,13 +355,14 @@ g_value_types_init (void) /* sync with gtype.c */
value_long0_init, /* value_init */
NULL, /* value_free */
value_long0_copy, /* value_copy */
NULL, /* value_peek_pointer */
G_VALUE_COLLECT_INT, /* collect_type */
value_int_collect_value, /* collect_value */
G_VALUE_COLLECT_POINTER, /* lcopy_type */
value_boolean_lcopy_value, /* lcopy_value */
};
info.value_table = &value_table;
type = g_type_register_fundamental (G_TYPE_BOOLEAN, "gboolean", &info, &finfo);
type = g_type_register_fundamental (G_TYPE_BOOLEAN, "gboolean", &info, &finfo, 0);
g_assert (type == G_TYPE_BOOLEAN);
}
@@ -323,15 +373,16 @@ g_value_types_init (void) /* sync with gtype.c */
value_long0_init, /* value_init */
NULL, /* value_free */
value_long0_copy, /* value_copy */
NULL, /* value_peek_pointer */
G_VALUE_COLLECT_INT, /* collect_type */
value_int_collect_value, /* collect_value */
G_VALUE_COLLECT_POINTER, /* lcopy_type */
value_int_lcopy_value, /* lcopy_value */
};
info.value_table = &value_table;
type = g_type_register_fundamental (G_TYPE_INT, "gint", &info, &finfo);
type = g_type_register_fundamental (G_TYPE_INT, "gint", &info, &finfo, 0);
g_assert (type == G_TYPE_INT);
type = g_type_register_fundamental (G_TYPE_UINT, "guint", &info, &finfo);
type = g_type_register_fundamental (G_TYPE_UINT, "guint", &info, &finfo, 0);
g_assert (type == G_TYPE_UINT);
}
@@ -342,15 +393,16 @@ g_value_types_init (void) /* sync with gtype.c */
value_long0_init, /* value_init */
NULL, /* value_free */
value_long0_copy, /* value_copy */
NULL, /* value_peek_pointer */
G_VALUE_COLLECT_LONG, /* collect_type */
value_long_collect_value, /* collect_value */
G_VALUE_COLLECT_POINTER, /* lcopy_type */
value_long_lcopy_value, /* lcopy_value */
};
info.value_table = &value_table;
type = g_type_register_fundamental (G_TYPE_LONG, "glong", &info, &finfo);
type = g_type_register_fundamental (G_TYPE_LONG, "glong", &info, &finfo, 0);
g_assert (type == G_TYPE_LONG);
type = g_type_register_fundamental (G_TYPE_ULONG, "gulong", &info, &finfo);
type = g_type_register_fundamental (G_TYPE_ULONG, "gulong", &info, &finfo, 0);
g_assert (type == G_TYPE_ULONG);
}
@@ -361,13 +413,14 @@ g_value_types_init (void) /* sync with gtype.c */
value_float_init, /* value_init */
NULL, /* value_free */
value_float_copy, /* value_copy */
NULL, /* value_peek_pointer */
G_VALUE_COLLECT_DOUBLE, /* collect_type */
value_float_collect_value, /* collect_value */
G_VALUE_COLLECT_POINTER, /* lcopy_type */
value_float_lcopy_value, /* lcopy_value */
};
info.value_table = &value_table;
type = g_type_register_fundamental (G_TYPE_FLOAT, "gfloat", &info, &finfo);
type = g_type_register_fundamental (G_TYPE_FLOAT, "gfloat", &info, &finfo, 0);
g_assert (type == G_TYPE_FLOAT);
}
@@ -378,13 +431,14 @@ g_value_types_init (void) /* sync with gtype.c */
value_double_init, /* value_init */
NULL, /* value_free */
value_double_copy, /* value_copy */
NULL, /* value_peek_pointer */
G_VALUE_COLLECT_DOUBLE, /* collect_type */
value_double_collect_value, /* collect_value */
G_VALUE_COLLECT_POINTER, /* lcopy_type */
value_double_lcopy_value, /* lcopy_value */
};
info.value_table = &value_table;
type = g_type_register_fundamental (G_TYPE_DOUBLE, "gdouble", &info, &finfo);
type = g_type_register_fundamental (G_TYPE_DOUBLE, "gdouble", &info, &finfo, 0);
g_assert (type == G_TYPE_DOUBLE);
}
@@ -395,15 +449,34 @@ g_value_types_init (void) /* sync with gtype.c */
value_string_init, /* value_init */
value_string_free_value, /* value_free */
value_string_copy_value, /* value_copy */
value_pointer_peek_pointer, /* value_peek_pointer */
G_VALUE_COLLECT_POINTER, /* collect_type */
value_string_collect_value, /* collect_value */
G_VALUE_COLLECT_POINTER, /* lcopy_type */
value_string_lcopy_value, /* lcopy_value */
};
info.value_table = &value_table;
type = g_type_register_fundamental (G_TYPE_STRING, "gstring", &info, &finfo);
type = g_type_register_fundamental (G_TYPE_STRING, "gstring", &info, &finfo, 0);
g_assert (type == G_TYPE_STRING);
}
/* G_TYPE_POINTER
*/
{
static const GTypeValueTable value_table = {
value_pointer_init, /* value_init */
NULL, /* value_free */
value_pointer_copy, /* value_copy */
value_pointer_peek_pointer, /* value_peek_pointer */
G_VALUE_COLLECT_POINTER, /* collect_type */
value_pointer_collect_value, /* collect_value */
G_VALUE_COLLECT_POINTER, /* lcopy_type */
value_pointer_lcopy_value, /* lcopy_value */
};
info.value_table = &value_table;
type = g_type_register_fundamental (G_TYPE_POINTER, "gpointer", &info, &finfo, 0);
g_assert (type == G_TYPE_POINTER);
}
}
@@ -418,7 +491,7 @@ g_value_set_char (GValue *value,
}
gint8
g_value_get_char (GValue *value)
g_value_get_char (const GValue *value)
{
g_return_val_if_fail (G_IS_VALUE_CHAR (value), 0);
@@ -435,7 +508,7 @@ g_value_set_uchar (GValue *value,
}
guint8
g_value_get_uchar (GValue *value)
g_value_get_uchar (const GValue *value)
{
g_return_val_if_fail (G_IS_VALUE_UCHAR (value), 0);
@@ -452,7 +525,7 @@ g_value_set_boolean (GValue *value,
}
gboolean
g_value_get_boolean (GValue *value)
g_value_get_boolean (const GValue *value)
{
g_return_val_if_fail (G_IS_VALUE_BOOLEAN (value), 0);
@@ -469,7 +542,7 @@ g_value_set_int (GValue *value,
}
gint
g_value_get_int (GValue *value)
g_value_get_int (const GValue *value)
{
g_return_val_if_fail (G_IS_VALUE_INT (value), 0);
@@ -486,7 +559,7 @@ g_value_set_uint (GValue *value,
}
guint
g_value_get_uint (GValue *value)
g_value_get_uint (const GValue *value)
{
g_return_val_if_fail (G_IS_VALUE_UINT (value), 0);
@@ -503,7 +576,7 @@ g_value_set_long (GValue *value,
}
glong
g_value_get_long (GValue *value)
g_value_get_long (const GValue *value)
{
g_return_val_if_fail (G_IS_VALUE_LONG (value), 0);
@@ -520,7 +593,7 @@ g_value_set_ulong (GValue *value,
}
gulong
g_value_get_ulong (GValue *value)
g_value_get_ulong (const GValue *value)
{
g_return_val_if_fail (G_IS_VALUE_ULONG (value), 0);
@@ -537,7 +610,7 @@ g_value_set_float (GValue *value,
}
gfloat
g_value_get_float (GValue *value)
g_value_get_float (const GValue *value)
{
g_return_val_if_fail (G_IS_VALUE_FLOAT (value), 0);
@@ -554,7 +627,7 @@ g_value_set_double (GValue *value,
}
gdouble
g_value_get_double (GValue *value)
g_value_get_double (const GValue *value)
{
g_return_val_if_fail (G_IS_VALUE_DOUBLE (value), 0);
@@ -572,7 +645,7 @@ g_value_set_string (GValue *value,
}
gchar*
g_value_get_string (GValue *value)
g_value_get_string (const GValue *value)
{
g_return_val_if_fail (G_IS_VALUE_STRING (value), NULL);
@@ -580,9 +653,26 @@ g_value_get_string (GValue *value)
}
gchar*
g_value_dup_string (GValue *value)
g_value_dup_string (const GValue *value)
{
g_return_val_if_fail (G_IS_VALUE_STRING (value), NULL);
return g_strdup (value->data[0].v_pointer);
}
void
g_value_set_pointer (GValue *value,
gpointer v_pointer)
{
g_return_if_fail (G_IS_VALUE_POINTER (value));
value->data[0].v_pointer = v_pointer;
}
gpointer
g_value_get_pointer (GValue *value)
{
g_return_val_if_fail (G_IS_VALUE_POINTER (value), NULL);
return value->data[0].v_pointer;
}

View File

@@ -8,7 +8,7 @@
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
@@ -22,7 +22,7 @@
#define __G_VALUETYPES_H__
#include <gobject/gvalue.h>
#include <gobject/gvalue.h>
#ifdef __cplusplus
@@ -31,50 +31,54 @@ extern "C" {
/* --- type macros --- */
#define G_IS_VALUE_CHAR(value) (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_CHAR))
#define G_IS_VALUE_UCHAR(value) (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_UCHAR))
#define G_IS_VALUE_BOOLEAN(value) (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_BOOLEAN))
#define G_IS_VALUE_INT(value) (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_INT))
#define G_IS_VALUE_UINT(value) (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_UINT))
#define G_IS_VALUE_LONG(value) (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_LONG))
#define G_IS_VALUE_ULONG(value) (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_ULONG))
#define G_IS_VALUE_FLOAT(value) (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_FLOAT))
#define G_IS_VALUE_DOUBLE(value) (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_DOUBLE))
#define G_IS_VALUE_STRING(value) (G_TYPE_CHECK_CLASS_TYPE ((value), G_TYPE_STRING))
#define G_IS_VALUE_CHAR(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_CHAR))
#define G_IS_VALUE_UCHAR(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_UCHAR))
#define G_IS_VALUE_BOOLEAN(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_BOOLEAN))
#define G_IS_VALUE_INT(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_INT))
#define G_IS_VALUE_UINT(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_UINT))
#define G_IS_VALUE_LONG(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_LONG))
#define G_IS_VALUE_ULONG(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_ULONG))
#define G_IS_VALUE_FLOAT(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_FLOAT))
#define G_IS_VALUE_DOUBLE(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_DOUBLE))
#define G_IS_VALUE_STRING(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_STRING))
#define G_IS_VALUE_POINTER(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_POINTER))
/* --- prototypes --- */
void g_value_set_char (GValue *value,
gint8 v_char);
gint8 g_value_get_char (GValue *value);
void g_value_set_uchar (GValue *value,
guint8 v_uchar);
guint8 g_value_get_uchar (GValue *value);
void g_value_set_boolean (GValue *value,
gboolean v_boolean);
gboolean g_value_get_boolean (GValue *value);
void g_value_set_int (GValue *value,
gint v_int);
gint g_value_get_int (GValue *value);
void g_value_set_uint (GValue *value,
guint v_uint);
guint g_value_get_uint (GValue *value);
void g_value_set_long (GValue *value,
glong v_long);
glong g_value_get_long (GValue *value);
void g_value_set_ulong (GValue *value,
gulong v_ulong);
gulong g_value_get_ulong (GValue *value);
void g_value_set_float (GValue *value,
gfloat v_float);
gfloat g_value_get_float (GValue *value);
void g_value_set_double (GValue *value,
gdouble v_double);
gdouble g_value_get_double (GValue *value);
void g_value_set_string (GValue *value,
const gchar *v_string);
gchar* g_value_get_string (GValue *value);
gchar* g_value_dup_string (GValue *value);
void g_value_set_char (GValue *value,
gint8 v_char);
gint8 g_value_get_char (const GValue *value);
void g_value_set_uchar (GValue *value,
guint8 v_uchar);
guint8 g_value_get_uchar (const GValue *value);
void g_value_set_boolean (GValue *value,
gboolean v_boolean);
gboolean g_value_get_boolean (const GValue *value);
void g_value_set_int (GValue *value,
gint v_int);
gint g_value_get_int (const GValue *value);
void g_value_set_uint (GValue *value,
guint v_uint);
guint g_value_get_uint (const GValue *value);
void g_value_set_long (GValue *value,
glong v_long);
glong g_value_get_long (const GValue *value);
void g_value_set_ulong (GValue *value,
gulong v_ulong);
gulong g_value_get_ulong (const GValue *value);
void g_value_set_float (GValue *value,
gfloat v_float);
gfloat g_value_get_float (const GValue *value);
void g_value_set_double (GValue *value,
gdouble v_double);
gdouble g_value_get_double (const GValue *value);
void g_value_set_string (GValue *value,
const gchar *v_string);
gchar* g_value_get_string (const GValue *value);
gchar* g_value_dup_string (const GValue *value);
void g_value_set_pointer (GValue *value,
gpointer v_pointer);
gpointer g_value_get_pointer (GValue *value);