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);
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);
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);