nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | <?xml version='1.0' encoding="UTF-8"?> |
2 | <!DOCTYPE part PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" |
||
3 | "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [ |
||
4 | ]> |
||
5 | <part label="IV"> |
||
6 | <title>Tutorial</title> |
||
7 | <partintro> |
||
8 | <para> |
||
9 | This chapter tries to answer the real-life questions of users and presents |
||
10 | the most common use cases in order from most likely to least |
||
11 | likely. |
||
12 | </para> |
||
13 | </partintro> |
||
14 | |||
15 | <chapter id="howto-gobject"> |
||
16 | <title>How to define and implement a new GObject</title> |
||
17 | |||
18 | <para> |
||
19 | This chapter focuses on the implementation of a subtype of GObject, for |
||
20 | example to create a custom class hierarchy, or to subclass a GTK+ widget. |
||
21 | </para> |
||
22 | |||
23 | <para> |
||
24 | Throughout the chapter, a running example of a file viewer program is used, |
||
25 | which has a <type>ViewerFile</type> class to represent a single file being |
||
26 | viewed, and various derived classes for different types of files with |
||
27 | special functionality, such as audio files. The example application also |
||
28 | supports editing files (for example, to tweak a photo being viewed), using |
||
29 | a <type>ViewerEditable</type> interface. |
||
30 | </para> |
||
31 | |||
32 | <sect1 id="howto-gobject-header"> |
||
33 | <title>Boilerplate header code</title> |
||
34 | |||
35 | <para> |
||
36 | The first step before writing the code for your GObject is to write the |
||
37 | type's header which contains the needed type, function and macro |
||
38 | definitions. Each of these elements is nothing but a convention which |
||
39 | is followed by almost all users of GObject, and has been refined over |
||
40 | multiple years of experience developing GObject-based code. If you are |
||
41 | writing a library, it is particularly important for you to adhere closely |
||
42 | to these conventions; users of your library will assume that you have. |
||
43 | Even if not writing a library, it will help other people who want to work |
||
44 | on your project. |
||
45 | </para> |
||
46 | |||
47 | <para> |
||
48 | Pick a name convention for your headers and source code and stick to it: |
||
49 | <itemizedlist> |
||
50 | <listitem><para>use a dash to separate the prefix from the typename: |
||
51 | <filename>viewer-file.h</filename> and <filename>viewer-file.c</filename> |
||
52 | (this is the convention used by Nautilus and most GNOME libraries).</para></listitem> |
||
53 | <listitem><para>use an underscore to separate the prefix from the |
||
54 | typename: <filename>viewer_file.h</filename> and |
||
55 | <filename>viewer_file.c</filename>.</para></listitem> |
||
56 | <listitem><para>Do not separate the prefix from the typename: |
||
57 | <filename>viewerfile.h</filename> and <filename>viewerfile.c</filename>. |
||
58 | (this is the convention used by GTK+)</para></listitem> |
||
59 | </itemizedlist> |
||
60 | Some people like the first two solutions better: it makes reading file |
||
61 | names easier for those with poor eyesight. |
||
62 | </para> |
||
63 | |||
64 | <para> |
||
65 | The basic conventions for any header which exposes a GType are described |
||
66 | in <xref linkend="gtype-conventions"/>. |
||
67 | </para> |
||
68 | |||
69 | <para> |
||
70 | If you want to declare a type named ‘file’ in namespace ‘viewer’, name the |
||
71 | type instance <function>ViewerFile</function> and its class |
||
72 | <function>ViewerFileClass</function> (names are case sensitive). The |
||
73 | recommended method of declaring a type differs based on whether the type |
||
74 | is final or derivable. |
||
75 | </para> |
||
76 | |||
77 | <para> |
||
78 | Final types cannot be subclassed further, and should be the default choice |
||
79 | for new types — changing a final type to be derivable is always a change |
||
80 | that will be compatible with existing uses of the code, but the converse |
||
81 | will often cause problems. Final types are declared using |
||
82 | <link linkend="G-DECLARE-FINAL-TYPE:CAPS"><function>G_DECLARE_FINAL_TYPE</function></link>, |
||
83 | and require a structure to hold the instance data to be declared in the |
||
84 | source code (not the header file). |
||
85 | |||
86 | <informalexample><programlisting> |
||
87 | /* |
||
88 | * Copyright/Licensing information. |
||
89 | */ |
||
90 | |||
91 | /* inclusion guard */ |
||
92 | #ifndef __VIEWER_FILE_H__ |
||
93 | #define __VIEWER_FILE_H__ |
||
94 | |||
95 | #include <glib-object.h> |
||
96 | /* |
||
97 | * Potentially, include other headers on which this header depends. |
||
98 | */ |
||
99 | |||
100 | G_BEGIN_DECLS |
||
101 | |||
102 | /* |
||
103 | * Type declaration. |
||
104 | */ |
||
105 | #define VIEWER_TYPE_FILE viewer_file_get_type () |
||
106 | G_DECLARE_FINAL_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject) |
||
107 | |||
108 | /* |
||
109 | * Method definitions. |
||
110 | */ |
||
111 | ViewerFile *viewer_file_new (void); |
||
112 | |||
113 | G_END_DECLS |
||
114 | |||
115 | #endif /* __VIEWER_FILE_H__ */ |
||
116 | </programlisting></informalexample> |
||
117 | </para> |
||
118 | |||
119 | <para> |
||
120 | Derivable types <emphasis>can</emphasis> be subclassed further, and their class and |
||
121 | instance structures form part of the public API which must not be changed |
||
122 | if API stability is cared about. They are declared using |
||
123 | <link linkend="G-DECLARE-DERIVABLE-TYPE:CAPS"><function>G_DECLARE_DERIVABLE_TYPE</function></link>: |
||
124 | <informalexample><programlisting> |
||
125 | /* |
||
126 | * Copyright/Licensing information. |
||
127 | */ |
||
128 | |||
129 | /* inclusion guard */ |
||
130 | #ifndef __VIEWER_FILE_H__ |
||
131 | #define __VIEWER_FILE_H__ |
||
132 | |||
133 | #include <glib-object.h> |
||
134 | /* |
||
135 | * Potentially, include other headers on which this header depends. |
||
136 | */ |
||
137 | |||
138 | G_BEGIN_DECLS |
||
139 | |||
140 | /* |
||
141 | * Type declaration. |
||
142 | */ |
||
143 | #define VIEWER_TYPE_FILE viewer_file_get_type () |
||
144 | G_DECLARE_DERIVABLE_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject) |
||
145 | |||
146 | struct _ViewerFileClass |
||
147 | { |
||
148 | GObjectClass parent_class; |
||
149 | |||
150 | /* Class virtual function fields. */ |
||
151 | void (* open) (ViewerFile *file, |
||
152 | GError **error); |
||
153 | |||
154 | /* Padding to allow adding up to 12 new virtual functions without |
||
155 | * breaking ABI. */ |
||
156 | gpointer padding[12]; |
||
157 | }; |
||
158 | |||
159 | /* |
||
160 | * Method definitions. |
||
161 | */ |
||
162 | ViewerFile *viewer_file_new (void); |
||
163 | |||
164 | G_END_DECLS |
||
165 | |||
166 | #endif /* __VIEWER_FILE_H__ */ |
||
167 | </programlisting></informalexample> |
||
168 | </para> |
||
169 | |||
170 | <para> |
||
171 | The convention for header includes is to add the minimum number of |
||
172 | <function>#include</function> directives to the top of your headers needed |
||
173 | to compile that header. This |
||
174 | allows client code to simply <function>#include "viewer-file.h"</function>, |
||
175 | without needing to know the prerequisites for |
||
176 | <filename>viewer-file.h</filename>. |
||
177 | </para> |
||
178 | </sect1> |
||
179 | |||
180 | <sect1 id="howto-gobject-code"> |
||
181 | <title>Boilerplate code</title> |
||
182 | |||
183 | <para> |
||
184 | In your code, the first step is to <function>#include</function> the |
||
185 | needed headers: |
||
186 | <informalexample><programlisting> |
||
187 | /* |
||
188 | * Copyright information |
||
189 | */ |
||
190 | |||
191 | #include "viewer-file.h" |
||
192 | |||
193 | /* Private structure definition. */ |
||
194 | typedef struct { |
||
195 | gchar *filename; |
||
196 | /* stuff */ |
||
197 | } ViewerFilePrivate; |
||
198 | |||
199 | /* |
||
200 | * forward definitions |
||
201 | */ |
||
202 | </programlisting></informalexample> |
||
203 | </para> |
||
204 | |||
205 | <para> |
||
206 | If the class is being declared as final using |
||
207 | <function>G_DECLARE_FINAL_TYPE</function>, its instance structure should |
||
208 | be defined in the C file: |
||
209 | <informalexample><programlisting> |
||
210 | struct _ViewerFile |
||
211 | { |
||
212 | GObject parent_instance; |
||
213 | |||
214 | /* Other members, including private data. */ |
||
215 | } |
||
216 | </programlisting></informalexample> |
||
217 | </para> |
||
218 | |||
219 | <para> |
||
220 | Call the <function>G_DEFINE_TYPE</function> macro (or |
||
221 | <function>G_DEFINE_TYPE_WITH_PRIVATE</function> if your class needs |
||
222 | private data — final types do <emphasis>not</emphasis> need private data) |
||
223 | using the name |
||
224 | of the type, the prefix of the functions and the parent GType to |
||
225 | reduce the amount of boilerplate needed. This macro will: |
||
226 | |||
227 | <itemizedlist> |
||
228 | <listitem><simpara>implement the <function>viewer_file_get_type</function> |
||
229 | function</simpara></listitem> |
||
230 | <listitem><simpara>define a parent class pointer accessible from |
||
231 | the whole .c file</simpara></listitem> |
||
232 | <listitem><simpara>add private instance data to the type (if using |
||
233 | <function>G_DEFINE_TYPE_WITH_PRIVATE</function>)</simpara></listitem> |
||
234 | </itemizedlist> |
||
235 | </para> |
||
236 | |||
237 | <para> |
||
238 | If the class has been declared as final using |
||
239 | <function>G_DECLARE_FINAL_TYPE</function> (see |
||
240 | <xref linkend="howto-gobject-header"/>), private data should be placed in |
||
241 | the instance structure, <type>ViewerFile</type>, and |
||
242 | <function>G_DEFINE_TYPE</function> should be used instead of |
||
243 | <function>G_DEFINE_TYPE_WITH_PRIVATE</function>. The instance structure |
||
244 | for a final class is not exposed publicly, and is not embedded in the |
||
245 | instance structures of any derived classes (because the class is final); |
||
246 | so its size can vary without causing incompatibilities for code which uses |
||
247 | the class. Conversely, private data for derivable classes |
||
248 | <emphasis>must</emphasis> be included in a private structure, and |
||
249 | <function>G_DEFINE_TYPE_WITH_PRIVATE</function> must be used. |
||
250 | |||
251 | <informalexample><programlisting> |
||
252 | G_DEFINE_TYPE (ViewerFile, viewer_file, G_TYPE_OBJECT) |
||
253 | </programlisting></informalexample> |
||
254 | or |
||
255 | <informalexample><programlisting> |
||
256 | G_DEFINE_TYPE_WITH_PRIVATE (ViewerFile, viewer_file, G_TYPE_OBJECT) |
||
257 | </programlisting></informalexample> |
||
258 | </para> |
||
259 | |||
260 | <para> |
||
261 | It is also possible to use the |
||
262 | <function>G_DEFINE_TYPE_WITH_CODE</function> macro to control the |
||
263 | <function>get_type</function> function implementation — for instance, to |
||
264 | add a call to the <function>G_IMPLEMENT_INTERFACE</function> macro to |
||
265 | implement an interface. |
||
266 | </para> |
||
267 | </sect1> |
||
268 | |||
269 | <sect1 id="howto-gobject-construction"> |
||
270 | <title>Object construction</title> |
||
271 | |||
272 | <para> |
||
273 | People often get confused when trying to construct their GObjects because of the |
||
274 | sheer number of different ways to hook into the objects's construction process: it is |
||
275 | difficult to figure which is the <emphasis>correct</emphasis>, recommended way. |
||
276 | </para> |
||
277 | |||
278 | <para> |
||
279 | <xref linkend="gobject-construction-table"/> shows what user-provided functions |
||
280 | are invoked during object instantiation and in which order they are invoked. |
||
281 | A user looking for the equivalent of the simple C++ constructor function should use |
||
282 | the <function>instance_init</function> method. It will be invoked after |
||
283 | all the parents’ <function>instance_init</function> |
||
284 | functions have been invoked. It cannot take arbitrary construction parameters |
||
285 | (as in C++) but if your object needs arbitrary parameters to complete initialization, |
||
286 | you can use construction properties. |
||
287 | </para> |
||
288 | |||
289 | <para> |
||
290 | Construction properties will be set only after all |
||
291 | <function>instance_init</function> functions have run. |
||
292 | No object reference will be returned to the client of <function><link linkend="g-object-new">g_object_new</link></function> |
||
293 | until all the construction properties have been set. |
||
294 | </para> |
||
295 | |||
296 | <para> |
||
297 | It is important to note that object construction cannot <emphasis>ever</emphasis> |
||
298 | fail. If you require a fallible GObject construction, you can use the |
||
299 | <link linkend="GInitable"><type>GInitable</type></link> and |
||
300 | <link linkend="GAsyncInitable"><type>GAsyncInitable</type></link> |
||
301 | interfaces provided by the GIO library. |
||
302 | </para> |
||
303 | |||
304 | <para> |
||
305 | You should write the following code first: |
||
306 | <informalexample><programlisting> |
||
307 | G_DEFINE_TYPE_WITH_PRIVATE (ViewerFile, viewer_file, G_TYPE_OBJECT) |
||
308 | |||
309 | static void |
||
310 | viewer_file_class_init (ViewerFileClass *klass) |
||
311 | { |
||
312 | } |
||
313 | |||
314 | static void |
||
315 | viewer_file_init (ViewerFile *self) |
||
316 | { |
||
317 | ViewerFilePrivate *priv = viewer_file_get_instance_private (self); |
||
318 | |||
319 | /* initialize all public and private members to reasonable default values. |
||
320 | * They are all automatically initialized to 0 to begin with. */ |
||
321 | } |
||
322 | </programlisting></informalexample> |
||
323 | </para> |
||
324 | |||
325 | <para> |
||
326 | If you need special construction properties (with |
||
327 | <link linkend="G-PARAM-CONSTRUCT-ONLY:CAPS"><function>G_PARAM_CONSTRUCT_ONLY</function></link> |
||
328 | set), install the properties in |
||
329 | the <function>class_init()</function> function, override the <function>set_property()</function> |
||
330 | and <function>get_property()</function> methods of the GObject class, |
||
331 | and implement them as described by <xref linkend="gobject-properties"/>. |
||
332 | </para> |
||
333 | |||
334 | <para> |
||
335 | Property IDs must start from 1, as 0 is reserved for internal use by |
||
336 | GObject. |
||
337 | <informalexample><programlisting> |
||
338 | enum |
||
339 | { |
||
340 | PROP_FILENAME = 1, |
||
341 | PROP_ZOOM_LEVEL, |
||
342 | N_PROPERTIES |
||
343 | }; |
||
344 | |||
345 | static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; |
||
346 | |||
347 | static void |
||
348 | viewer_file_class_init (ViewerFileClass *klass) |
||
349 | { |
||
350 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
||
351 | |||
352 | object_class->set_property = viewer_file_set_property; |
||
353 | object_class->get_property = viewer_file_get_property; |
||
354 | |||
355 | obj_properties[PROP_FILENAME] = |
||
356 | g_param_spec_string ("filename", |
||
357 | "Filename", |
||
358 | "Name of the file to load and display from.", |
||
359 | NULL /* default value */, |
||
360 | G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); |
||
361 | |||
362 | obj_properties[PROP_ZOOM_LEVEL] = |
||
363 | g_param_spec_uint ("zoom-level", |
||
364 | "Zoom level", |
||
365 | "Zoom level to view the file at.", |
||
366 | |||
367 | 10 /* maximum value */, |
||
368 | 2 /* default value */, |
||
369 | G_PARAM_READWRITE)); |
||
370 | |||
371 | g_object_class_install_properties (object_class, |
||
372 | N_PROPERTIES, |
||
373 | obj_properties); |
||
374 | } |
||
375 | </programlisting></informalexample> |
||
376 | If you need this, make sure you can build and run code similar to the |
||
377 | code shown above. Also, make sure your construct properties can be set |
||
378 | without side effects during construction. |
||
379 | </para> |
||
380 | |||
381 | <para> |
||
382 | Some people sometimes need to complete the initialization of a instance |
||
383 | of a type only after the properties passed to the constructors have been |
||
384 | set. This is possible through the use of the <function>constructor()</function> |
||
385 | class method as described in <xref linkend="gobject-instantiation"/> or, |
||
386 | more simply, using the <function>constructed()</function> class method. |
||
387 | Note that the <function>constructed()</function> |
||
388 | virtual function will only be invoked after the properties marked as |
||
389 | <function>G_PARAM_CONSTRUCT_ONLY</function> or |
||
390 | <function>G_PARAM_CONSTRUCT</function> have been consumed, but |
||
391 | before the regular properties passed to <function>g_object_new()</function> |
||
392 | have been set. |
||
393 | </para> |
||
394 | </sect1> |
||
395 | |||
396 | <sect1 id="howto-gobject-destruction"> |
||
397 | <title>Object destruction</title> |
||
398 | |||
399 | <para> |
||
400 | Again, it is often difficult to figure out which mechanism to use to |
||
401 | hook into the object's destruction process: when the last |
||
402 | <function><link linkend="g-object-unref">g_object_unref</link></function> |
||
403 | function call is made, a lot of things happen as described in |
||
404 | <xref linkend="gobject-destruction-table"/>. |
||
405 | </para> |
||
406 | |||
407 | <para> |
||
408 | The destruction process of your object is in two phases: dispose and |
||
409 | finalize. This split is necessary to handle |
||
410 | potential cycles due to the nature of the reference counting mechanism |
||
411 | used by GObject, as well as dealing with temporary revival of |
||
412 | instances in case of signal emission during the destruction sequence. |
||
413 | See <xref linkend="gobject-memory-cycles"/> for more information. |
||
414 | <informalexample><programlisting> |
||
415 | struct _ViewerFilePrivate |
||
416 | { |
||
417 | gchar *filename; |
||
418 | guint zoom_level; |
||
419 | |||
420 | GInputStream *input_stream; |
||
421 | }; |
||
422 | |||
423 | G_DEFINE_TYPE_WITH_PRIVATE (ViewerFile, viewer_file, G_TYPE_OBJECT) |
||
424 | |||
425 | static void |
||
426 | viewer_file_dispose (GObject *gobject) |
||
427 | { |
||
428 | ViewerFilePrivate *priv = viewer_file_get_instance_private (VIEWER_FILE (gobject)); |
||
429 | |||
430 | /* In dispose(), you are supposed to free all types referenced from this |
||
431 | * object which might themselves hold a reference to self. Generally, |
||
432 | * the most simple solution is to unref all members on which you own a |
||
433 | * reference. |
||
434 | */ |
||
435 | |||
436 | /* dispose() might be called multiple times, so we must guard against |
||
437 | * calling g_object_unref() on an invalid GObject by setting the member |
||
438 | * NULL; g_clear_object() does this for us. |
||
439 | */ |
||
440 | g_clear_object (&priv->input_stream); |
||
441 | |||
442 | /* Always chain up to the parent class; there is no need to check if |
||
443 | * the parent class implements the dispose() virtual function: it is |
||
444 | * always guaranteed to do so |
||
445 | */ |
||
446 | G_OBJECT_CLASS (viewer_file_parent_class)->dispose (gobject); |
||
447 | } |
||
448 | |||
449 | static void |
||
450 | viewer_file_finalize (GObject *gobject) |
||
451 | { |
||
452 | ViewerFilePrivate *priv = viewer_file_get_instance_private (VIEWER_FILE (gobject)); |
||
453 | |||
454 | g_free (priv->filename); |
||
455 | |||
456 | /* Always chain up to the parent class; as with dispose(), finalize() |
||
457 | * is guaranteed to exist on the parent's class virtual function table |
||
458 | */ |
||
459 | G_OBJECT_CLASS (viewer_file_parent_class)->finalize (gobject); |
||
460 | } |
||
461 | |||
462 | static void |
||
463 | viewer_file_class_init (ViewerFileClass *klass) |
||
464 | { |
||
465 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
||
466 | |||
467 | object_class->dispose = viewer_file_dispose; |
||
468 | object_class->finalize = viewer_file_finalize; |
||
469 | } |
||
470 | |||
471 | static void |
||
472 | viewer_file_init (ViewerFile *self); |
||
473 | { |
||
474 | ViewerFilePrivate *priv = viewer_file_get_instance_private (self); |
||
475 | |||
476 | priv->input_stream = g_object_new (VIEWER_TYPE_INPUT_STREAM, NULL); |
||
477 | priv->filename = /* would be set as a property */; |
||
478 | } |
||
479 | </programlisting></informalexample> |
||
480 | </para> |
||
481 | |||
482 | <para> |
||
483 | It is possible that object methods might be invoked after dispose is |
||
484 | run and before finalize runs. GObject does not consider this to be a |
||
485 | program error: you must gracefully detect this and neither crash nor |
||
486 | warn the user, by having a disposed instance revert to an inert state. |
||
487 | </para> |
||
488 | </sect1> |
||
489 | |||
490 | <sect1 id="howto-gobject-methods"> |
||
491 | <title>Object methods</title> |
||
492 | |||
493 | <para> |
||
494 | Just as with C++, there are many different ways to define object |
||
495 | methods and extend them: the following list and sections draw on |
||
496 | C++ vocabulary. (Readers are expected to know basic C++ concepts. |
||
497 | Those who have not had to write C++ code recently can refer to e.g. |
||
498 | <ulink url="http://www.cplusplus.com/doc/tutorial/"/> to refresh |
||
499 | their memories.) |
||
500 | <itemizedlist> |
||
501 | <listitem><para> |
||
502 | non-virtual public methods, |
||
503 | </para></listitem> |
||
504 | <listitem><para> |
||
505 | virtual public methods and |
||
506 | </para></listitem> |
||
507 | <listitem><para> |
||
508 | virtual private methods |
||
509 | </para></listitem> |
||
510 | </itemizedlist> |
||
511 | </para> |
||
512 | |||
513 | <sect2 id="non-virtual-public-methods"> |
||
514 | <title>Non-virtual public methods</title> |
||
515 | |||
516 | <para> |
||
517 | These are the simplest, providing a simple method which |
||
518 | acts on the object. Provide a function |
||
519 | prototype in the header and an implementation of that prototype |
||
520 | in the source file. |
||
521 | <informalexample><programlisting> |
||
522 | /* declaration in the header. */ |
||
523 | void viewer_file_open (ViewerFile *self, |
||
524 | GError **error); |
||
525 | |||
526 | /* implementation in the source file */ |
||
527 | void |
||
528 | viewer_file_open (ViewerFile *self, |
||
529 | GError **error) |
||
530 | { |
||
531 | g_return_if_fail (VIEWER_IS_FILE (self)); |
||
532 | g_return_if_fail (error == NULL || *error == NULL); |
||
533 | |||
534 | /* do stuff here. */ |
||
535 | } |
||
536 | </programlisting></informalexample> |
||
537 | </para> |
||
538 | </sect2> |
||
539 | |||
540 | <sect2 id="virtual-public-methods"> |
||
541 | <title>Virtual public methods</title> |
||
542 | |||
543 | <para> |
||
544 | This is the preferred way to create GObjects with overridable methods: |
||
545 | <itemizedlist> |
||
546 | <listitem><para> |
||
547 | Define the common method and its virtual function in the |
||
548 | class structure in the public header |
||
549 | </para></listitem> |
||
550 | <listitem><para> |
||
551 | Define the common method in the header file and implement it in the |
||
552 | source file |
||
553 | </para></listitem> |
||
554 | <listitem><para> |
||
555 | Implement a base version of the virtual function in the source |
||
556 | file and initialize the virtual function pointer to this |
||
557 | implementation in the object’s <function>class_init</function> |
||
558 | function; or leave it as <constant>NULL</constant> for a ‘pure |
||
559 | virtual’ method which must be overridden by derived classes |
||
560 | </para></listitem> |
||
561 | <listitem><para> |
||
562 | Re-implement the virtual function in each derived class which needs |
||
563 | to override it |
||
564 | </para></listitem> |
||
565 | </itemizedlist> |
||
566 | </para> |
||
567 | <para> |
||
568 | Note that virtual functions can only be defined if the class is |
||
569 | derivable, declared using |
||
570 | <link linkend="G-DECLARE-DERIVABLE-TYPE:CAPS"><function>G_DECLARE_DERIVABLE_TYPE</function></link> |
||
571 | so the class structure can be defined. |
||
572 | <informalexample><programlisting> |
||
573 | /* declaration in viewer-file.h. */ |
||
574 | #define VIEWER_TYPE_FILE viewer_file_get_type () |
||
575 | G_DECLARE_DERIVABLE_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject) |
||
576 | |||
577 | struct _ViewerFileClass |
||
578 | { |
||
579 | GObjectClass parent_class; |
||
580 | |||
581 | /* stuff */ |
||
582 | void (*open) (ViewerFile *self, |
||
583 | GError **error); |
||
584 | |||
585 | /* Padding to allow adding up to 12 new virtual functions without |
||
586 | * breaking ABI. */ |
||
587 | gpointer padding[12]; |
||
588 | }; |
||
589 | |||
590 | void viewer_file_open (ViewerFile *self, |
||
591 | GError **error); |
||
592 | |||
593 | /* implementation in viewer-file.c */ |
||
594 | void |
||
595 | viewer_file_open (ViewerFile *self, |
||
596 | GError **error) |
||
597 | { |
||
598 | ViewerFileClass *klass; |
||
599 | |||
600 | g_return_if_fail (VIEWER_IS_FILE (self)); |
||
601 | g_return_if_fail (error == NULL || *error == NULL); |
||
602 | |||
603 | klass = VIEWER_FILE_GET_CLASS (self); |
||
604 | g_return_if_fail (klass->open != NULL); |
||
605 | |||
606 | klass->open (self, error); |
||
607 | } |
||
608 | </programlisting></informalexample> |
||
609 | The code above simply redirects the <function>open</function> call |
||
610 | to the relevant virtual function. |
||
611 | </para> |
||
612 | |||
613 | <para> |
||
614 | It is possible to provide a default |
||
615 | implementation for this class method in the object's |
||
616 | <function>class_init</function> function: initialize the |
||
617 | <function>klass->open</function> field to a pointer to the |
||
618 | actual implementation. |
||
619 | By default, class methods that are not inherited are initialized to |
||
620 | <function>NULL</function>, and thus are to be considered "pure virtual". |
||
621 | <informalexample><programlisting> |
||
622 | static void |
||
623 | viewer_file_real_close (ViewerFile *self, |
||
624 | GError **error) |
||
625 | { |
||
626 | /* Default implementation for the virtual method. */ |
||
627 | } |
||
628 | |||
629 | static void |
||
630 | viewer_file_class_init (ViewerFileClass *klass) |
||
631 | { |
||
632 | /* this is not necessary, except for demonstration purposes. |
||
633 | * |
||
634 | * pure virtual method: mandates implementation in children. |
||
635 | */ |
||
636 | klass->open = NULL; |
||
637 | |||
638 | /* merely virtual method. */ |
||
639 | klass->close = viewer_file_real_close; |
||
640 | } |
||
641 | |||
642 | void |
||
643 | viewer_file_open (ViewerFile *self, |
||
644 | GError **error) |
||
645 | { |
||
646 | ViewerFileClass *klass; |
||
647 | |||
648 | g_return_if_fail (VIEWER_IS_FILE (self)); |
||
649 | g_return_if_fail (error == NULL || *error == NULL); |
||
650 | |||
651 | klass = VIEWER_FILE_GET_CLASS (self); |
||
652 | |||
653 | /* if the method is purely virtual, then it is a good idea to |
||
654 | * check that it has been overridden before calling it, and, |
||
655 | * depending on the intent of the class, either ignore it silently |
||
656 | * or warn the user. |
||
657 | */ |
||
658 | g_return_if_fail (klass->open != NULL); |
||
659 | klass->open (self, error); |
||
660 | } |
||
661 | |||
662 | void |
||
663 | viewer_file_close (ViewerFile *self, |
||
664 | GError **error) |
||
665 | { |
||
666 | ViewerFileClass *klass; |
||
667 | |||
668 | g_return_if_fail (VIEWER_IS_FILE (self)); |
||
669 | g_return_if_fail (error == NULL || *error == NULL); |
||
670 | |||
671 | klass = VIEWER_FILE_GET_CLASS (self); |
||
672 | if (klass->close != NULL) |
||
673 | klass->close (self, error); |
||
674 | } |
||
675 | </programlisting></informalexample> |
||
676 | </para> |
||
677 | </sect2> |
||
678 | |||
679 | <sect2 id="virtual-private-methods"> |
||
680 | <title>Virtual private Methods</title> |
||
681 | |||
682 | <para> |
||
683 | These are very similar to <link linkend="virtual-public-methods">virtual |
||
684 | public methods</link>. They just don't |
||
685 | have a public function to call directly. The header |
||
686 | file contains only a declaration of the virtual function: |
||
687 | <informalexample><programlisting> |
||
688 | /* declaration in viewer-file.h. */ |
||
689 | struct _ViewerFileClass |
||
690 | { |
||
691 | GObjectClass parent; |
||
692 | |||
693 | /* Public virtual method as before. */ |
||
694 | void (*open) (ViewerFile *self, |
||
695 | GError **error); |
||
696 | |||
697 | /* Private helper function to work out whether the file can be loaded via |
||
698 | * memory mapped I/O, or whether it has to be read as a stream. */ |
||
699 | gboolean (*can_memory_map) (ViewerFile *self); |
||
700 | |||
701 | /* Padding to allow adding up to 12 new virtual functions without |
||
702 | * breaking ABI. */ |
||
703 | gpointer padding[12]; |
||
704 | }; |
||
705 | |||
706 | void viewer_file_open (ViewerFile *self, GError **error); |
||
707 | </programlisting></informalexample> |
||
708 | These virtual functions are often used to delegate part of the job |
||
709 | to child classes: |
||
710 | <informalexample><programlisting> |
||
711 | /* this accessor function is static: it is not exported outside of this file. */ |
||
712 | static gboolean |
||
713 | viewer_file_can_memory_map (ViewerFile *self) |
||
714 | { |
||
715 | return VIEWER_FILE_GET_CLASS (self)->can_memory_map (self); |
||
716 | } |
||
717 | |||
718 | void |
||
719 | viewer_file_open (ViewerFile *self, |
||
720 | GError **error) |
||
721 | { |
||
722 | g_return_if_fail (VIEWER_IS_FILE (self)); |
||
723 | g_return_if_fail (error == NULL || *error == NULL); |
||
724 | |||
725 | /* |
||
726 | * Try to load the file using memory mapped I/O, if the implementation of the |
||
727 | * class determines that is possible using its private virtual method. |
||
728 | */ |
||
729 | if (viewer_file_can_memory_map (self)) |
||
730 | { |
||
731 | /* Load the file using memory mapped I/O. */ |
||
732 | } |
||
733 | else |
||
734 | { |
||
735 | /* Fall back to trying to load the file using streaming I/O… */ |
||
736 | } |
||
737 | } |
||
738 | </programlisting></informalexample> |
||
739 | </para> |
||
740 | |||
741 | <para> |
||
742 | Again, it is possible to provide a default implementation for this |
||
743 | private virtual function: |
||
744 | <informalexample><programlisting> |
||
745 | static gboolean |
||
746 | viewer_file_real_can_memory_map (ViewerFile *self) |
||
747 | { |
||
748 | /* As an example, always return false. Or, potentially return true if the |
||
749 | * file is local. */ |
||
750 | return FALSE; |
||
751 | } |
||
752 | |||
753 | static void |
||
754 | viewer_file_class_init (ViewerFileClass *klass) |
||
755 | { |
||
756 | /* non-pure virtual method; does not have to be implemented in children. */ |
||
757 | klass->can_memory_map = viewer_file_real_can_memory_map; |
||
758 | } |
||
759 | </programlisting></informalexample> |
||
760 | </para> |
||
761 | |||
762 | <para> |
||
763 | Derived classes can then override the method with code such as: |
||
764 | <informalexample><programlisting> |
||
765 | static void |
||
766 | viewer_audio_file_class_init (ViewerAudioFileClass *klass) |
||
767 | { |
||
768 | ViewerFileClass *file_class = VIEWER_FILE_CLASS (klass); |
||
769 | |||
770 | /* implement pure virtual function. */ |
||
771 | file_class->can_memory_map = viewer_audio_file_can_memory_map; |
||
772 | } |
||
773 | </programlisting></informalexample> |
||
774 | </para> |
||
775 | </sect2> |
||
776 | </sect1> |
||
777 | |||
778 | <sect1 id="howto-gobject-chainup"> |
||
779 | <title>Chaining up</title> |
||
780 | |||
781 | <para>Chaining up is often loosely defined by the following set of |
||
782 | conditions: |
||
783 | <itemizedlist> |
||
784 | <listitem><para>Parent class A defines a public virtual method named <function>foo</function> and |
||
785 | provides a default implementation.</para></listitem> |
||
786 | <listitem><para>Child class B re-implements method <function>foo</function>.</para></listitem> |
||
787 | <listitem><para>B’s implementation of <function>foo</function> calls (‘chains up to’) its parent class A’s implementation of <function>foo</function>.</para></listitem> |
||
788 | </itemizedlist> |
||
789 | There are various uses of this idiom: |
||
790 | <itemizedlist> |
||
791 | <listitem><para>You need to extend the behaviour of a class without modifying its code. You create |
||
792 | a subclass to inherit its implementation, re-implement a public virtual method to modify the behaviour |
||
793 | and chain up to ensure that the previous behaviour is not really modified, just extended. |
||
794 | </para></listitem> |
||
795 | <listitem><para>You need to implement the |
||
796 | <ulink url="http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern">Chain |
||
797 | Of Responsibility pattern</ulink>: each object of the inheritance |
||
798 | tree chains up to its parent (typically, at the beginning or the end of the method) to ensure that |
||
799 | each handler is run in turn.</para></listitem> |
||
800 | </itemizedlist> |
||
801 | </para> |
||
802 | |||
803 | <para> |
||
804 | To explicitly chain up to the implementation of the virtual method in the parent class, |
||
805 | you first need a handle to the original parent class structure. This pointer can then be used to |
||
806 | access the original virtual function pointer and invoke it directly. |
||
807 | <footnote> |
||
808 | <para> |
||
809 | The <emphasis>original</emphasis> adjective used in this sentence is not innocuous. To fully |
||
810 | understand its meaning, recall how class structures are initialized: for each object type, |
||
811 | the class structure associated with this object is created by first copying the class structure of its |
||
812 | parent type (a simple <function>memcpy</function>) and then by invoking the <function>class_init</function> callback on |
||
813 | the resulting class structure. Since the <function>class_init</function> callback is responsible for overwriting the class structure |
||
814 | with the user re-implementations of the class methods, the modified copy of the parent class |
||
815 | structure stored in the derived instance cannot be used. A copy of the class structure of an instance of the parent |
||
816 | class is needed. |
||
817 | </para> |
||
818 | </footnote> |
||
819 | </para> |
||
820 | |||
821 | <para> |
||
822 | Use the <function>parent_class</function> pointer created and initialized |
||
823 | by the |
||
824 | <link linkend="G-DEFINE-TYPE:CAPS"><function>G_DEFINE_TYPE</function></link> |
||
825 | family of macros, for instance: |
||
826 | <informalexample><programlisting> |
||
827 | static void |
||
828 | b_method_to_call (B *obj, gint some_param) |
||
829 | { |
||
830 | /* do stuff before chain up */ |
||
831 | |||
832 | /* call the method_to_call() virtual function on the |
||
833 | * parent of BClass, AClass. |
||
834 | * |
||
835 | * remember the explicit cast to AClass* |
||
836 | */ |
||
837 | A_CLASS (b_parent_class)->method_to_call (obj, some_param); |
||
838 | |||
839 | /* do stuff after chain up */ |
||
840 | } |
||
841 | </programlisting></informalexample> |
||
842 | </para> |
||
843 | |||
844 | </sect1> |
||
845 | |||
846 | </chapter> |
||
847 | <!-- End Howto GObject --> |
||
848 | |||
849 | <chapter id="howto-interface"> |
||
850 | <title>How to define and implement interfaces</title> |
||
851 | |||
852 | <sect1 id="howto-interface-define"> |
||
853 | <title>Defining interfaces</title> |
||
854 | |||
855 | <para> |
||
856 | The theory behind how GObject interfaces work is given in |
||
857 | <xref linkend="gtype-non-instantiable-classed"/>; this section covers how to |
||
858 | define and implement an interface. |
||
859 | </para> |
||
860 | |||
861 | <para> |
||
862 | The first step is to get the header right. This interface |
||
863 | defines two methods: |
||
864 | <informalexample><programlisting> |
||
865 | /* |
||
866 | * Copyright/Licensing information. |
||
867 | */ |
||
868 | |||
869 | #ifndef __VIEWER_EDITABLE_H__ |
||
870 | #define __VIEWER_EDITABLE_H__ |
||
871 | |||
872 | #include <glib-object.h> |
||
873 | |||
874 | G_BEGIN_DECLS |
||
875 | |||
876 | #define VIEWER_TYPE_EDITABLE viewer_editable_get_type () |
||
877 | G_DECLARE_INTERFACE (ViewerEditable, viewer_editable, VIEWER, EDITABLE, GObject) |
||
878 | |||
879 | struct _ViewerEditableInterface |
||
880 | { |
||
881 | GTypeInterface parent_iface; |
||
882 | |||
883 | void (*save) (ViewerEditable *self, |
||
884 | GError **error); |
||
885 | void (*undo) (ViewerEditable *self, |
||
886 | guint n_steps); |
||
887 | void (*redo) (ViewerEditable *self, |
||
888 | guint n_steps); |
||
889 | }; |
||
890 | |||
891 | void viewer_editable_save (ViewerEditable *self, |
||
892 | GError **error); |
||
893 | void viewer_editable_undo (ViewerEditable *self, |
||
894 | guint n_steps); |
||
895 | void viewer_editable_redo (ViewerEditable *self, |
||
896 | guint n_steps); |
||
897 | |||
898 | G_END_DECLS |
||
899 | |||
900 | #endif /* __VIEWER_EDITABLE_H__ */ |
||
901 | </programlisting></informalexample> |
||
902 | This code is the same as the code for a normal <link linkend="GType"><type>GType</type></link> |
||
903 | which derives from a <link linkend="GObject"><type>GObject</type></link> except for a few details: |
||
904 | <itemizedlist> |
||
905 | <listitem><para> |
||
906 | The <function>_GET_CLASS</function> function is called |
||
907 | <function>_GET_IFACE</function> (and is defined by |
||
908 | <link linkend="G-DECLARE-INTERFACE:CAPS"><function>G_DECLARE_INTERFACE</function></link>). |
||
909 | </para></listitem> |
||
910 | <listitem><para> |
||
911 | The instance type, <type>ViewerEditable</type>, is not fully defined: it is |
||
912 | used merely as an abstract type which represents an instance of |
||
913 | whatever object which implements the interface. |
||
914 | </para></listitem> |
||
915 | <listitem><para> |
||
916 | The parent of the <type>ViewerEditableInterface</type> is |
||
917 | <type>GTypeInterface</type>, not <type>GObjectClass</type>. |
||
918 | </para></listitem> |
||
919 | </itemizedlist> |
||
920 | </para> |
||
921 | |||
922 | <para> |
||
923 | The implementation of the <type>ViewerEditable</type> type itself is trivial: |
||
924 | <itemizedlist> |
||
925 | <listitem><para><function><link linkend="G-DEFINE-INTERFACE:CAPS">G_DEFINE_INTERFACE</link></function> |
||
926 | creates a <function>viewer_editable_get_type</function> function which registers the |
||
927 | type in the type system. The third argument is used to define a |
||
928 | <link linkend="howto-interface-prerequisite">prerequisite interface</link> |
||
929 | (which we'll talk about more later). Just pass <code>0</code> for this |
||
930 | argument when an interface has no prerequisite. |
||
931 | </para></listitem> |
||
932 | <listitem><para><function>viewer_editable_default_init</function> is expected |
||
933 | to register the interface's signals if there are any (we will see a bit |
||
934 | later how to use them).</para></listitem> |
||
935 | <listitem><para>The interface methods <function>viewer_editable_save</function>, |
||
936 | <function>viewer_editable_undo</function> and <function>viewer_editable_redo</function> dereference the interface |
||
937 | structure to access its associated interface function and call it. |
||
938 | </para></listitem> |
||
939 | </itemizedlist> |
||
940 | <informalexample><programlisting> |
||
941 | G_DEFINE_INTERFACE (ViewerEditable, viewer_editable, G_TYPE_OBJECT); |
||
942 | |||
943 | static void |
||
944 | viewer_editable_default_init (ViewerEditableInterface *iface) |
||
945 | { |
||
946 | /* add properties and signals to the interface here */ |
||
947 | } |
||
948 | |||
949 | void |
||
950 | viewer_editable_save (ViewerEditable *self, |
||
951 | GError **error) |
||
952 | { |
||
953 | ViewerEditableInterface *iface; |
||
954 | |||
955 | g_return_if_fail (VIEWER_IS_EDITABLE (self)); |
||
956 | g_return_if_fail (error == NULL || *error == NULL); |
||
957 | |||
958 | iface = VIEWER_EDITABLE_GET_IFACE (self); |
||
959 | g_return_if_fail (iface->save != NULL); |
||
960 | iface->save (self, error); |
||
961 | } |
||
962 | |||
963 | void |
||
964 | viewer_editable_undo (ViewerEditable *self, |
||
965 | guint n_steps) |
||
966 | { |
||
967 | ViewerEditableInterface *iface; |
||
968 | |||
969 | g_return_if_fail (VIEWER_IS_EDITABLE (self)); |
||
970 | |||
971 | iface = VIEWER_EDITABLE_GET_IFACE (self); |
||
972 | g_return_if_fail (iface->undo != NULL); |
||
973 | iface->undo (self, n_steps); |
||
974 | } |
||
975 | |||
976 | void |
||
977 | viewer_editable_redo (ViewerEditable *self, |
||
978 | guint n_steps) |
||
979 | { |
||
980 | ViewerEditableInterface *iface; |
||
981 | |||
982 | g_return_if_fail (VIEWER_IS_EDITABLE (self)); |
||
983 | |||
984 | iface = VIEWER_EDITABLE_GET_IFACE (self); |
||
985 | g_return_if_fail (iface->redo != NULL); |
||
986 | iface->redo (self, n_steps); |
||
987 | } |
||
988 | </programlisting></informalexample> |
||
989 | </para> |
||
990 | </sect1> |
||
991 | |||
992 | <sect1 id="howto-interface-implement"> |
||
993 | <title>Implementing interfaces</title> |
||
994 | |||
995 | <para> |
||
996 | Once the interface is defined, implementing it is rather trivial. |
||
997 | </para> |
||
998 | |||
999 | <para> |
||
1000 | The first step is to define a normal final GObject class exactly as in |
||
1001 | <xref linkend="howto-gobject-header"/>. |
||
1002 | </para> |
||
1003 | |||
1004 | <para> |
||
1005 | The second step is to implement <type>ViewerFile</type> by defining |
||
1006 | it using |
||
1007 | <function><link linkend="G-DEFINE-TYPE-WITH-CODE:CAPS">G_DEFINE_TYPE_WITH_CODE</link></function> |
||
1008 | and |
||
1009 | <function><link linkend="G-IMPLEMENT-INTERFACE:CAPS">G_IMPLEMENT_INTERFACE</link></function> |
||
1010 | instead of |
||
1011 | <function><link linkend="G-DEFINE-TYPE:CAPS">G_DEFINE_TYPE</link></function>: |
||
1012 | <informalexample><programlisting> |
||
1013 | static void viewer_file_editable_interface_init (ViewerEditableInterface *iface); |
||
1014 | |||
1015 | G_DEFINE_TYPE_WITH_CODE (ViewerFile, viewer_file, G_TYPE_OBJECT, |
||
1016 | G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, |
||
1017 | viewer_file_editable_interface_init)) |
||
1018 | </programlisting></informalexample> |
||
1019 | This definition is very much like all the similar functions seen |
||
1020 | previously. The only interface-specific code present here is the use of |
||
1021 | <function><link linkend="G-IMPLEMENT-INTERFACE:CAPS">G_IMPLEMENT_INTERFACE</link></function>. |
||
1022 | </para> |
||
1023 | |||
1024 | <note><para>Classes can implement multiple interfaces by using multiple calls to |
||
1025 | <function><link linkend="G-IMPLEMENT-INTERFACE:CAPS">G_IMPLEMENT_INTERFACE</link></function> |
||
1026 | inside the call to |
||
1027 | <function><link linkend="G-DEFINE-TYPE-WITH-CODE:CAPS">G_DEFINE_TYPE_WITH_CODE</link></function> |
||
1028 | </para></note> |
||
1029 | |||
1030 | <para> |
||
1031 | <function>viewer_file_editable_interface_init</function>, the interface |
||
1032 | initialization function: inside it every virtual method of the interface |
||
1033 | must be assigned to its implementation: |
||
1034 | <informalexample><programlisting> |
||
1035 | static void |
||
1036 | viewer_file_editable_save (ViewerFile *self, |
||
1037 | GError **error) |
||
1038 | { |
||
1039 | g_print ("File implementation of editable interface save method: %s.\n", |
||
1040 | self->filename); |
||
1041 | } |
||
1042 | |||
1043 | static void |
||
1044 | viewer_file_editable_undo (ViewerFile *self, |
||
1045 | guint n_steps) |
||
1046 | { |
||
1047 | g_print ("File implementation of editable interface undo method: %s.\n", |
||
1048 | self->filename); |
||
1049 | } |
||
1050 | |||
1051 | static void |
||
1052 | viewer_file_editable_redo (ViewerFile *self, |
||
1053 | guint n_steps) |
||
1054 | { |
||
1055 | g_print ("File implementation of editable interface redo method: %s.\n", |
||
1056 | self->filename); |
||
1057 | } |
||
1058 | |||
1059 | static void |
||
1060 | viewer_file_editable_interface_init (ViewerEditableInterface *iface) |
||
1061 | { |
||
1062 | iface->save = viewer_file_editable_save; |
||
1063 | iface->undo = viewer_file_editable_undo; |
||
1064 | iface->redo = viewer_file_editable_redo; |
||
1065 | } |
||
1066 | |||
1067 | static void |
||
1068 | viewer_file_init (ViewerFile *self) |
||
1069 | { |
||
1070 | /* Instance variable initialisation code. */ |
||
1071 | } |
||
1072 | </programlisting></informalexample> |
||
1073 | </para> |
||
1074 | </sect1> |
||
1075 | |||
1076 | <sect1 id="howto-interface-prerequisite"> |
||
1077 | <title>Interface definition prerequisites</title> |
||
1078 | |||
1079 | <para> |
||
1080 | To specify that an interface requires the presence of other interfaces |
||
1081 | when implemented, GObject introduces the concept of |
||
1082 | <emphasis>prerequisites</emphasis>: it is possible to associate |
||
1083 | a list of prerequisite types to an interface. For example, if |
||
1084 | object A wishes to implement interface I1, and if interface I1 has a |
||
1085 | prerequisite on interface I2, A has to implement both I1 and I2. |
||
1086 | </para> |
||
1087 | |||
1088 | <para> |
||
1089 | The mechanism described above is, in practice, very similar to |
||
1090 | Java's interface I1 extends interface I2. The example below shows |
||
1091 | the GObject equivalent: |
||
1092 | <informalexample><programlisting> |
||
1093 | /* Make the ViewerEditableLossy interface require ViewerEditable interface. */ |
||
1094 | G_DEFINE_INTERFACE (ViewerEditableLossy, viewer_editable_lossy, VIEWER_TYPE_EDITABLE); |
||
1095 | </programlisting></informalexample> |
||
1096 | In the <function><link linkend="G-DEFINE-INTERFACE:CAPS">G_DEFINE_INTERFACE</link></function> |
||
1097 | call above, the third parameter defines the prerequisite type. This |
||
1098 | is the GType of either an interface or a class. In this case |
||
1099 | the <type>ViewerEditable</type> interface is a prerequisite of |
||
1100 | <type>ViewerEditableLossy</type>. The code |
||
1101 | below shows how an implementation can implement both interfaces and |
||
1102 | register their implementations: |
||
1103 | <informalexample><programlisting> |
||
1104 | static void |
||
1105 | viewer_file_editable_lossy_compress (ViewerEditableLossy *editable) |
||
1106 | { |
||
1107 | ViewerFile *self = VIEWER_FILE (editable); |
||
1108 | |||
1109 | g_print ("File implementation of lossy editable interface compress method: %s.\n", |
||
1110 | self->filename); |
||
1111 | } |
||
1112 | |||
1113 | static void |
||
1114 | viewer_file_editable_lossy_interface_init (ViewerEditableLossyInterface *iface) |
||
1115 | { |
||
1116 | iface->compress = viewer_file_editable_lossy_compress; |
||
1117 | } |
||
1118 | |||
1119 | static void |
||
1120 | viewer_file_editable_save (ViewerEditable *editable, |
||
1121 | GError **error) |
||
1122 | { |
||
1123 | ViewerFile *self = VIEWER_FILE (editable); |
||
1124 | |||
1125 | g_print ("File implementation of editable interface save method: %s.\n", |
||
1126 | self->filename); |
||
1127 | } |
||
1128 | |||
1129 | static void |
||
1130 | viewer_file_editable_undo (ViewerEditable *editable, |
||
1131 | guint n_steps) |
||
1132 | { |
||
1133 | ViewerFile *self = VIEWER_FILE (editable); |
||
1134 | |||
1135 | g_print ("File implementation of editable interface undo method: %s.\n", |
||
1136 | self->filename); |
||
1137 | } |
||
1138 | |||
1139 | static void |
||
1140 | viewer_file_editable_redo (ViewerEditable *editable, |
||
1141 | guint n_steps) |
||
1142 | { |
||
1143 | ViewerFile *self = VIEWER_FILE (editable); |
||
1144 | |||
1145 | g_print ("File implementation of editable interface redo method: %s.\n", |
||
1146 | self->filename); |
||
1147 | } |
||
1148 | |||
1149 | static void |
||
1150 | viewer_file_editable_interface_init (ViewerEditableInterface *iface) |
||
1151 | { |
||
1152 | iface->save = viewer_file_editable_save; |
||
1153 | iface->undo = viewer_file_editable_undo; |
||
1154 | iface->redo = viewer_file_editable_redo; |
||
1155 | } |
||
1156 | |||
1157 | static void |
||
1158 | viewer_file_class_init (ViewerFileClass *klass) |
||
1159 | { |
||
1160 | /* Nothing here. */ |
||
1161 | } |
||
1162 | |||
1163 | static void |
||
1164 | viewer_file_init (ViewerFile *self) |
||
1165 | { |
||
1166 | /* Instance variable initialisation code. */ |
||
1167 | } |
||
1168 | |||
1169 | G_DEFINE_TYPE_WITH_CODE (ViewerFile, viewer_file, G_TYPE_OBJECT, |
||
1170 | G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, |
||
1171 | viewer_file_editable_interface_init) |
||
1172 | G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE_LOSSY, |
||
1173 | viewer_file_editable_lossy_interface_init)) |
||
1174 | </programlisting></informalexample> |
||
1175 | It is very important to notice that the order in which interface |
||
1176 | implementations are added to the main object is not random: |
||
1177 | <function><link linkend="g-type-add-interface-static">g_type_add_interface_static</link></function>, |
||
1178 | which is called by |
||
1179 | <function><link linkend="G-DEFINE-INTERFACE:CAPS">G_IMPLEMENT_INTERFACE</link></function>, |
||
1180 | must be invoked first on the interfaces which have no prerequisites and then on |
||
1181 | the others. |
||
1182 | </para> |
||
1183 | </sect1> |
||
1184 | |||
1185 | <sect1 id="howto-interface-properties"> |
||
1186 | <title>Interface properties</title> |
||
1187 | |||
1188 | <para> |
||
1189 | GObject interfaces can also have |
||
1190 | properties. Declaration of the interface properties is similar to |
||
1191 | declaring the properties of ordinary GObject types as explained in |
||
1192 | <xref linkend="gobject-properties"/>, except that |
||
1193 | <function><link linkend="g-object-interface-install-property">g_object_interface_install_property</link></function> |
||
1194 | is used to declare the properties instead of |
||
1195 | <function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>. |
||
1196 | </para> |
||
1197 | |||
1198 | <para> |
||
1199 | To include a property named 'autosave-frequency' of type <type>gdouble</type> in the |
||
1200 | <type>ViewerEditable</type> interface example code above, we only need to |
||
1201 | add one call in <function>viewer_editable_default_init</function> as shown |
||
1202 | below: |
||
1203 | <informalexample><programlisting> |
||
1204 | static void |
||
1205 | viewer_editable_default_init (ViewerEditableInterface *iface) |
||
1206 | { |
||
1207 | g_object_interface_install_property (iface, |
||
1208 | g_param_spec_double ("autosave-frequency", |
||
1209 | "Autosave frequency", |
||
1210 | "Frequency (in per-seconds) to autosave backups of the editable content at. " |
||
1211 | "Or zero to disable autosaves.", |
||
1212 | 0.0, /* minimum */ |
||
1213 | G_MAXDOUBLE, /* maximum */ |
||
1214 | 0.0, /* default */ |
||
1215 | G_PARAM_READWRITE)); |
||
1216 | } |
||
1217 | </programlisting></informalexample> |
||
1218 | </para> |
||
1219 | |||
1220 | <para> |
||
1221 | One point worth noting is that the declared property wasn't assigned an |
||
1222 | integer ID. The reason being that integer IDs of properties are used |
||
1223 | only inside the <function>get_property</function> and |
||
1224 | <function>set_property</function> virtual methods. Since interfaces |
||
1225 | declare but do not <emphasis>implement</emphasis> properties, there is no |
||
1226 | need to assign integer IDs to them. |
||
1227 | </para> |
||
1228 | |||
1229 | <para> |
||
1230 | An implementation declares and defines its properties in the usual |
||
1231 | way as explained in <xref linkend="gobject-properties"/>, except for one |
||
1232 | small change: it can declare the properties of the interface it |
||
1233 | implements using <function><link linkend="g-object-class-override-property">g_object_class_override_property</link></function> |
||
1234 | instead of <function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>. |
||
1235 | The following code snippet shows the modifications needed in the |
||
1236 | <type>ViewerFile</type> declaration and implementation above: |
||
1237 | <informalexample><programlisting> |
||
1238 | struct _ViewerFile |
||
1239 | { |
||
1240 | GObject parent_instance; |
||
1241 | |||
1242 | gdouble autosave_frequency; |
||
1243 | }; |
||
1244 | |||
1245 | enum |
||
1246 | { |
||
1247 | PROP_AUTOSAVE_FREQUENCY = 1, |
||
1248 | N_PROPERTIES |
||
1249 | }; |
||
1250 | |||
1251 | static void |
||
1252 | viewer_file_set_property (GObject *object, |
||
1253 | guint prop_id, |
||
1254 | const GValue *value, |
||
1255 | GParamSpec *pspec) |
||
1256 | { |
||
1257 | ViewerFile *file = VIEWER_FILE (object); |
||
1258 | |||
1259 | switch (prop_id) |
||
1260 | { |
||
1261 | case PROP_AUTOSAVE_FREQUENCY: |
||
1262 | file->autosave_frequency = g_value_get_double (value); |
||
1263 | break; |
||
1264 | |||
1265 | default: |
||
1266 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
||
1267 | break; |
||
1268 | } |
||
1269 | } |
||
1270 | |||
1271 | static void |
||
1272 | viewer_file_get_property (GObject *object, |
||
1273 | guint prop_id, |
||
1274 | GValue *value, |
||
1275 | GParamSpec *pspec) |
||
1276 | { |
||
1277 | ViewerFile *file = VIEWER_FILE (object); |
||
1278 | |||
1279 | switch (prop_id) |
||
1280 | { |
||
1281 | case PROP_AUTOSAVE_FREQUENCY: |
||
1282 | g_value_set_double (value, file->autosave_frequency); |
||
1283 | break; |
||
1284 | |||
1285 | default: |
||
1286 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
||
1287 | break; |
||
1288 | } |
||
1289 | } |
||
1290 | |||
1291 | static void |
||
1292 | viewer_file_class_init (ViewerFileClass *klass) |
||
1293 | { |
||
1294 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
||
1295 | |||
1296 | object_class->set_property = viewer_file_set_property; |
||
1297 | object_class->get_property = viewer_file_get_property; |
||
1298 | |||
1299 | g_object_class_override_property (object_class, PROP_AUTOSAVE_FREQUENCY, "autosave-frequency"); |
||
1300 | } |
||
1301 | </programlisting></informalexample> |
||
1302 | </para> |
||
1303 | |||
1304 | </sect1> |
||
1305 | |||
1306 | <sect1 id="howto-interface-override"> |
||
1307 | <title>Overriding interface methods</title> |
||
1308 | |||
1309 | <para> |
||
1310 | If a base class already implements an interface and a derived |
||
1311 | class needs to implement the same interface but needs to override certain |
||
1312 | methods, you must reimplement the interface and set only the interface |
||
1313 | methods which need overriding. |
||
1314 | </para> |
||
1315 | |||
1316 | <para> |
||
1317 | In this example, <type>ViewerAudioFile</type> is derived from |
||
1318 | <type>ViewerFile</type>. Both implement the <type>ViewerEditable</type> |
||
1319 | interface. <type>ViewerAudioFile</type> only implements one method of the |
||
1320 | <type>ViewerEditable</type> interface and uses the base class implementation of |
||
1321 | the other. |
||
1322 | <informalexample><programlisting> |
||
1323 | static void |
||
1324 | viewer_audio_file_editable_save (ViewerEditable *editable, |
||
1325 | GError **error) |
||
1326 | { |
||
1327 | ViewerAudioFile *self = VIEWER_AUDIO_FILE (editable); |
||
1328 | |||
1329 | g_print ("Audio file implementation of editable interface save method.\n"); |
||
1330 | } |
||
1331 | |||
1332 | static void |
||
1333 | viewer_audio_file_editable_interface_init (ViewerEditableInterface *iface) |
||
1334 | { |
||
1335 | /* Override the implementation of save(). */ |
||
1336 | iface->save = viewer_audio_file_editable_save; |
||
1337 | |||
1338 | /* |
||
1339 | * Leave iface->undo and ->redo alone, they are already set to the |
||
1340 | * base class implementation. |
||
1341 | */ |
||
1342 | } |
||
1343 | |||
1344 | G_DEFINE_TYPE_WITH_CODE (ViewerAudioFile, viewer_audio_file, VIEWER_TYPE_FILE, |
||
1345 | G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, |
||
1346 | viewer_audio_file_editable_interface_init)) |
||
1347 | |||
1348 | static void |
||
1349 | viewer_audio_file_class_init (ViewerAudioFileClass *klass) |
||
1350 | { |
||
1351 | /* Nothing here. */ |
||
1352 | } |
||
1353 | |||
1354 | static void |
||
1355 | viewer_audio_file_init (ViewerAudioFile *self) |
||
1356 | { |
||
1357 | /* Nothing here. */ |
||
1358 | } |
||
1359 | </programlisting></informalexample> |
||
1360 | </para> |
||
1361 | |||
1362 | <para> |
||
1363 | To access the base class interface implementation use |
||
1364 | <function><link linkend="g-type-interface-peek-parent">g_type_interface_peek_parent</link></function> |
||
1365 | from within an interface's <function>default_init</function> function. |
||
1366 | </para> |
||
1367 | |||
1368 | <para> |
||
1369 | To call the base class implementation of an interface |
||
1370 | method from an derived class where than interface method has been |
||
1371 | overridden, stash away the pointer returned from |
||
1372 | <function><link linkend="g-type-interface-peek-parent">g_type_interface_peek_parent</link></function> |
||
1373 | in a global variable. |
||
1374 | </para> |
||
1375 | |||
1376 | <para> |
||
1377 | In this example <type>ViewerAudioFile</type> overrides the |
||
1378 | <function>save</function> interface method. In its overridden method |
||
1379 | it calls the base class implementation of the same interface method. |
||
1380 | <informalexample><programlisting> |
||
1381 | static ViewerEditableInterface *viewer_editable_parent_interface = NULL; |
||
1382 | |||
1383 | static void |
||
1384 | viewer_audio_file_editable_save (ViewerEditable *editable, |
||
1385 | GError **error) |
||
1386 | { |
||
1387 | ViewerAudioFile *self = VIEWER_AUDIO_FILE (editable); |
||
1388 | |||
1389 | g_print ("Audio file implementation of editable interface save method.\n"); |
||
1390 | |||
1391 | /* Now call the base implementation */ |
||
1392 | viewer_editable_parent_interface->save (editable, error); |
||
1393 | } |
||
1394 | |||
1395 | static void |
||
1396 | viewer_audio_file_editable_interface_init (ViewerEditableInterface *iface) |
||
1397 | { |
||
1398 | viewer_editable_parent_interface = g_type_interface_peek_parent (iface); |
||
1399 | |||
1400 | iface->save = viewer_audio_file_editable_save; |
||
1401 | } |
||
1402 | |||
1403 | G_DEFINE_TYPE_WITH_CODE (ViewerAudioFile, viewer_audio_file, VIEWER_TYPE_FILE, |
||
1404 | G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, |
||
1405 | viewer_audio_file_editable_interface_init)) |
||
1406 | |||
1407 | static void |
||
1408 | viewer_audio_file_class_init (ViewerAudioFileClass *klass) |
||
1409 | { |
||
1410 | /* Nothing here. */ |
||
1411 | } |
||
1412 | |||
1413 | static void |
||
1414 | viewer_audio_file_init (ViewerAudioFile *self) |
||
1415 | { |
||
1416 | /* Nothing here. */ |
||
1417 | } |
||
1418 | </programlisting></informalexample> |
||
1419 | </para> |
||
1420 | |||
1421 | </sect1> |
||
1422 | |||
1423 | </chapter> |
||
1424 | <!-- End Howto Interfaces --> |
||
1425 | |||
1426 | <chapter id="howto-signals"> |
||
1427 | <title>How to create and use signals</title> |
||
1428 | |||
1429 | <para> |
||
1430 | The signal system in GType is pretty complex and |
||
1431 | flexible: it is possible for its users to connect at runtime any |
||
1432 | number of callbacks (implemented in any language for which a binding |
||
1433 | exists) |
||
1434 | <footnote> |
||
1435 | <para>A Python callback can be connected to any signal on any |
||
1436 | C-based GObject, and vice versa, assuming that the Python object |
||
1437 | inherits from GObject.</para> |
||
1438 | </footnote> |
||
1439 | to any signal and to stop the emission of any signal at any |
||
1440 | state of the signal emission process. This flexibility makes it |
||
1441 | possible to use GSignal for much more than just emitting signals to |
||
1442 | multiple clients. |
||
1443 | </para> |
||
1444 | |||
1445 | <sect1 id="howto-simple-signals"> |
||
1446 | <title>Simple use of signals</title> |
||
1447 | |||
1448 | <para> |
||
1449 | The most basic use of signals is to implement event |
||
1450 | notification. For example, given a <type>ViewerFile</type> object with |
||
1451 | a <function>write</function> method, a signal could be emitted whenever |
||
1452 | the file is changed using that method. |
||
1453 | The code below shows how the user can connect a callback to the |
||
1454 | "changed" signal. |
||
1455 | <informalexample><programlisting> |
||
1456 | file = g_object_new (VIEWER_FILE_TYPE, NULL); |
||
1457 | |||
1458 | g_signal_connect (file, "changed", (GCallback) changed_event, NULL); |
||
1459 | |||
1460 | viewer_file_write (file, buffer, strlen (buffer)); |
||
1461 | </programlisting></informalexample> |
||
1462 | </para> |
||
1463 | |||
1464 | <para> |
||
1465 | The <type>ViewerFile</type> signal is registered in the |
||
1466 | <function>class_init</function> function: |
||
1467 | <informalexample><programlisting> |
||
1468 | file_signals[CHANGED] = |
||
1469 | g_signal_newv ("changed", |
||
1470 | G_TYPE_FROM_CLASS (object_class), |
||
1471 | G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, |
||
1472 | NULL /* closure */, |
||
1473 | NULL /* accumulator */, |
||
1474 | NULL /* accumulator data */, |
||
1475 | NULL /* C marshaller */, |
||
1476 | G_TYPE_NONE /* return_type */, |
||
1477 | |||
1478 | NULL /* param_types */); |
||
1479 | </programlisting></informalexample> |
||
1480 | and the signal is emitted in <function>viewer_file_write</function>: |
||
1481 | <informalexample><programlisting> |
||
1482 | void |
||
1483 | viewer_file_write (ViewerFile *self, |
||
1484 | const guint8 *buffer, |
||
1485 | gsize size) |
||
1486 | { |
||
1487 | g_return_if_fail (VIEWER_IS_FILE (self)); |
||
1488 | g_return_if_fail (buffer != NULL || size == 0); |
||
1489 | |||
1490 | /* First write data. */ |
||
1491 | |||
1492 | /* Then, notify user of data written. */ |
||
1493 | g_signal_emit (self, file_signals[CHANGED], 0 /* details */); |
||
1494 | } |
||
1495 | </programlisting></informalexample> |
||
1496 | As shown above, the details parameter can safely be set to zero if no |
||
1497 | detail needs to be conveyed. For a discussion of what it can be used for, |
||
1498 | see <xref linkend="signal-detail"/> |
||
1499 | </para> |
||
1500 | |||
1501 | <para> |
||
1502 | The C signal marshaller should always be <literal>NULL</literal>, in which |
||
1503 | case the best marshaller for the given closure type will be chosen by |
||
1504 | GLib. This may be an internal marshaller specific to the closure type, or |
||
1505 | <function>g_cclosure_marshal_generic</function>, which implements generic |
||
1506 | conversion of arrays of parameters to C callback invocations. GLib used to |
||
1507 | require the user to write or generate a type-specific marshaller and pass |
||
1508 | that, but that has been deprecated in favour of automatic selection of |
||
1509 | marshallers. |
||
1510 | </para> |
||
1511 | |||
1512 | <para> |
||
1513 | Note that <function>g_cclosure_marshal_generic</function> is slower than |
||
1514 | non-generic marshallers, so should be avoided for performance critical |
||
1515 | code. However, performance critical code should rarely be using signals |
||
1516 | anyway, as emitting a signal blocks on emitting it to all listeners, which |
||
1517 | has potentially unbounded cost. |
||
1518 | </para> |
||
1519 | </sect1> |
||
1520 | </chapter> |
||
1521 | </part> |