A type, as manipulated by the GLib type system, is much more generic than what is usually understood as an Object type. It is best explained by looking at the structure and the functions used to register new types in the type system. typedef struct _GTypeInfo GTypeInfo; struct _GTypeInfo { /* interface types, classed types, instantiated types */ guint16 class_size; GBaseInitFunc base_init; GBaseFinalizeFunc base_finalize; /* classed types, instantiated types */ GClassInitFunc class_init; GClassFinalizeFunc class_finalize; gconstpointer class_data; /* instantiated types */ guint16 instance_size; guint16 n_preallocs; GInstanceInitFunc instance_init; /* value handling */ const GTypeValueTable *value_table; }; GType g_type_register_static (GType parent_type, const gchar *type_name, const GTypeInfo *info, GTypeFlags flags); GType g_type_register_fundamental (GType type_id, const gchar *type_name, const GTypeInfo *info, const GTypeFundamentalInfo *finfo, GTypeFlags flags);
Fundamental types are top-level types which do not derive from any other type
while other non-fundamental types derive from other types.
Upon initialization by Fundamental and non-fundamental types are defined by:
Fundamental types are also defined by a set of GTypeFundamentalFlags
which are stored in a GTypeFundamentalInfo.
Non-fundamental types are furthermore defined by the type of their parent which is
passed as the parent_type parameter to The major common point between all GLib types (fundamental and non-fundamental, classed and non-classed, instantiable and non-instantiable) is that they can all be manipulated through a single API to copy/assign them.
The GValue structure is used as an abstract container for all of these
types. Its simplistic API (defined in
The following code shows how you can copy around a 64 bit integer, as well as a GObject
instance pointer (sample code for this is located in the source tarball for this document in
static void test_int (void) { GValue a_value = {0, }; GValue b_value = {0, }; guint64 a, b; a = 0xdeadbeaf; g_value_init (&a_value, G_TYPE_UINT64); g_value_set_uint64 (&a_value, a); g_value_init (&b_value, G_TYPE_UINT64); g_value_copy (&a_value, &b_value); b = g_value_get_uint64 (&b_value); if (a == b) { g_print ("Yay !! 10 lines of code to copy around a uint64.\n"); } else { g_print ("Are you sure this is not a Z80 ?\n"); } } static void test_object (void) { GObject *obj; GValue obj_vala = {0, }; GValue obj_valb = {0, }; obj = g_object_new (MAMAN_TYPE_BAR, NULL); g_value_init (&obj_vala, MAMAN_TYPE_BAR); g_value_set_object (&obj_vala, obj); g_value_init (&obj_valb, G_TYPE_OBJECT); /* g_value_copy's semantics for G_TYPE_OBJECT types is to copy the reference. This function thus calls g_object_ref. It is interesting to note that the assignment works here because MAMAN_TYPE_BAR is a G_TYPE_OBJECT. */ g_value_copy (&obj_vala, &obj_valb); g_object_unref (G_OBJECT (obj)); g_object_unref (G_OBJECT (obj)); } The important point about the above code is that the exact semantics of the copy calls is undefined since they depend on the implementation of the copy function. Certain copy functions might decide to allocate a new chunk of memory and then to copy the data from the source to the destination. Others might want to simply increment the reference count of the instance and copy the reference to the new GValue.
The value_table used to specify these assignment functions is defined in
typedef struct _GTypeValueTable GTypeValueTable; struct _GTypeValueTable { void (*value_init) (GValue *value); void (*value_free) (GValue *value); void (*value_copy) (const GValue *src_value, GValue *dest_value); /* varargs functionality (optional) */ gpointer (*value_peek_pointer) (const GValue *value); gchar *collect_format; gchar* (*collect_value) (GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags); gchar *lcopy_format; gchar* (*lcopy_value) (const GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags); }; Interestingly, it is also very unlikely you will ever need to specify a value_table during type registration because these value_tables are inherited from the parent types for non-fundamental types which means that unless you want to write a fundamental type (not a great idea!), you will not need to provide a new value_table since you will inherit the value_table structure from your parent type. [2]
Please note that there exists another registration function: the
|