Purpose of GValue, GTypeValueTable, GTypeInfo and GParamSpec

The GObject library is really terribly documented. It is too hard to understand the purpose of the created entities. Namely, I do not get the roles of GValue , GTypeValueTable , GTypeInfo , GParamSpec and TypeData .

In short, the type registration process is as follows. Each type is represented by a TypeNode structure. There are 2 stores of TypeNode structures: static_fundamental_type_nodes array for storing TypeNodes static fundamental types and a hash table static_type_nodes_ht for static non-factor types. Each GType is only the memory address of the corresponding TypeNode in the case of non-fundamental types or the TypeNode index in static_fundamental_type_nodes in the case of fundamental types. What happens to dynamic types - I don't know, please explain to me if you can. The corresponding code is in the gtype_init function responsible for initializing the type system: http://git.gnome.org/browse/glib/tree/gobject/gtype.c#n4323 .

enter image description here

GValue , GParamSpec and GObject are GTypes themselves, so they are registered as types.

GValue used to register new type values ​​through it, but how ?.

GParameters and GParamSpec seem to be necessary for registering a GObject type (not sure). How exactly is this done? What are the roles of each?

MOST IMPORTANT: What are the roles of GTypeValueTable , GTypeInfo and TypeData ? TypeData refers to TypeNode and contains GTypeValueTable , as well as BoxedData, ClassData, IFaceData, InstanceData substructures (why an instance, we do not register the type?). Moreover, they seem to duplicate each other, because EVERYTHING contains references to base_init / finalize, class_init / finalize has a link to GTypeValueTable .

So, GObject papas, if you are reading this, please explain it yourself! Describe the purpose of the structures you use.

+6
source share
1 answer

Only two of them that you really need to take care of if you are not trying to work with very low level code are GValue and GParamType

I'll start with GParamType

GParamType used to register properties with GObject. Say, for example, I have a subclass of GObject called Person, and I wanted it to have two properties: Name and Age. In the class_init function class_init I would register them like this:

 { GParamSpec *pspec; . . . pspec = g_param_spec_string ("name", "Name", "The name of the person", "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_NAME, pspec); pspec = g_param_spec_int ("age", "Age", "The age of the person", 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_AGE, spec); . . . } 

Now you can call g_object_get or g_object_set for these properties, and the system will know how to handle it

 char *name; int age; g_object_set (G_OBJECT (person), "name", "Steve", "age", 37, NULL); g_object_get (G_OBJECT (person), "name", &name, "age", &age, NULL); g_print ("%s is %d years old\n", name, age); // And because the type system knows when a property is a string, it knows how to give // you a copy of the string, so you need to free it once you've finished with it g_free (name); 

Various parameters are described here: GParamSpec There are GValue types for all standard types: strings, bools, int, etc. and some other libraries, such as GStreamer, will register their own custom ones.

Outside of setting properties on GObjectClass, you very rarely have to deal with GParamSpec. The two main cases when they appear are in the GObjectClass set / get_property methods and the GObject notification signal. In the latter case, it is useful to determine which property the notification signal received by calling g_param_spec_get_name , but in fact it is better to use a more specific notification signal like this:

 g_signal_connect (person, "notify::name", G_CALLBACK (name_changed_cb), NULL); g_signal_connect (person, "notify::age", G_CALLBACK (age_changed_cb), NULL); 

but not

 g_signal_connect (person, "notify", G_CALLBACK (something_changed_cb), NULL); 

Sometimes you may need to create your own structures and use them for properties. For example, if I had

 struct _PersonDetails { char *name; int age; } 

and instead of having two properties of the Person object, I wanted one of them to be called "parts." A system like GLib does not know how to work with my custom struct _PersonDetails , so I would need to create a box type for it so that it knows how to copy / release the structure correctly, since it is passed inside the internal Glib objects. And that is where GValue comes GValue .

GValue designed to carry values ​​of different types, so you can copy and release them correctly (if they should be), and so you can use common functions.

For example, the GObjectClass set_property method has a prototype

 void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) 

This means that any type that can be represented by GValue can be passed, and special functions such as set_int_property, set_string_property, set_bool_property are not required.

It also means that the g_object_set and g_object_get know how to handle the passed parameters, because it knows that the "name" property is registered as a string type, and it has the necessary functions to copy / free this string.

More about GValue can be found here - General Values

To register our custom struct _PersonDetails with a system like GLib, we will create our own boxed type that tells how to copy and free it. Details here: Boxed Types

 G_DEFINE_BOXED_TYPE (PersonDetails, person_details, person_details_copy, person_details_free) . . . static gpointer person_details_copy (gpointer data) { struct _PersonDetails *details = (struct _PersonDetails *)data; struct _PersonDetails *copy = g_new (struct _PersonDetails, 1); // We need to copy the string copy->name = g_strdup (details->name); copy->age = details->age; return (gpointer) copy; } static void person_details_free (gpointer data) { struct _PersonDetails *details = (struct _PersonDetails *)data; // name was allocated so it needs freed as well g_free (details->name); g_free (details); } 

Now we can register our type using

 pspec = g_param_spec_boxed ("details", "Details", "The person details", person_details_get_type (), G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_DETAILS, pspec); 
+14
source

All Articles