GObject system provides properties. Properties are values kept by instances, which is a descendant of GObject, and they are open to other instances. They can be accessed with their names.
For example, GtkWindow has “title”, “default-width”, “default-height” and other properties. The string “title” is the name of the property. The name of a property is a string that begins with a letter followed by letters, digits, dash (‘-’) or underscore (’_’). Dash and underscore is used as separators but they cannot be mixed. Using dash is more efficient than underscore. For example, “value”, “double” and “double-value” are correct property names. “_value” or “-value” are incorrect.
Properties have various types of values. The type of “title” property is string. The type of “default-width” and “default-height” is integer.
Properties are set and got with functions defined in GObject.
g_object_new
and g_object_set
are often
used.g_object_get
is often used.The functions above belongs to GObject, but they can be used for any descendant object of GObject. The following is an example of GtkWindow, which is a descendant object of GObject.
An instance is created and its properties are set with
g_object_new
.
*win;
GtkWindow = g_object_new (GTK_TYPE_WINDOW, "title", "Hello", "default-width", 800, "default-height", 600, NULL); win
The example above creates an instance of GtkWindow and sets the properties.
The last parameter of g_object_new
is NULL
which is the end of the list of properties.
If you have already created a GtkWindow instance and you want to set
its title, you can use g_object_set
.
*win;
GtkWindow = g_object_new (GTK_TYPE_WINDOW, NULL);
win (win, "title", "Good bye", NULL); g_object_set
You can get the value of a property with
g_object_get
.
*win;
GtkWindow char *title;
int width, height;
= g_object_new (GTK_TYPE_WINDOW, "title", "Hello", "default-width", 800, "default-height", 600, NULL);
win (win, "title", &title, "default-width", &width, "default-height", &height, NULL);
g_object_get ("%s, %d, %d\n", title, width, height);
g_print (title); g_free
The rest of this section is about implementing properties in a descendant of GObject. It is divided into two things.
set_property
and get_property
class
method to complement g_object_set
and
g_object_get
.GParamSpec is a fundamental object. GParamSpec and GObject don’t have parent-child relationship. GParamSpec has information of parameters. “ParamSpec” is short for “Parameter specification”.
For example,
= g_param_spec_double ("value", "val", "Double value",
double_property -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
); G_PARAM_READWRITE
This function creates a GParamSpec instance, more precisely a GParamSpecDouble instance. GParamSpecDouble is a child of GParamSpec.
The instance has information:
double
in g_param_spec_double
, implies the
type.G_PARAM_READWRITE
is a flag.
G_PARAM_READWRITE
means that the parameter is readable and
writable.For further information, refer to the GObject API reference.
GParamSpec is used for the registration for GObject properties. This is extracted from tdouble.c in src/tdouble6.
#define PROP_DOUBLE 1
static GParamSpec *double_property = NULL;
static void
(TDoubleClass *class) {
t_double_class_init *gobject_class = G_OBJECT_CLASS (class);
GObjectClass
->set_property = t_double_set_property;
gobject_class->get_property = t_double_get_property;
gobject_class= g_param_spec_double ("value", "val", "Double value", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE);
double_property (gobject_class, PROP_DOUBLE, double_property);
g_object_class_install_property }
The variable double_property
is static. GParamSpec
instance is assigned to double_property
.
The function g_object_class_install_property
installs a
property. It must be called after set_property
and
get_property
methods are overridden. These methods will be
explained later. The arguments are TDoubleClass class, PROP_DOUBLE
(property id) and GParamSpec instance. Property id is used to identify
the property in tdouble.c
. It is a positive integer.
Property values vary from instance to instance. Therefore, the value is stored to each instance of the object.
The function g_object_set
is given a value as an
argument and stores the value. But how does g_object_set
know the instance to store? It is compiled before the object is made.
So, it doesn’t know where to store the value at all. That part needs to
be programmed by the writer of the object with overriding.
The function g_object_set
first checks the property and
value, then it creates GValue (generic value) from the value. And it
calls a function pointed by set_property
in the class. Look
at the diagram below.
The member set_property
in GObjectClass class points
g_object_do_set_property
in GObject program, which is made
by compiling gobject.c
. The GObjectClass part of the
TDoubleClass structure (it is the same as TDoubleClass because
TDoubleClass doesn’t have its own area) is initialized by copying from
the contents of GObjectClass. Therefore, set_property
in
TDoubleClass class points g_object_do_set_property
in
GObject program. But g_object_do_set_property
doesn’t store
the value to the TDouble instance. The writer of TDouble object makes
t_double_set_property
function in tdouble.c
.
And assigns the address of t_double_set_property
to
set_property
in TDoubleClass class. It is shown with a red
curve in the diagram. As a result, g_object_set
calls
t_double_set_property
instead of
g_object_do_set_property
(red dotted curve) and the value
will be stored in the TDouble instance. See the function
t_double_class_init
above. It changes the member
gobject_class->set_property
to point the function
t_double_set_property
. The function
g_object_set
sees the TDoubleClass and call the function
pointed by the member set_property
.
The program of t_double_set_property
and
t_double_get_property
will shown later.
GValue is generic value. GValue consists of type and value.
The type is any Gtype. The table below shows some GType, but not all.
GType | C type | type name | notes |
---|---|---|---|
G_TYPE_CHAR | char | gchar | |
G_TYPE_BOOLEAN | int | gboolean | |
G_TYPE_INT | int | gint | |
G_TYPE_FLOAT | float | gfloat | |
G_TYPE_DOUBLE | double | gdouble | |
G_TYPE_STRING | gchararray | null-terminated Cstring | |
G_TYPE_PARAM | GParam | GParamSpec | |
G_TYPE_OBJECT | GObject | ||
G_TYPE_VARIANT | GVariant |
If the type of a GValue value
is
G_TYPE_DOUBLE
, value
can be get with
g_value_get_double
function.
;
GValue value= ... ... ... (a GValue object is assigned. Its type is double.)
value double v;
= g_value_get_double (&value); v
Conversely, you can set GValue value
with
g_value_set_double
.
(value, 123.45); g_value_set_double
Refer to GObject API Reference – GValue for further information.
g_object_set
makes GValue from the value of the property
given as an argument. And calls a function pointed by
set_property
in the class. The function is declared in
GObjectClass structure.
struct _GObjectClass
{
... ... ...
... ... ...
/* overridable methods */
void (*set_property) (GObject *object,
,
guint property_idconst GValue *value,
*pspec);
GParamSpec void (*get_property) (GObject *object,
,
guint property_id*value,
GValue *pspec);
GParamSpec ... ... ...
... ... ...
};
t_double_set_property
just get the value from GValue
value
and store it to the TDouble instance.
static void
t_double_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) {
TDouble *self = T_DOUBLE (object);
if (property_id == PROP_DOUBLE)
self->value = g_value_get_double (value);
else
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
object
to TDouble object
self
.self->value
. The assigned value is got with
g_value_get_double
function.In the same way, t_double_get_property
stores
self->value
to GValue.
static void
t_double_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) {
TDouble *self = T_DOUBLE (object);
if (property_id == PROP_DOUBLE)
g_value_set_double (value, self->value);
else
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
GObject emits “notify” signal when a property is set. When you connect “notify” signal to your handler, you can specify a detail which is the name of the property. The detail is added to the signal name with the delimiter “::”.
(G_OBJECT (d1), "notify::value", G_CALLBACK (notify_cb), NULL); g_signal_connect
If you don’t specify details, the handler is called whenever any properties are set. So, usually the detail is set.
Notify signal doesn’t mean that the value of the property is changed.
It is emitted even if the same value is set. You might want to emit the
notify signal only when the property is actually changed. In that case,
you define the GPramSpec with G_PARAM_EXPLICIT_NOTIFY
flag.
Then, the notify signal isn’t emitted automatically. Instead you call
g_object_notify_by_pspec
function to emit “notify” signal
explicitly when the value of the property is actually changed.
It is possible to make setter and getter for the property. But if you just set the instance member in your setter, notify signal isn’t emitted.
void
(TDouble *self, double value) {
t_double_set_value (T_IS_DOUBLE (self));
g_return_if_fail
->value = value; /* Just set d->value. No "notify" signal is emitted. */
self}
Users must be confused if they want to catch the “notify” signal. One
solution is use g_object_set
in your setter. Then, notify
signal will be emitted even if a user uses the setter function.
void
(TDouble *d, double value) {
t_double_set_value (T_IS_DOUBLE (d));
g_return_if_fail
(d, "value", value, NULL); /* Use g_object_set. "notify" signal will be emitted. */
g_object_set }
The other solution is use g_object_notify_by_pspec
to
emit the signal explicitly. Anyway, if you make a setter for your
property, be careful about notify signal.
If you define more than one property, use an array of property id. It
is good for you to see Gtk source files such as gtklabel.c
.
GtkLabel has 18 properties.
There’s an example in src/tdouble6 directory.
Make TInt object. It is like TDouble but the value type is int. Define “div-by-zero” signal and “value” property.
Compare your answer to the files in src/tint directory.