1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
|
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
]>
<chapter id="chapter-gobject">
<title>The GObject base class</title>
<para>
The previous chapter discussed the details of GLib's Dynamic Type System.
The GObject library also contains an implementation for a base fundamental
type named <link linkend="GObject"><type>GObject</type></link>.
</para>
<para>
<link linkend="GObject"><type>GObject</type></link> is a fundamental classed instantiatable type. It implements:
<itemizedlist>
<listitem><para>Memory management with reference counting</para></listitem>
<listitem><para>Construction/Destruction of instances</para></listitem>
<listitem><para>Generic per-object properties with set/get function pairs</para></listitem>
<listitem><para>Easy use of signals</para></listitem>
</itemizedlist>
All the GNOME libraries which use the GLib type system (like GTK and GStreamer)
inherit from <link linkend="GObject"><type>GObject</type></link> which is why it is important to understand
the details of how it works.
</para>
<sect1 id="gobject-instantiation">
<title>Object instantiation</title>
<para>
The <function><link linkend="g-object-new">g_object_new</link></function>
family of functions can be used to instantiate any GType which inherits
from the GObject base type. All these functions make sure the class and
instance structures have been correctly initialized by GLib's type system
and then invoke at one point or another the constructor class method
which is used to:
<itemizedlist>
<listitem><para>
Allocate and clear memory through <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>,
</para></listitem>
<listitem><para>
Initialize the object's instance with the construction properties.
</para></listitem>
</itemizedlist>
Although one can expect all class and instance members (except the fields
pointing to the parents) to be set to zero, some consider it good practice
to explicitly set them.
</para>
<para>
Once all construction operations have been completed and constructor
properties set, the constructed class method is called.
</para>
<para>
Objects which inherit from GObject are allowed to override this
constructed class method.
The example below shows how <type>ViewerFile</type> overrides the parent's construction process:
<informalexample><programlisting>
#define VIEWER_TYPE_FILE viewer_file_get_type ()
G_DECLARE_FINAL_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject)
struct _ViewerFile
{
GObject parent_instance;
/* instance members */
gchar *filename;
guint zoom_level;
};
/* will create viewer_file_get_type and set viewer_file_parent_class */
G_DEFINE_TYPE (ViewerFile, viewer_file, G_TYPE_OBJECT)
static void
viewer_file_constructed (GObject *obj)
{
/* update the object state depending on constructor properties */
/* Always chain up to the parent constructed function to complete object
* initialisation. */
G_OBJECT_CLASS (viewer_file_parent_class)->constructed (obj);
}
static void
viewer_file_finalize (GObject *obj)
{
ViewerFile *self = VIEWER_FILE (obj);
g_free (self->filename);
/* Always chain up to the parent finalize function to complete object
* destruction. */
G_OBJECT_CLASS (viewer_file_parent_class)->finalize (obj);
}
static void
viewer_file_class_init (ViewerFileClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = viewer_file_constructed;
object_class->finalize = viewer_file_finalize;
}
static void
viewer_file_init (ViewerFile *self)
{
/* initialize the object */
}
</programlisting></informalexample>
If the user instantiates an object <type>ViewerFile</type> with:
<informalexample><programlisting>
ViewerFile *file = g_object_new (VIEWER_TYPE_FILE, NULL);
</programlisting></informalexample>
If this is the first instantiation of such an object, the
<function>viewer_file_class_init</function> function will be invoked
after any <function>viewer_file_base_class_init</function> function.
This will make sure the class structure of this new object is
correctly initialized. Here, <function>viewer_file_class_init</function>
is expected to override the object's class methods and setup the
class' own methods. In the example above, the <literal>constructed</literal>
method is the only overridden method: it is set to
<function>viewer_file_constructed</function>.
</para>
<para>
Once <function><link linkend="g-object-new">g_object_new</link></function> has obtained a reference to an initialized
class structure, it invokes its constructor method to create an instance of the new
object, if the constructor has been overridden in <function>viewer_file_class_init</function>.
Overridden constructors must chain up to their parent’s constructor. In
order to find the parent class and chain up to the parent class
constructor, we can use the <literal>viewer_file_parent_class</literal>
pointer that has been set up for us by the
<link linkend="G-DEFINE-TYPE:CAPS"><literal>G_DEFINE_TYPE</literal></link>
macro.
</para>
<para>
Finally, at one point or another, <function>g_object_constructor</function> is invoked
by the last constructor in the chain. This function allocates the object's instance buffer
through <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>
which means that the <function>instance_init</function> function is invoked at this point if one
was registered. After <function>instance_init</function> returns, the object is fully initialized and should be
ready to have its methods called by the user. When
<function><link linkend="g-type-create-instance">g_type_create_instance</link></function>
returns, <function>g_object_constructor</function> sets the construction properties
(i.e. the properties which were given to <function><link linkend="g-object-new">g_object_new</link></function>) and returns
to the user's constructor.
</para>
<para>
The process described above might seem a bit complicated, but it can be
summarized easily by the table below which lists the functions invoked
by <function><link linkend="g-object-new">g_object_new</link></function>
and their order of invocation:
</para>
<para>
<table id="gobject-construction-table">
<title><function><link linkend="g-object-new">g_object_new</link></function></title>
<tgroup cols="3">
<colspec colwidth="*" colnum="1" align="left"/>
<colspec colwidth="*" colnum="2" align="left"/>
<colspec colwidth="8*" colnum="3" align="left"/>
<thead>
<row>
<entry>Invocation time</entry>
<entry>Function invoked</entry>
<entry>Function's parameters</entry>
<entry>Remark</entry>
</row>
</thead>
<tbody>
<row>
<entry morerows="3">First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry>
<entry>target type's <function>base_init</function> function</entry>
<entry>On the inheritance tree of classes from fundamental type to target type.
<function>base_init</function> is invoked once for each class structure.</entry>
<entry>Never used in practice. Unlikely you will need it.</entry>
</row>
<row>
<!--entry>First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
<entry>target type's <function>class_init</function> function</entry>
<entry>On target type's class structure</entry>
<entry>
Here, you should make sure to initialize or override class methods (that is,
assign to each class' method its function pointer) and create the signals and
the properties associated to your object.
</entry>
</row>
<row>
<!--entry>First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
<entry>interface's <function>base_init</function> function</entry>
<entry>On interface's vtable</entry>
<entry></entry>
</row>
<row>
<!--entry>First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
<entry>interface's <function>interface_init</function> function</entry>
<entry>On interface's vtable</entry>
<entry></entry>
</row>
<row>
<entry morerows="2">Each call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry>
<entry>target type's class <function>constructor</function> method: <function>GObjectClass->constructor</function></entry>
<entry>On object's instance</entry>
<entry>
If you need to handle construct properties in a custom way, or implement a singleton class, override the constructor
method and make sure to chain up to the object's
parent class before doing your own initialization.
In doubt, do not override the constructor method.
</entry>
</row>
<row>
<!--entry>Each call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
<entry>type's <function>instance_init</function> function</entry>
<entry>On the inheritance tree of classes from fundamental type to target type.
the <function>instance_init</function> provided for each type is invoked once for each instance
structure.</entry>
<entry>
Provide an <function>instance_init</function> function to initialize your object before its construction
properties are set. This is the preferred way to initialize a GObject instance.
This function is equivalent to C++ constructors.
</entry>
</row>
<row>
<!--entry>Each call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
<entry>target type's class <function>constructed</function> method: <function>GObjectClass->constructed</function></entry>
<entry>On object's instance</entry>
<entry>
If you need to perform object initialization steps after all construct properties have been set.
This is the final step in the object initialization process, and is only called if the <function>constructor</function>
method returned a new object instance (rather than, for example, an existing singleton).
</entry>
</row>
</tbody>
</tgroup>
</table>
</para>
<para>
Readers should feel concerned about one little twist in the order in
which functions are invoked: while, technically, the class' constructor
method is called <emphasis>before</emphasis> the GType's <function>instance_init</function>
function (since <function><link linkend="g-type-create-instance">g_type_create_instance</link></function> which calls <function>instance_init</function> is called by
<function>g_object_constructor</function> which is the top-level class
constructor method and to which users are expected to chain to), the
user's code which runs in a user-provided constructor will always
run <emphasis>after</emphasis> GType's <function>instance_init</function> function since the
user-provided constructor <emphasis>must</emphasis> (you've been warned)
chain up <emphasis>before</emphasis> doing anything useful.
</para>
</sect1>
<sect1 id="gobject-memory">
<title>Object memory management</title>
<para>
The memory-management API for GObjects is a bit complicated but the idea behind it
is pretty simple: the goal is to provide a flexible model based on reference counting
which can be integrated in applications which use or require different memory management
models (such as garbage collection). The methods which are used to
manipulate this reference count are described below.
</para>
<sect2 id="gobject-memory-refcount">
<title>Reference count</title>
<para>
The functions <function><link linkend="g-object-ref">g_object_ref</link></function>/<function><link linkend="g-object-unref">g_object_unref</link></function> respectively
increase and decrease the reference count. These functions are
thread-safe.
<function><link linkend="g-clear-object">g_clear_object</link></function>
is a convenience wrapper around <function>g_object_unref</function>
which also clears the pointer passed to it.
</para>
<para>
The reference count is initialized to one by
<function><link linkend="g-object-new">g_object_new</link></function> which means that the caller
is currently the sole owner of the newly-created reference. (If the object is derived from <link linkend="GInitiallyUnowned"><type>GInitiallyUnowned</type></link>, this reference count is <link linkend="floating-ref">floating</link>.)
When the reference count reaches zero, that is,
when <function><link linkend="g-object-unref">g_object_unref</link></function> is called by the last client holding
a reference to the object, the <emphasis>dispose</emphasis> and the
<emphasis>finalize</emphasis> class methods are invoked.
</para>
<para>
Finally, after <emphasis>finalize</emphasis> is invoked,
<function><link linkend="g-type-free-instance">g_type_free_instance</link></function> is called to free the object instance.
Depending on the memory allocation policy decided when the type was registered (through
one of the <function>g_type_register_*</function> functions), the object's instance
memory will be freed or returned to the object pool for this type.
Once the object has been freed, if it was the last instance of the type, the type's class
will be destroyed as described in <xref linkend="gtype-instantiatable-classed"/> and
<xref linkend="gtype-non-instantiatable-non-classed"/>.
</para>
<para>
The table below summarizes the destruction process of a GObject:
<table id="gobject-destruction-table">
<title><function><link linkend="g-object-unref">g_object_unref</link></function></title>
<tgroup cols="3">
<colspec colwidth="*" colnum="1" align="left"/>
<colspec colwidth="*" colnum="2" align="left"/>
<colspec colwidth="8*" colnum="3" align="left"/>
<thead>
<row>
<entry>Invocation time</entry>
<entry>Function invoked</entry>
<entry>Function's parameters</entry>
<entry>Remark</entry>
</row>
</thead>
<tbody>
<row>
<entry morerows="1">Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for an instance
of target type
</entry>
<entry>target type's dispose class function</entry>
<entry>GObject instance</entry>
<entry>
When dispose ends, the object should not hold any reference to any other
member object. The object is also expected to be able to answer client
method invocations (with possibly an error code but no memory violation)
until finalize is executed. dispose can be executed more than once.
dispose should chain up to its parent implementation just before returning
to the caller.
</entry>
</row>
<row>
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for an instance
of target type
</entry-->
<entry>target type's finalize class function</entry>
<entry>GObject instance</entry>
<entry>
Finalize is expected to complete the destruction process initiated by
dispose. It should complete the object's destruction. finalize will be
executed only once.
finalize should chain up to its parent implementation just before returning
to the caller.
The reason why the destruction process is split is two different phases is
explained in <xref linkend="gobject-memory-cycles"/>.
</entry>
</row>
<row>
<entry morerows="3">Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for the last
instance of target type
</entry>
<entry>interface's <function>interface_finalize</function> function</entry>
<entry>On interface's vtable</entry>
<entry>Never used in practice. Unlikely you will need it.</entry>
</row>
<row>
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function>for the last
instance of target type
</entry-->
<entry>interface's <function>base_finalize</function> function</entry>
<entry>On interface's vtable</entry>
<entry>Never used in practice. Unlikely you will need it.</entry>
</row>
<row>
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for the last
instance of target type
</entry-->
<entry>target type's <function>class_finalize</function> function</entry>
<entry>On target type's class structure</entry>
<entry>Never used in practice. Unlikely you will need it.</entry>
</row>
<row>
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for the last
instance of target type
</entry-->
<entry>type's <function>base_finalize</function> function</entry>
<entry>On the inheritance tree of classes from fundamental type to target type.
<function>base_init</function> is invoked once for each class structure.</entry>
<entry>Never used in practice. Unlikely you will need it.</entry>
</row>
</tbody>
</tgroup>
</table>
</para>
</sect2>
<sect2 id="gobject-memory-weakref">
<title>Weak References</title>
<para>
Weak references are used to monitor object finalization:
<function><link linkend="g-object-weak-ref">g_object_weak_ref</link></function> adds a monitoring callback which does
not hold a reference to the object but which is invoked when the object runs
its dispose method. As such, each weak ref can be invoked more than once upon
object finalization (since dispose can run more than once during object
finalization).
</para>
<para>
<function><link linkend="g-object-weak-unref">g_object_weak_unref</link></function> can be used to remove a monitoring
callback from the object.
</para>
<para>
Weak references are also used to implement <function><link linkend="g-object-add-weak-pointer">g_object_add_weak_pointer</link></function>
and <function><link linkend="g-object-remove-weak-pointer">g_object_remove_weak_pointer</link></function>. These functions add a weak reference
to the object they are applied to which makes sure to nullify the pointer given by the user
when object is finalized.
</para>
<para>
Similarly, <link linkend="GWeakRef"><type>GWeakRef</type></link> can be
used to implement weak references if thread safety is required.
</para>
</sect2>
<sect2 id="gobject-memory-cycles">
<title>Reference counts and cycles</title>
<para>
GObject's memory management model was designed to be easily integrated in existing code
using garbage collection. This is why the destruction process is split in two phases:
the first phase, executed in the dispose handler is supposed to release all references
to other member objects. The second phase, executed by the finalize handler is supposed
to complete the object's destruction process. Object methods should be able to run
without program error in-between the two phases.
</para>
<para>
This two-step destruction process is very useful to break reference counting cycles.
While the detection of the cycles is up to the external code, once the cycles have been
detected, the external code can invoke <function><link linkend="g-object-run-dispose">g_object_run_dispose</link></function> which
will indeed break any existing cycles since it will run the dispose handler associated
to the object and thus release all references to other objects.
</para>
<para>
This explains one of the rules about the dispose handler stated earlier:
the dispose handler can be invoked multiple times. Let's say we
have a reference count cycle: object A references B which itself references object A.
Let's say we have detected the cycle and we want to destroy the two objects. One way to
do this would be to invoke <function><link linkend="g-object-run-dispose">g_object_run_dispose</link></function> on one of the
objects.
</para>
<para>
If object A releases all its references to all objects, this means it releases its
reference to object B. If object B was not owned by anyone else, this is its last
reference count which means this last unref runs B's dispose handler which, in turn,
releases B's reference on object A. If this is A's last reference count, this last
unref runs A's dispose handler which is running for the second time before
A's finalize handler is invoked !
</para>
<para>
The above example, which might seem a bit contrived, can really happen if
GObjects are being handled by language bindings — hence the rules for
object destruction should be closely followed.
</para>
</sect2>
</sect1>
<sect1 id="gobject-properties">
<title>Object properties</title>
<para>
One of GObject's nice features is its generic get/set mechanism for object
properties. When an object
is instantiated, the object's <function>class_init</function> handler should be used to register
the object's properties with <function><link linkend="g-object-class-install-properties">g_object_class_install_properties</link></function>.
</para>
<para>
The best way to understand how object properties work is by looking at a real example
of how it is used:
<informalexample><programlisting>
/************************************************/
/* Implementation */
/************************************************/
typedef enum
{
PROP_FILENAME = 1,
PROP_ZOOM_LEVEL,
N_PROPERTIES
} ViewerFileProperty;
static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
static void
viewer_file_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
ViewerFile *self = VIEWER_FILE (object);
switch ((ViewerFileProperty) property_id)
{
case PROP_FILENAME:
g_free (self->filename);
self->filename = g_value_dup_string (value);
g_print ("filename: %s\n", self->filename);
break;
case PROP_ZOOM_LEVEL:
self->zoom_level = g_value_get_uint (value);
g_print ("zoom level: %u\n", self->zoom_level);
break;
default:
/* We don't have any other property... */
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
viewer_file_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
ViewerFile *self = VIEWER_FILE (object);
switch ((ViewerFileProperty) property_id)
{
case PROP_FILENAME:
g_value_set_string (value, self->filename);
break;
case PROP_ZOOM_LEVEL:
g_value_set_uint (value, self->zoom_level);
break;
default:
/* We don't have any other property... */
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
viewer_file_class_init (ViewerFileClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = viewer_file_set_property;
object_class->get_property = viewer_file_get_property;
obj_properties[PROP_FILENAME] =
g_param_spec_string ("filename",
"Filename",
"Name of the file to load and display from.",
NULL /* default value */,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
obj_properties[PROP_ZOOM_LEVEL] =
g_param_spec_uint ("zoom-level",
"Zoom level",
"Zoom level to view the file at.",
0 /* minimum value */,
10 /* maximum value */,
2 /* default value */,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class,
N_PROPERTIES,
obj_properties);
}
/************************************************/
/* Use */
/************************************************/
ViewerFile *file;
GValue val = G_VALUE_INIT;
file = g_object_new (VIEWER_TYPE_FILE, NULL);
g_value_init (&val, G_TYPE_UINT);
g_value_set_char (&val, 11);
g_object_set_property (G_OBJECT (file), "zoom-level", &val);
g_value_unset (&val);
</programlisting></informalexample>
The client code above looks simple but a lot of things happen under the hood:
</para>
<para>
<function><link linkend="g-object-set-property">g_object_set_property</link></function> first ensures a property
with this name was registered in <emphasis>file</emphasis>'s <function>class_init</function> handler. If so it walks the class hierarchy,
from bottom-most most-derived type, to top-most fundamental type to find the class
which registered that property. It then tries to convert the user-provided
<link linkend="GValue"><type>GValue</type></link>
into a <type>GValue</type> whose type is that of the associated property.
</para>
<para>
If the user provides a <type>signed char</type> <type>GValue</type>, as is shown
here, and if the object's property was registered as an <type>unsigned int</type>,
<function><link linkend="g-value-transform">g_value_transform</link></function> will try to transform the input signed char into
an unsigned int. Of course, the success of the transformation depends on the availability
of the required transform function. In practice, there will almost always be a transformation
<footnote>
<para>Its behaviour might not be what you expect but it is up to you to actually avoid
relying on these transformations.
</para>
</footnote>
which matches and conversion will be carried out if needed.
</para>
<para>
After transformation, the <link linkend="GValue"><type>GValue</type></link> is validated by
<function><link linkend="g-param-value-validate">g_param_value_validate</link></function> which makes sure the user's
data stored in the <link linkend="GValue"><type>GValue</type></link> matches the characteristics specified by
the property's <link linkend="GParamSpec"><type>GParamSpec</type></link>.
Here, the <link linkend="GParamSpec"><type>GParamSpec</type></link> we
provided in <function>class_init</function> has a validation function which makes sure that the GValue
contains a value which respects the minimum and maximum bounds of the
<link linkend="GParamSpec"><type>GParamSpec</type></link>. In the example above, the client's GValue does not
respect these constraints (it is set to 11, while the maximum is 10). As such, the
<function><link linkend="g-object-set-property">g_object_set_property</link></function> function will return with an error.
</para>
<para>
If the user's GValue had been set to a valid value, <function><link linkend="g-object-set-property">g_object_set_property</link></function>
would have proceeded with calling the object's
<function>set_property</function> class method. Here, since our
implementation of <type>ViewerFile</type> did override this method, execution would jump to
<function>viewer_file_set_property</function> after having retrieved from the
<link linkend="GParamSpec"><type>GParamSpec</type></link> the <emphasis>param_id</emphasis>
<footnote>
<para>
It should be noted that the param_id used here need only to uniquely identify each
<link linkend="GParamSpec"><type>GParamSpec</type></link> within the <type>ViewerFileClass</type> such that the switch
used in the set and get methods actually works. Of course, this locally-unique
integer is purely an optimization: it would have been possible to use a set of
<emphasis>if (strcmp (a, b) == 0) {} else if (strcmp (a, b) == 0) {}</emphasis> statements.
</para>
</footnote>
which had been stored by
<function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>.
</para>
<para>
Once the property has been set by the object's
<function>set_property</function> class method, execution
returns to <function><link linkend="g-object-set-property">g_object_set_property</link></function> which makes sure that
the "notify" signal is emitted on the object's instance with the changed property as
parameter unless notifications were frozen by <function><link linkend="g-object-freeze-notify">g_object_freeze_notify</link></function>.
</para>
<para>
<function><link linkend="g-object-thaw-notify">g_object_thaw_notify</link></function> can be used to re-enable notification of
property modifications through the
<link linkend="GObject-notify"><type>“notify”</type></link> signal. It is important to remember that
even if properties are changed while property change notification is frozen, the "notify"
signal will be emitted once for each of these changed properties as soon as the property
change notification is thawed: no property change is lost for the "notify"
signal, although multiple notifications for a single property are
compressed. Signals can only be delayed by the notification freezing
mechanism.
</para>
<para>
It sounds like a tedious task to set up GValues every time when one wants to modify a property.
In practice one will rarely do this. The functions <function><link linkend="g-object-set-property">g_object_set_property</link></function>
and <function><link linkend="g-object-get-property">g_object_get_property</link></function>
are meant to be used by language bindings. For application there is an easier way and
that is described next.
</para>
<sect2 id="gobject-multi-properties">
<title>Accessing multiple properties at once</title>
<para>
It is interesting to note that the <function><link linkend="g-object-set">g_object_set</link></function> and
<function><link linkend="g-object-set-valist">g_object_set_valist</link></function> (variadic version) functions can be used to set
multiple properties at once. The client code shown above can then be re-written as:
<informalexample><programlisting>
ViewerFile *file;
file = /* */;
g_object_set (G_OBJECT (file),
"zoom-level", 6,
"filename", "~/some-file.txt",
NULL);
</programlisting></informalexample>
This saves us from managing the GValues that we were needing to handle when using
<function><link linkend="g-object-set-property">g_object_set_property</link></function>.
The code above will trigger one notify signal emission for each property modified.
</para>
<para>
Equivalent <function>_get</function> versions are also available:
<function><link linkend="g-object-get">g_object_get</link></function>
and <function><link linkend="g-object-get-valist">g_object_get_valist</link></function> (variadic version) can be used to get numerous
properties at once.
</para>
<para>
These high level functions have one drawback — they don't provide a return value.
One should pay attention to the argument types and ranges when using them.
A known source of errors is to pass a different type from what the
property expects; for instance, passing an integer when the property
expects a floating point value and thus shifting all subsequent parameters
by some number of bytes. Also forgetting the terminating
<literal>NULL</literal> will lead to undefined behaviour.
</para>
<para>
This explains how <function><link linkend="g-object-new">g_object_new</link></function>,
<function><link linkend="g-object-newv">g_object_newv</link></function> and <function><link linkend="g-object-new-valist">g_object_new_valist</link></function>
work: they parse the user-provided variable number of parameters and invoke
<function><link linkend="g-object-set">g_object_set</link></function> on the parameters only after the object has been successfully constructed.
The "notify" signal will be emitted for each property set.
</para>
</sect2>
<!-- @todo tell here about how to pass use handle properties in derived classes -->
</sect1>
</chapter>
|