diff --git a/docs/reference/gobject/gobject-docs.xml b/docs/reference/gobject/gobject-docs.xml
index ecac914d7..cb7a74229 100644
--- a/docs/reference/gobject/gobject-docs.xml
+++ b/docs/reference/gobject/gobject-docs.xml
@@ -43,7 +43,6 @@
-
diff --git a/docs/reference/gobject/gobject.toml.in b/docs/reference/gobject/gobject.toml.in
index 2e879e1aa..881971449 100644
--- a/docs/reference/gobject/gobject.toml.in
+++ b/docs/reference/gobject/gobject.toml.in
@@ -43,6 +43,7 @@ urlmap_file = "urlmap.js"
# The same order will be used when generating the index
content_files = [
"concepts.md",
+ "tutorial.md",
"floating-refs.md",
"boxed.md",
"enum-types.md",
diff --git a/docs/reference/gobject/meson.build b/docs/reference/gobject/meson.build
index 30c2b6d99..3a608ddfe 100644
--- a/docs/reference/gobject/meson.build
+++ b/docs/reference/gobject/meson.build
@@ -38,7 +38,6 @@ if get_option('gtk_doc')
'glib-mkenums.xml',
'glib-genmarshal.xml',
'gobject-query.xml',
- 'tut_howto.xml',
'tut_tools.xml'
],
html_assets : [
@@ -72,6 +71,7 @@ expand_content_files = [
'enum-types.md',
'floating-refs.md',
'gvalue.md',
+ 'tutorial.md',
]
gobject_gir = meson.current_source_dir() / 'GObject-2.0.gir'
diff --git a/docs/reference/gobject/tut_howto.xml b/docs/reference/gobject/tut_howto.xml
deleted file mode 100644
index 82419239a..000000000
--- a/docs/reference/gobject/tut_howto.xml
+++ /dev/null
@@ -1,1535 +0,0 @@
-
-
-
- Tutorial
-
-
- This chapter tries to answer the real-life questions of users and presents
- the most common use cases in order from most likely to least
- likely.
-
-
-
-
- How to define and implement a new GObject
-
-
- This chapter focuses on the implementation of a subtype of GObject, for
- example to create a custom class hierarchy, or to subclass a GTK widget.
-
-
-
- Throughout the chapter, a running example of a file viewer program is used,
- which has a ViewerFile class to represent a single file being
- viewed, and various derived classes for different types of files with
- special functionality, such as audio files. The example application also
- supports editing files (for example, to tweak a photo being viewed), using
- a ViewerEditable interface.
-
-
-
- Boilerplate header code
-
-
- The first step before writing the code for your GObject is to write the
- type's header which contains the needed type, function and macro
- definitions. Each of these elements is nothing but a convention which
- is followed by almost all users of GObject, and has been refined over
- multiple years of experience developing GObject-based code. If you are
- writing a library, it is particularly important for you to adhere closely
- to these conventions; users of your library will assume that you have.
- Even if not writing a library, it will help other people who want to work
- on your project.
-
-
-
- Pick a name convention for your headers and source code and stick to it:
-
- use a dash to separate the prefix from the typename:
- viewer-file.h and viewer-file.c
- (this is the convention used by Nautilus and most GNOME libraries).
- use an underscore to separate the prefix from the
- typename: viewer_file.h and
- viewer_file.c.
- Do not separate the prefix from the typename:
- viewerfile.h and viewerfile.c.
- (this is the convention used by GTK)
-
- Some people like the first two solutions better: it makes reading file
- names easier for those with poor eyesight.
-
-
-
- The basic conventions for any header which exposes a GType are described
- in .
-
-
-
- If you want to declare a type named ‘file’ in namespace ‘viewer’, name the
- type instance ViewerFile and its class
- ViewerFileClass (names are case sensitive). The
- recommended method of declaring a type differs based on whether the type
- is final or derivable.
-
-
-
- Final types cannot be subclassed further, and should be the default choice
- for new types — changing a final type to be derivable is always a change
- that will be compatible with existing uses of the code, but the converse
- will often cause problems. Final types are declared using
- G_DECLARE_FINAL_TYPE,
- and require a structure to hold the instance data to be declared in the
- source code (not the header file).
-
-
-/*
- * Copyright/Licensing information.
- */
-
-/* inclusion guard */
-#ifndef __VIEWER_FILE_H__
-#define __VIEWER_FILE_H__
-
-#include <glib-object.h>
-/*
- * Potentially, include other headers on which this header depends.
- */
-
-G_BEGIN_DECLS
-
-/*
- * Type declaration.
- */
-#define VIEWER_TYPE_FILE viewer_file_get_type ()
-G_DECLARE_FINAL_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject)
-
-/*
- * Method definitions.
- */
-ViewerFile *viewer_file_new (void);
-
-G_END_DECLS
-
-#endif /* __VIEWER_FILE_H__ */
-
-
-
-
- Derivable types can be subclassed further, and their class and
- instance structures form part of the public API which must not be changed
- if API stability is cared about. They are declared using
- G_DECLARE_DERIVABLE_TYPE:
-
-/*
- * Copyright/Licensing information.
- */
-
-/* inclusion guard */
-#ifndef __VIEWER_FILE_H__
-#define __VIEWER_FILE_H__
-
-#include <glib-object.h>
-/*
- * Potentially, include other headers on which this header depends.
- */
-
-G_BEGIN_DECLS
-
-/*
- * Type declaration.
- */
-#define VIEWER_TYPE_FILE viewer_file_get_type ()
-G_DECLARE_DERIVABLE_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject)
-
-struct _ViewerFileClass
-{
- GObjectClass parent_class;
-
- /* Class virtual function fields. */
- void (* open) (ViewerFile *file,
- GError **error);
-
- /* Padding to allow adding up to 12 new virtual functions without
- * breaking ABI. */
- gpointer padding[12];
-};
-
-/*
- * Method definitions.
- */
-ViewerFile *viewer_file_new (void);
-
-G_END_DECLS
-
-#endif /* __VIEWER_FILE_H__ */
-
-
-
-
- The convention for header includes is to add the minimum number of
- #include directives to the top of your headers needed
- to compile that header. This
- allows client code to simply #include "viewer-file.h",
- without needing to know the prerequisites for
- viewer-file.h.
-
-
-
-
- Boilerplate code
-
-
- In your code, the first step is to #include the
- needed headers:
-
-/*
- * Copyright information
- */
-
-#include "viewer-file.h"
-
-/* Private structure definition. */
-typedef struct {
- gchar *filename;
- /* stuff */
-} ViewerFilePrivate;
-
-/*
- * forward definitions
- */
-
-
-
-
- If the class is being declared as final using
- G_DECLARE_FINAL_TYPE, its instance structure should
- be defined in the C file:
-
-struct _ViewerFile
-{
- GObject parent_instance;
-
- /* Other members, including private data. */
-};
-
-
-
-
- Call the G_DEFINE_TYPE macro (or
- G_DEFINE_TYPE_WITH_PRIVATE if your class needs
- private data — final types do not need private data)
- using the name
- of the type, the prefix of the functions and the parent GType to
- reduce the amount of boilerplate needed. This macro will:
-
-
- implement the viewer_file_get_type
- function
- define a parent class pointer accessible from
- the whole .c file
- add private instance data to the type (if using
- G_DEFINE_TYPE_WITH_PRIVATE)
-
-
-
-
- If the class has been declared as final using
- G_DECLARE_FINAL_TYPE (see
- ), private data should be placed in
- the instance structure, ViewerFile, and
- G_DEFINE_TYPE should be used instead of
- G_DEFINE_TYPE_WITH_PRIVATE. The instance structure
- for a final class is not exposed publicly, and is not embedded in the
- instance structures of any derived classes (because the class is final);
- so its size can vary without causing incompatibilities for code which uses
- the class. Conversely, private data for derivable classes
- must be included in a private structure, and
- G_DEFINE_TYPE_WITH_PRIVATE must be used.
-
-
-G_DEFINE_TYPE (ViewerFile, viewer_file, G_TYPE_OBJECT)
-
-or
-
-G_DEFINE_TYPE_WITH_PRIVATE (ViewerFile, viewer_file, G_TYPE_OBJECT)
-
-
-
-
- It is also possible to use the
- G_DEFINE_TYPE_WITH_CODE macro to control the
- get_type function implementation — for instance, to
- add a call to the G_IMPLEMENT_INTERFACE macro to
- implement an interface.
-
-
-
-
- Object construction
-
-
- People often get confused when trying to construct their GObjects because of the
- sheer number of different ways to hook into the objects's construction process: it is
- difficult to figure which is the correct, recommended way.
-
-
-
- shows what user-provided functions
- are invoked during object instantiation and in which order they are invoked.
- A user looking for the equivalent of the simple C++ constructor function should use
- the instance_init method. It will be invoked after
- all the parents’ instance_init
- functions have been invoked. It cannot take arbitrary construction parameters
- (as in C++) but if your object needs arbitrary parameters to complete initialization,
- you can use construction properties.
-
-
-
- Construction properties will be set only after all
- instance_init functions have run.
- No object reference will be returned to the client of g_object_new
- until all the construction properties have been set.
-
-
-
- It is important to note that object construction cannot ever
- fail. If you require a fallible GObject construction, you can use the
- GInitable and
- GAsyncInitable
- interfaces provided by the GIO library.
-
-
-
- You should write the following code first:
-
-G_DEFINE_TYPE_WITH_PRIVATE (ViewerFile, viewer_file, G_TYPE_OBJECT)
-
-static void
-viewer_file_class_init (ViewerFileClass *klass)
-{
-}
-
-static void
-viewer_file_init (ViewerFile *self)
-{
- ViewerFilePrivate *priv = viewer_file_get_instance_private (self);
-
- /* initialize all public and private members to reasonable default values.
- * They are all automatically initialized to 0 to begin with. */
-}
-
-
-
-
- If you need special construction properties (with
- G_PARAM_CONSTRUCT_ONLY
- set), install the properties in
- the class_init() function, override the set_property()
- and get_property() methods of the GObject class,
- and implement them as described by .
-
-
-
- Property IDs must start from 1, as 0 is reserved for internal use by
- GObject.
-
-enum
-{
- PROP_FILENAME = 1,
- PROP_ZOOM_LEVEL,
- N_PROPERTIES
-};
-
-static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
-
-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);
-
- 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_object_class_install_properties (object_class,
- N_PROPERTIES,
- obj_properties);
-}
-
- If you need this, make sure you can build and run code similar to the
- code shown above. Also, make sure your construct properties can be set
- without side effects during construction.
-
-
-
- Some people sometimes need to complete the initialization of an instance
- of a type only after the properties passed to the constructors have been
- set. This is possible through the use of the constructor()
- class method as described in or,
- more simply, using the constructed() class method.
- Note that the constructed()
- virtual function will only be invoked after the properties marked as
- G_PARAM_CONSTRUCT_ONLY or
- G_PARAM_CONSTRUCT have been consumed, but
- before the regular properties passed to g_object_new()
- have been set.
-
-
-
-
- Object destruction
-
-
- Again, it is often difficult to figure out which mechanism to use to
- hook into the object's destruction process: when the last
- g_object_unref
- function call is made, a lot of things happen as described in
- .
-
-
-
- The destruction process of your object is in two phases: dispose and
- finalize. This split is necessary to handle
- potential cycles due to the nature of the reference counting mechanism
- used by GObject, as well as dealing with temporary revival of
- instances in case of signal emission during the destruction sequence.
- See for more information.
-
-struct _ViewerFilePrivate
-{
- gchar *filename;
- guint zoom_level;
-
- GInputStream *input_stream;
-};
-
-G_DEFINE_TYPE_WITH_PRIVATE (ViewerFile, viewer_file, G_TYPE_OBJECT)
-
-static void
-viewer_file_dispose (GObject *gobject)
-{
- ViewerFilePrivate *priv = viewer_file_get_instance_private (VIEWER_FILE (gobject));
-
- /* In dispose(), you are supposed to free all types referenced from this
- * object which might themselves hold a reference to self. Generally,
- * the most simple solution is to unref all members on which you own a
- * reference.
- */
-
- /* dispose() might be called multiple times, so we must guard against
- * calling g_object_unref() on an invalid GObject by setting the member
- * NULL; g_clear_object() does this for us.
- */
- g_clear_object (&priv->input_stream);
-
- /* Always chain up to the parent class; there is no need to check if
- * the parent class implements the dispose() virtual function: it is
- * always guaranteed to do so
- */
- G_OBJECT_CLASS (viewer_file_parent_class)->dispose (gobject);
-}
-
-static void
-viewer_file_finalize (GObject *gobject)
-{
- ViewerFilePrivate *priv = viewer_file_get_instance_private (VIEWER_FILE (gobject));
-
- g_free (priv->filename);
-
- /* Always chain up to the parent class; as with dispose(), finalize()
- * is guaranteed to exist on the parent's class virtual function table
- */
- G_OBJECT_CLASS (viewer_file_parent_class)->finalize (gobject);
-}
-
-static void
-viewer_file_class_init (ViewerFileClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->dispose = viewer_file_dispose;
- object_class->finalize = viewer_file_finalize;
-}
-
-static void
-viewer_file_init (ViewerFile *self);
-{
- ViewerFilePrivate *priv = viewer_file_get_instance_private (self);
-
- priv->input_stream = g_object_new (VIEWER_TYPE_INPUT_STREAM, NULL);
- priv->filename = /* would be set as a property */;
-}
-
-
-
-
- It is possible that object methods might be invoked after dispose is
- run and before finalize runs. GObject does not consider this to be a
- program error: you must gracefully detect this and neither crash nor
- warn the user, by having a disposed instance revert to an inert state.
-
-
-
-
- Object methods
-
-
- Just as with C++, there are many different ways to define object
- methods and extend them: the following list and sections draw on
- C++ vocabulary. (Readers are expected to know basic C++ concepts.
- Those who have not had to write C++ code recently can refer to e.g.
- to refresh
- their memories.)
-
-
- non-virtual public methods,
-
-
- virtual public methods and
-
-
- virtual private methods
-
-
-
-
-
- Non-virtual public methods
-
-
- These are the simplest, providing a simple method which
- acts on the object. Provide a function
- prototype in the header and an implementation of that prototype
- in the source file.
-
-/* declaration in the header. */
-void viewer_file_open (ViewerFile *self,
- GError **error);
-
-/* implementation in the source file */
-void
-viewer_file_open (ViewerFile *self,
- GError **error)
-{
- g_return_if_fail (VIEWER_IS_FILE (self));
- g_return_if_fail (error == NULL || *error == NULL);
-
- /* do stuff here. */
-}
-
-
-
-
-
- Virtual public methods
-
-
- This is the preferred way to create GObjects with overridable methods:
-
-
- Define the common method and its virtual function in the
- class structure in the public header
-
-
- Define the common method in the header file and implement it in the
- source file
-
-
- Implement a base version of the virtual function in the source
- file and initialize the virtual function pointer to this
- implementation in the object’s class_init
- function; or leave it as NULL for a ‘pure
- virtual’ method which must be overridden by derived classes
-
-
- Re-implement the virtual function in each derived class which needs
- to override it
-
-
-
-
- Note that virtual functions can only be defined if the class is
- derivable, declared using
- G_DECLARE_DERIVABLE_TYPE
- so the class structure can be defined.
-
-/* declaration in viewer-file.h. */
-#define VIEWER_TYPE_FILE viewer_file_get_type ()
-G_DECLARE_DERIVABLE_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject)
-
-struct _ViewerFileClass
-{
- GObjectClass parent_class;
-
- /* stuff */
- void (*open) (ViewerFile *self,
- GError **error);
-
- /* Padding to allow adding up to 12 new virtual functions without
- * breaking ABI. */
- gpointer padding[12];
-};
-
-void viewer_file_open (ViewerFile *self,
- GError **error);
-
-/* implementation in viewer-file.c */
-void
-viewer_file_open (ViewerFile *self,
- GError **error)
-{
- ViewerFileClass *klass;
-
- g_return_if_fail (VIEWER_IS_FILE (self));
- g_return_if_fail (error == NULL || *error == NULL);
-
- klass = VIEWER_FILE_GET_CLASS (self);
- g_return_if_fail (klass->open != NULL);
-
- klass->open (self, error);
-}
-
- The code above simply redirects the open call
- to the relevant virtual function.
-
-
-
- It is possible to provide a default
- implementation for this class method in the object's
- class_init function: initialize the
- klass->open field to a pointer to the
- actual implementation.
- By default, class methods that are not inherited are initialized to
- NULL, and thus are to be considered "pure virtual".
-
-static void
-viewer_file_real_close (ViewerFile *self,
- GError **error)
-{
- /* Default implementation for the virtual method. */
-}
-
-static void
-viewer_file_class_init (ViewerFileClass *klass)
-{
- /* this is not necessary, except for demonstration purposes.
- *
- * pure virtual method: mandates implementation in children.
- */
- klass->open = NULL;
-
- /* merely virtual method. */
- klass->close = viewer_file_real_close;
-}
-
-void
-viewer_file_open (ViewerFile *self,
- GError **error)
-{
- ViewerFileClass *klass;
-
- g_return_if_fail (VIEWER_IS_FILE (self));
- g_return_if_fail (error == NULL || *error == NULL);
-
- klass = VIEWER_FILE_GET_CLASS (self);
-
- /* if the method is purely virtual, then it is a good idea to
- * check that it has been overridden before calling it, and,
- * depending on the intent of the class, either ignore it silently
- * or warn the user.
- */
- g_return_if_fail (klass->open != NULL);
- klass->open (self, error);
-}
-
-void
-viewer_file_close (ViewerFile *self,
- GError **error)
-{
- ViewerFileClass *klass;
-
- g_return_if_fail (VIEWER_IS_FILE (self));
- g_return_if_fail (error == NULL || *error == NULL);
-
- klass = VIEWER_FILE_GET_CLASS (self);
- if (klass->close != NULL)
- klass->close (self, error);
-}
-
-
-
-
-
- Virtual private Methods
-
-
- These are very similar to virtual
- public methods. They just don't
- have a public function to call directly. The header
- file contains only a declaration of the virtual function:
-
-/* declaration in viewer-file.h. */
-struct _ViewerFileClass
-{
- GObjectClass parent;
-
- /* Public virtual method as before. */
- void (*open) (ViewerFile *self,
- GError **error);
-
- /* Private helper function to work out whether the file can be loaded via
- * memory mapped I/O, or whether it has to be read as a stream. */
- gboolean (*can_memory_map) (ViewerFile *self);
-
- /* Padding to allow adding up to 12 new virtual functions without
- * breaking ABI. */
- gpointer padding[12];
-};
-
-void viewer_file_open (ViewerFile *self, GError **error);
-
- These virtual functions are often used to delegate part of the job
- to child classes:
-
-/* this accessor function is static: it is not exported outside of this file. */
-static gboolean
-viewer_file_can_memory_map (ViewerFile *self)
-{
- return VIEWER_FILE_GET_CLASS (self)->can_memory_map (self);
-}
-
-void
-viewer_file_open (ViewerFile *self,
- GError **error)
-{
- g_return_if_fail (VIEWER_IS_FILE (self));
- g_return_if_fail (error == NULL || *error == NULL);
-
- /*
- * Try to load the file using memory mapped I/O, if the implementation of the
- * class determines that is possible using its private virtual method.
- */
- if (viewer_file_can_memory_map (self))
- {
- /* Load the file using memory mapped I/O. */
- }
- else
- {
- /* Fall back to trying to load the file using streaming I/O… */
- }
-}
-
-
-
-
- Again, it is possible to provide a default implementation for this
- private virtual function:
-
-static gboolean
-viewer_file_real_can_memory_map (ViewerFile *self)
-{
- /* As an example, always return false. Or, potentially return true if the
- * file is local. */
- return FALSE;
-}
-
-static void
-viewer_file_class_init (ViewerFileClass *klass)
-{
- /* non-pure virtual method; does not have to be implemented in children. */
- klass->can_memory_map = viewer_file_real_can_memory_map;
-}
-
-
-
-
- Derived classes can then override the method with code such as:
-
-static void
-viewer_audio_file_class_init (ViewerAudioFileClass *klass)
-{
- ViewerFileClass *file_class = VIEWER_FILE_CLASS (klass);
-
- /* implement pure virtual function. */
- file_class->can_memory_map = viewer_audio_file_can_memory_map;
-}
-
-
-
-
-
-
- Chaining up
-
- Chaining up is often loosely defined by the following set of
- conditions:
-
- Parent class A defines a public virtual method named foo and
- provides a default implementation.
- Child class B re-implements method foo.
- B’s implementation of foo calls (‘chains up to’) its parent class A’s implementation of foo.
-
- There are various uses of this idiom:
-
- You need to extend the behaviour of a class without modifying its code. You create
- a subclass to inherit its implementation, re-implement a public virtual method to modify the behaviour
- and chain up to ensure that the previous behaviour is not really modified, just extended.
-
- You need to implement the
- Chain
- Of Responsibility pattern: each object of the inheritance
- tree chains up to its parent (typically, at the beginning or the end of the method) to ensure that
- each handler is run in turn.
-
-
-
-
- To explicitly chain up to the implementation of the virtual method in the parent class,
- you first need a handle to the original parent class structure. This pointer can then be used to
- access the original virtual function pointer and invoke it directly.
-
-
- The original adjective used in this sentence is not innocuous. To fully
- understand its meaning, recall how class structures are initialized: for each object type,
- the class structure associated with this object is created by first copying the class structure of its
- parent type (a simple memcpy) and then by invoking the class_init callback on
- the resulting class structure. Since the class_init callback is responsible for overwriting the class structure
- with the user re-implementations of the class methods, the modified copy of the parent class
- structure stored in the derived instance cannot be used. A copy of the class structure of an instance of the parent
- class is needed.
-
-
-
-
-
- Use the parent_class pointer created and initialized
- by the
- G_DEFINE_TYPE
- family of macros, for instance:
-
-static void
-b_method_to_call (B *obj, gint some_param)
-{
- /* do stuff before chain up */
-
- /* call the method_to_call() virtual function on the
- * parent of BClass, AClass.
- *
- * remember the explicit cast to AClass*
- */
- A_CLASS (b_parent_class)->method_to_call (obj, some_param);
-
- /* do stuff after chain up */
-}
-
-
-
-
-
-
-
-
-
- How to define and implement interfaces
-
-
- Defining interfaces
-
-
- The theory behind how GObject interfaces work is given in
- ; this section covers how to
- define and implement an interface.
-
-
-
- The first step is to get the header right. This interface
- defines three methods:
-
-/*
- * Copyright/Licensing information.
- */
-
-#ifndef __VIEWER_EDITABLE_H__
-#define __VIEWER_EDITABLE_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define VIEWER_TYPE_EDITABLE viewer_editable_get_type ()
-G_DECLARE_INTERFACE (ViewerEditable, viewer_editable, VIEWER, EDITABLE, GObject)
-
-struct _ViewerEditableInterface
-{
- GTypeInterface parent_iface;
-
- void (*save) (ViewerEditable *self,
- GError **error);
- void (*undo) (ViewerEditable *self,
- guint n_steps);
- void (*redo) (ViewerEditable *self,
- guint n_steps);
-};
-
-void viewer_editable_save (ViewerEditable *self,
- GError **error);
-void viewer_editable_undo (ViewerEditable *self,
- guint n_steps);
-void viewer_editable_redo (ViewerEditable *self,
- guint n_steps);
-
-G_END_DECLS
-
-#endif /* __VIEWER_EDITABLE_H__ */
-
- This code is the same as the code for a normal GType
- which derives from a GObject except for a few details:
-
-
- The _GET_CLASS function is called
- _GET_IFACE (and is defined by
- G_DECLARE_INTERFACE).
-
-
- The instance type, ViewerEditable, is not fully defined: it is
- used merely as an abstract type which represents an instance of
- whatever object which implements the interface.
-
-
- The parent of the ViewerEditableInterface is
- GTypeInterface, not GObjectClass.
-
-
-
-
-
- The implementation of the ViewerEditable type itself is trivial:
-
- G_DEFINE_INTERFACE
- creates a viewer_editable_get_type function which registers the
- type in the type system. The third argument is used to define a
- prerequisite interface
- (which we'll talk about more later). Just pass 0 for this
- argument when an interface has no prerequisite.
-
- viewer_editable_default_init is expected
- to register the interface's signals if there are any (we will see a bit
- later how to use them).
- The interface methods viewer_editable_save,
- viewer_editable_undo and viewer_editable_redo dereference the interface
- structure to access its associated interface function and call it.
-
-
-
-G_DEFINE_INTERFACE (ViewerEditable, viewer_editable, G_TYPE_OBJECT)
-
-static void
-viewer_editable_default_init (ViewerEditableInterface *iface)
-{
- /* add properties and signals to the interface here */
-}
-
-void
-viewer_editable_save (ViewerEditable *self,
- GError **error)
-{
- ViewerEditableInterface *iface;
-
- g_return_if_fail (VIEWER_IS_EDITABLE (self));
- g_return_if_fail (error == NULL || *error == NULL);
-
- iface = VIEWER_EDITABLE_GET_IFACE (self);
- g_return_if_fail (iface->save != NULL);
- iface->save (self, error);
-}
-
-void
-viewer_editable_undo (ViewerEditable *self,
- guint n_steps)
-{
- ViewerEditableInterface *iface;
-
- g_return_if_fail (VIEWER_IS_EDITABLE (self));
-
- iface = VIEWER_EDITABLE_GET_IFACE (self);
- g_return_if_fail (iface->undo != NULL);
- iface->undo (self, n_steps);
-}
-
-void
-viewer_editable_redo (ViewerEditable *self,
- guint n_steps)
-{
- ViewerEditableInterface *iface;
-
- g_return_if_fail (VIEWER_IS_EDITABLE (self));
-
- iface = VIEWER_EDITABLE_GET_IFACE (self);
- g_return_if_fail (iface->redo != NULL);
- iface->redo (self, n_steps);
-}
-
-
-
-
-
- Implementing interfaces
-
-
- Once the interface is defined, implementing it is rather trivial.
-
-
-
- The first step is to define a normal final GObject class exactly as in
- .
-
-
-
- The second step is to implement ViewerFile by defining
- it using
- G_DEFINE_TYPE_WITH_CODE
- and
- G_IMPLEMENT_INTERFACE
- instead of
- G_DEFINE_TYPE:
-
-static void viewer_file_editable_interface_init (ViewerEditableInterface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (ViewerFile, viewer_file, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE,
- viewer_file_editable_interface_init))
-
- This definition is very much like all the similar functions seen
- previously. The only interface-specific code present here is the use of
- G_IMPLEMENT_INTERFACE.
-
-
- Classes can implement multiple interfaces by using multiple calls to
- G_IMPLEMENT_INTERFACE
- inside the call to
- G_DEFINE_TYPE_WITH_CODE
-
-
-
- viewer_file_editable_interface_init, the interface
- initialization function: inside it every virtual method of the interface
- must be assigned to its implementation:
-
-static void
-viewer_file_editable_save (ViewerFile *self,
- GError **error)
-{
- g_print ("File implementation of editable interface save method: %s.\n",
- self->filename);
-}
-
-static void
-viewer_file_editable_undo (ViewerFile *self,
- guint n_steps)
-{
- g_print ("File implementation of editable interface undo method: %s.\n",
- self->filename);
-}
-
-static void
-viewer_file_editable_redo (ViewerFile *self,
- guint n_steps)
-{
- g_print ("File implementation of editable interface redo method: %s.\n",
- self->filename);
-}
-
-static void
-viewer_file_editable_interface_init (ViewerEditableInterface *iface)
-{
- iface->save = viewer_file_editable_save;
- iface->undo = viewer_file_editable_undo;
- iface->redo = viewer_file_editable_redo;
-}
-
-static void
-viewer_file_init (ViewerFile *self)
-{
- /* Instance variable initialisation code. */
-}
-
-
-
- If the object is not of final type, e.g. was declared using
- G_DECLARE_DERIVABLE_TYPE
- then
- G_ADD_PRIVATE
- macro should be added. The private structure should be declared exactly
- as for a normal derivable object, see .
-
-G_DEFINE_TYPE_WITH_CODE (ViewerFile, viewer_file, G_TYPE_OBJECT,
- G_ADD_PRIVATE (ViewerFile)
- G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE,
- viewer_file_editable_interface_init))
-
-
-
-
-
- Interface definition prerequisites
-
-
- To specify that an interface requires the presence of other interfaces
- when implemented, GObject introduces the concept of
- prerequisites: it is possible to associate
- a list of prerequisite types to an interface. For example, if
- object A wishes to implement interface I1, and if interface I1 has a
- prerequisite on interface I2, A has to implement both I1 and I2.
-
-
-
- The mechanism described above is, in practice, very similar to
- Java's interface I1 extends interface I2. The example below shows
- the GObject equivalent:
-
-/* Make the ViewerEditableLossy interface require ViewerEditable interface. */
-G_DEFINE_INTERFACE (ViewerEditableLossy, viewer_editable_lossy, VIEWER_TYPE_EDITABLE)
-
- In the G_DEFINE_INTERFACE
- call above, the third parameter defines the prerequisite type. This
- is the GType of either an interface or a class. In this case
- the ViewerEditable interface is a prerequisite of
- ViewerEditableLossy. The code
- below shows how an implementation can implement both interfaces and
- register their implementations:
-
-static void
-viewer_file_editable_lossy_compress (ViewerEditableLossy *editable)
-{
- ViewerFile *self = VIEWER_FILE (editable);
-
- g_print ("File implementation of lossy editable interface compress method: %s.\n",
- self->filename);
-}
-
-static void
-viewer_file_editable_lossy_interface_init (ViewerEditableLossyInterface *iface)
-{
- iface->compress = viewer_file_editable_lossy_compress;
-}
-
-static void
-viewer_file_editable_save (ViewerEditable *editable,
- GError **error)
-{
- ViewerFile *self = VIEWER_FILE (editable);
-
- g_print ("File implementation of editable interface save method: %s.\n",
- self->filename);
-}
-
-static void
-viewer_file_editable_undo (ViewerEditable *editable,
- guint n_steps)
-{
- ViewerFile *self = VIEWER_FILE (editable);
-
- g_print ("File implementation of editable interface undo method: %s.\n",
- self->filename);
-}
-
-static void
-viewer_file_editable_redo (ViewerEditable *editable,
- guint n_steps)
-{
- ViewerFile *self = VIEWER_FILE (editable);
-
- g_print ("File implementation of editable interface redo method: %s.\n",
- self->filename);
-}
-
-static void
-viewer_file_editable_interface_init (ViewerEditableInterface *iface)
-{
- iface->save = viewer_file_editable_save;
- iface->undo = viewer_file_editable_undo;
- iface->redo = viewer_file_editable_redo;
-}
-
-static void
-viewer_file_class_init (ViewerFileClass *klass)
-{
- /* Nothing here. */
-}
-
-static void
-viewer_file_init (ViewerFile *self)
-{
- /* Instance variable initialisation code. */
-}
-
-G_DEFINE_TYPE_WITH_CODE (ViewerFile, viewer_file, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE,
- viewer_file_editable_interface_init)
- G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE_LOSSY,
- viewer_file_editable_lossy_interface_init))
-
- It is very important to notice that the order in which interface
- implementations are added to the main object is not random:
- g_type_add_interface_static,
- which is called by
- G_IMPLEMENT_INTERFACE,
- must be invoked first on the interfaces which have no prerequisites and then on
- the others.
-
-
-
-
- Interface properties
-
-
- GObject interfaces can also have
- properties. Declaration of the interface properties is similar to
- declaring the properties of ordinary GObject types as explained in
- , except that
- g_object_interface_install_property
- is used to declare the properties instead of
- g_object_class_install_property.
-
-
-
- To include a property named 'autosave-frequency' of type gdouble in the
- ViewerEditable interface example code above, we only need to
- add one call in viewer_editable_default_init as shown
- below:
-
-static void
-viewer_editable_default_init (ViewerEditableInterface *iface)
-{
- g_object_interface_install_property (iface,
- g_param_spec_double ("autosave-frequency",
- "Autosave frequency",
- "Frequency (in per-seconds) to autosave backups of the editable content at. "
- "Or zero to disable autosaves.",
- 0.0, /* minimum */
- G_MAXDOUBLE, /* maximum */
- 0.0, /* default */
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-}
-
-
-
-
- One point worth noting is that the declared property wasn't assigned an
- integer ID. The reason being that integer IDs of properties are used
- only inside the get_property and
- set_property virtual methods. Since interfaces
- declare but do not implement properties, there is no
- need to assign integer IDs to them.
-
-
-
- An implementation declares and defines its properties in the usual
- way as explained in , except for one
- small change: it can declare the properties of the interface it
- implements using g_object_class_override_property
- instead of g_object_class_install_property.
- The following code snippet shows the modifications needed in the
- ViewerFile declaration and implementation above:
-
-struct _ViewerFile
-{
- GObject parent_instance;
-
- gdouble autosave_frequency;
-};
-
-enum
-{
- PROP_AUTOSAVE_FREQUENCY = 1,
- N_PROPERTIES
-};
-
-static void
-viewer_file_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- ViewerFile *file = VIEWER_FILE (object);
-
- switch (prop_id)
- {
- case PROP_AUTOSAVE_FREQUENCY:
- file->autosave_frequency = g_value_get_double (value);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-viewer_file_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- ViewerFile *file = VIEWER_FILE (object);
-
- switch (prop_id)
- {
- case PROP_AUTOSAVE_FREQUENCY:
- g_value_set_double (value, file->autosave_frequency);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_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;
-
- g_object_class_override_property (object_class, PROP_AUTOSAVE_FREQUENCY, "autosave-frequency");
-}
-
-
-
-
-
-
- Overriding interface methods
-
-
- If a base class already implements an interface and a derived
- class needs to implement the same interface but needs to override certain
- methods, you must reimplement the interface and set only the interface
- methods which need overriding.
-
-
-
- In this example, ViewerAudioFile is derived from
- ViewerFile. Both implement the ViewerEditable
- interface. ViewerAudioFile only implements one method of the
- ViewerEditable interface and uses the base class implementation of
- the other.
-
-static void
-viewer_audio_file_editable_save (ViewerEditable *editable,
- GError **error)
-{
- ViewerAudioFile *self = VIEWER_AUDIO_FILE (editable);
-
- g_print ("Audio file implementation of editable interface save method.\n");
-}
-
-static void
-viewer_audio_file_editable_interface_init (ViewerEditableInterface *iface)
-{
- /* Override the implementation of save(). */
- iface->save = viewer_audio_file_editable_save;
-
- /*
- * Leave iface->undo and ->redo alone, they are already set to the
- * base class implementation.
- */
-}
-
-G_DEFINE_TYPE_WITH_CODE (ViewerAudioFile, viewer_audio_file, VIEWER_TYPE_FILE,
- G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE,
- viewer_audio_file_editable_interface_init))
-
-static void
-viewer_audio_file_class_init (ViewerAudioFileClass *klass)
-{
- /* Nothing here. */
-}
-
-static void
-viewer_audio_file_init (ViewerAudioFile *self)
-{
- /* Nothing here. */
-}
-
-
-
-
- To access the base class interface implementation use
- g_type_interface_peek_parent
- from within an interface's default_init function.
-
-
-
- To call the base class implementation of an interface
- method from a derived class where than interface method has been
- overridden, stash away the pointer returned from
- g_type_interface_peek_parent
- in a global variable.
-
-
-
- In this example ViewerAudioFile overrides the
- save interface method. In its overridden method
- it calls the base class implementation of the same interface method.
-
-static ViewerEditableInterface *viewer_editable_parent_interface = NULL;
-
-static void
-viewer_audio_file_editable_save (ViewerEditable *editable,
- GError **error)
-{
- ViewerAudioFile *self = VIEWER_AUDIO_FILE (editable);
-
- g_print ("Audio file implementation of editable interface save method.\n");
-
- /* Now call the base implementation */
- viewer_editable_parent_interface->save (editable, error);
-}
-
-static void
-viewer_audio_file_editable_interface_init (ViewerEditableInterface *iface)
-{
- viewer_editable_parent_interface = g_type_interface_peek_parent (iface);
-
- iface->save = viewer_audio_file_editable_save;
-}
-
-G_DEFINE_TYPE_WITH_CODE (ViewerAudioFile, viewer_audio_file, VIEWER_TYPE_FILE,
- G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE,
- viewer_audio_file_editable_interface_init))
-
-static void
-viewer_audio_file_class_init (ViewerAudioFileClass *klass)
-{
- /* Nothing here. */
-}
-
-static void
-viewer_audio_file_init (ViewerAudioFile *self)
-{
- /* Nothing here. */
-}
-
-
-
-
-
-
-
-
-
- How to create and use signals
-
-
- The signal system in GType is pretty complex and
- flexible: it is possible for its users to connect at runtime any
- number of callbacks (implemented in any language for which a binding
- exists)
-
- A Python callback can be connected to any signal on any
- C-based GObject, and vice versa, assuming that the Python object
- inherits from GObject.
-
- to any signal and to stop the emission of any signal at any
- state of the signal emission process. This flexibility makes it
- possible to use GSignal for much more than just emitting signals to
- multiple clients.
-
-
-
- Simple use of signals
-
-
- The most basic use of signals is to implement event
- notification. For example, given a ViewerFile object with
- a write method, a signal could be emitted whenever
- the file is changed using that method.
- The code below shows how the user can connect a callback to the
- "changed" signal.
-
-file = g_object_new (VIEWER_FILE_TYPE, NULL);
-
-g_signal_connect (file, "changed", (GCallback) changed_event, NULL);
-
-viewer_file_write (file, buffer, strlen (buffer));
-
-
-
-
- The ViewerFile signal is registered in the
- class_init function:
-
-file_signals[CHANGED] =
- g_signal_newv ("changed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
- NULL /* closure */,
- NULL /* accumulator */,
- NULL /* accumulator data */,
- NULL /* C marshaller */,
- G_TYPE_NONE /* return_type */,
- 0 /* n_params */,
- NULL /* param_types */);
-
- and the signal is emitted in viewer_file_write:
-
-void
-viewer_file_write (ViewerFile *self,
- const guint8 *buffer,
- gsize size)
-{
- g_return_if_fail (VIEWER_IS_FILE (self));
- g_return_if_fail (buffer != NULL || size == 0);
-
- /* First write data. */
-
- /* Then, notify user of data written. */
- g_signal_emit (self, file_signals[CHANGED], 0 /* details */);
-}
-
- As shown above, the details parameter can safely be set to zero if no
- detail needs to be conveyed. For a discussion of what it can be used for,
- see
-
-
-
- The C signal marshaller should always be NULL, in which
- case the best marshaller for the given closure type will be chosen by
- GLib. This may be an internal marshaller specific to the closure type, or
- g_cclosure_marshal_generic, which implements generic
- conversion of arrays of parameters to C callback invocations. GLib used to
- require the user to write or generate a type-specific marshaller and pass
- that, but that has been deprecated in favour of automatic selection of
- marshallers.
-
-
-
- Note that g_cclosure_marshal_generic is slower than
- non-generic marshallers, so should be avoided for performance critical
- code. However, performance critical code should rarely be using signals
- anyway, as emitting a signal blocks on emitting it to all listeners, which
- has potentially unbounded cost.
-
-
-
-
diff --git a/docs/reference/gobject/tutorial.md b/docs/reference/gobject/tutorial.md
new file mode 100644
index 000000000..ec5eab939
--- /dev/null
+++ b/docs/reference/gobject/tutorial.md
@@ -0,0 +1,1288 @@
+Title: GObject Tutorial
+
+# GObject Tutorial
+
+## How to define and implement a new GObject
+
+This document focuses on the implementation of a subtype of GObject, for
+example to create a custom class hierarchy, or to subclass a GTK widget.
+
+Throughout the chapter, a running example of a file viewer program is used,
+which has a `ViewerFile` class to represent a single file being viewed, and
+various derived classes for different types of files with special
+functionality, such as audio files. The example application also supports
+editing files (for example, to tweak a photo being viewed), using a
+`ViewerEditable` interface.
+
+### Boilerplate header code
+
+The first step before writing the code for your GObject is to write the
+type's header which contains the needed type, function and macro
+definitions. Each of these elements is nothing but a convention which is
+followed by almost all users of GObject, and has been refined over multiple
+years of experience developing GObject-based code. If you are writing a
+library, it is particularly important for you to adhere closely to these
+conventions; users of your library will assume that you have. Even if not
+writing a library, it will help other people who want to work on your
+project.
+
+Pick a name convention for your headers and source code and stick to it:
+
+- use a dash to separate the prefix from the typename: `viewer-file.h` and
+ `viewer-file.c` (this is the convention used by most GNOME libraries and
+ applications)
+- use an underscore to separate the prefix from the typename:
+ `viewer_file.h` and `viewer_file.c`
+- do not separate the prefix from the typename: `viewerfile.h` and
+ `viewerfile.c` (this is the convention used by GTK)
+
+Some people like the first two solutions better: it makes reading file names
+easier for those with poor eyesight.
+
+The basic conventions for any header which exposes a GType are described in
+the section of the Type system introduction called
+["Conventions"](concepts.html#conventions).
+
+If you want to declare a type named "file" in the namespace "viewer", name
+the type instance `ViewerFile` and its class `ViewerFileClass` (names are
+case sensitive). The recommended method of declaring a type differs based on
+whether the type is final or derivable.
+
+Final types cannot be subclassed further, and should be the default choice
+for new types—changing a final type to be derivable is always a change that
+will be compatible with existing uses of the code, but the converse will
+often cause problems. Final types are declared using the
+`G_DECLARE_FINAL_TYPE` macro, and require a structure to hold the instance
+data to be declared in the source code (not the header file).
+
+```c
+/*
+ * Copyright/Licensing information.
+ */
+
+/* inclusion guard */
+#pragma once
+
+#include
+
+/*
+ * Potentially, include other headers on which this header depends.
+ */
+
+G_BEGIN_DECLS
+
+/*
+ * Type declaration.
+ */
+#define VIEWER_TYPE_FILE viewer_file_get_type()
+G_DECLARE_FINAL_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject)
+
+/*
+ * Method definitions.
+ */
+ViewerFile *viewer_file_new (void);
+
+G_END_DECLS
+```
+
+Derivable types can be subclassed further, and their class and instance
+structures form part of the public API which must not be changed if API
+stability is cared about. They are declared using the
+`G_DECLARE_DERIVABLE_TYPE` macro:
+
+```c
+/*
+ * Copyright/Licensing information.
+ */
+
+/* inclusion guard */
+#pragma once
+
+#include
+
+/*
+ * Potentially, include other headers on which this header depends.
+ */
+
+G_BEGIN_DECLS
+
+/*
+ * Type declaration.
+ */
+#define VIEWER_TYPE_FILE viewer_file_get_type()
+G_DECLARE_DERIVABLE_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject)
+
+struct _ViewerFileClass
+{
+ GObjectClass parent_class;
+
+ /* Class virtual function fields. */
+ void (* open) (ViewerFile *file,
+ GError **error);
+
+ /* Padding to allow adding up to 12 new virtual functions without
+ * breaking ABI. */
+ gpointer padding[12];
+};
+
+/*
+ * Method definitions.
+ */
+ViewerFile *viewer_file_new (void);
+
+G_END_DECLS
+```
+
+The convention for header includes is to add the minimum number of
+`#include` directives to the top of your headers needed to compile that
+header. This allows client code to simply `#include "viewer-file.h"`,
+without needing to know the prerequisites for `viewer-file.h`.
+
+### Boilerplate code
+
+In your code, the first step is to `#include` the needed headers:
+
+```c
+/*
+ * Copyright/Licensing information
+ */
+
+#include "viewer-file.h"
+
+/* Private structure definition. */
+typedef struct {
+ char *filename;
+
+ /* other private fields */
+} ViewerFilePrivate;
+
+/*
+ * forward definitions
+ */
+```
+
+If the class is being declared as final using `G_DECLARE_FINAL_TYPE`, its instance structure should be defined in the C file:
+
+```c
+struct _ViewerFile
+{
+ GObject parent_instance;
+
+ /* Other members, including private data. */
+};
+```
+
+Call the `G_DEFINE_TYPE` macro (or `G_DEFINE_TYPE_WITH_PRIVATE` if your
+class needs private data—final types do not need private data) using the
+name of the type, the prefix of the functions and the parent GType to reduce
+the amount of boilerplate needed. This macro will:
+
+- implement the `viewer_file_get_type` function
+- define a parent class pointer accessible from the whole `.c` file
+- add private instance data to the type (if using `G_DEFINE_TYPE_WITH_PRIVATE`)
+
+If the class has been declared as final using `G_DECLARE_FINAL_TYPE` private
+data should be placed in the instance structure, `ViewerFile`, and
+`G_DEFINE_TYPE` should be used instead of `G_DEFINE_TYPE_WITH_PRIVATE`. The
+instance structure for a final class is not exposed publicly, and is not
+embedded in the instance structures of any derived classes (because the
+class is final); so its size can vary without causing incompatibilities for
+code which uses the class. Conversely, private data for derivable classes
+must be included in a private structure, and `G_DEFINE_TYPE_WITH_PRIVATE`
+must be used.
+
+```c
+G_DEFINE_TYPE (ViewerFile, viewer_file, G_TYPE_OBJECT)
+```
+
+or
+
+```c
+G_DEFINE_TYPE_WITH_PRIVATE (ViewerFile, viewer_file, G_TYPE_OBJECT)
+```
+
+It is also possible to use the `G_DEFINE_TYPE_WITH_CODE` macro to control
+the `get_type` function implementation — for instance, to add a call to the
+`G_IMPLEMENT_INTERFACE` macro to implement an interface.
+
+### Object construction
+
+People often get confused when trying to construct their GObjects because of
+the sheer number of different ways to hook into the objects's construction
+process: it is difficult to figure which is the correct, recommended way.
+
+The [documentation on object
+instantiation](concepts.html#object-instantiation) shows what user-provided
+functions are invoked during object instantiation and in which order they
+are invoked. A user looking for the equivalent of the simple C++ constructor
+function should use the `instance_init` method. It will be invoked after all
+the parents’ `instance_init` functions have been invoked. It cannot take
+arbitrary construction parameters (as in C++) but if your object needs
+arbitrary parameters to complete initialization, you can use construction
+properties.
+
+Construction properties will be set only after all `instance_init` functions have run. No object reference will be returned to the client of `g_object_new()` until all the construction properties have been set.
+
+It is important to note that object construction cannot ever fail. If you
+require a fallible GObject construction, you can use the `GInitable` and
+`GAsyncInitable` interfaces provided by the GIO library.
+
+You should write the following code first:
+
+```c
+G_DEFINE_TYPE_WITH_PRIVATE (ViewerFile, viewer_file, G_TYPE_OBJECT)
+
+static void
+viewer_file_class_init (ViewerFileClass *klass)
+{
+}
+
+static void
+viewer_file_init (ViewerFile *self)
+{
+ ViewerFilePrivate *priv = viewer_file_get_instance_private (self);
+
+ /* initialize all public and private members to reasonable default values.
+ * They are all automatically initialized to 0 to begin with. */
+}
+```
+
+If you need special construction properties (with `G_PARAM_CONSTRUCT_ONLY`
+set), install the properties in the `class_init()` function, override the
+`set_property()` and `get_property()` methods of the GObject class, and
+implement them as described by the section called ["Object
+properties"](concepts.html#object-properties).
+
+Property identifiers must start from 1, as 0 is reserved for internal use by GObject.
+
+```c
+enum
+{
+ PROP_FILENAME = 1,
+ PROP_ZOOM_LEVEL,
+ N_PROPERTIES
+};
+
+static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
+
+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);
+
+ 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_object_class_install_properties (object_class,
+ N_PROPERTIES,
+ obj_properties);
+}
+```
+
+If you need this, make sure you can build and run code similar to the code
+shown above. Also, make sure your construct properties can be set without
+side effects during construction.
+
+Some people sometimes need to complete the initialization of an instance of
+a type only after the properties passed to the constructors have been set.
+This is possible through the use of the `constructor()` class method as
+described in the section called "Object instantiation" or, more simply,
+using the `constructed()` class method. Note that the `constructed()` virtual
+function will only be invoked after the properties marked as
+`G_PARAM_CONSTRUCT_ONLY` or `G_PARAM_CONSTRUCT` have been consumed, but before
+the regular properties passed to `g_object_new()` have been set.
+
+### Object destruction
+
+Again, it is often difficult to figure out which mechanism to use to hook
+into the object's destruction process: when the last `g_object_unref()` function
+call is made, a lot of things happen as described in [the "Object memory
+management" section](concepts.html#object-memory-management) of the
+documentation.
+
+The destruction process of your object is in two phases: dispose and
+finalize. This split is necessary to handle potential cycles due to the
+nature of the reference counting mechanism used by GObject, as well as
+dealing with temporary revival of instances in case of signal emission
+during the destruction sequence.
+
+```c
+struct _ViewerFilePrivate
+{
+ gchar *filename;
+ guint zoom_level;
+
+ GInputStream *input_stream;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (ViewerFile, viewer_file, G_TYPE_OBJECT)
+
+static void
+viewer_file_dispose (GObject *gobject)
+{
+ ViewerFilePrivate *priv = viewer_file_get_instance_private (VIEWER_FILE (gobject));
+
+ /* In dispose(), you are supposed to free all types referenced from this
+ * object which might themselves hold a reference to self. Generally,
+ * the most simple solution is to unref all members on which you own a
+ * reference.
+ */
+
+ /* dispose() might be called multiple times, so we must guard against
+ * calling g_object_unref() on an invalid GObject by setting the member
+ * NULL; g_clear_object() does this for us.
+ */
+ g_clear_object (&priv->input_stream);
+
+ /* Always chain up to the parent class; there is no need to check if
+ * the parent class implements the dispose() virtual function: it is
+ * always guaranteed to do so
+ */
+ G_OBJECT_CLASS (viewer_file_parent_class)->dispose (gobject);
+}
+
+static void
+viewer_file_finalize (GObject *gobject)
+{
+ ViewerFilePrivate *priv = viewer_file_get_instance_private (VIEWER_FILE (gobject));
+
+ g_free (priv->filename);
+
+ /* Always chain up to the parent class; as with dispose(), finalize()
+ * is guaranteed to exist on the parent's class virtual function table
+ */
+ G_OBJECT_CLASS (viewer_file_parent_class)->finalize (gobject);
+}
+
+static void
+viewer_file_class_init (ViewerFileClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = viewer_file_dispose;
+ object_class->finalize = viewer_file_finalize;
+}
+
+static void
+viewer_file_init (ViewerFile *self);
+{
+ ViewerFilePrivate *priv = viewer_file_get_instance_private (self);
+
+ priv->input_stream = g_object_new (VIEWER_TYPE_INPUT_STREAM, NULL);
+ priv->filename = /* would be set as a property */;
+}
+```
+
+It is possible that object methods might be invoked after dispose is run and
+before finalize runs. GObject does not consider this to be a program error:
+you must gracefully detect this and neither crash nor warn the user, by
+having a disposed instance revert to an inert state.
+
+### Object methods
+
+Just as with C++, there are many different ways to define object methods and
+extend them: the following list and sections draw on C++ vocabulary.
+(Readers are expected to know basic C++ concepts. Those who have not had to
+write C++ code recently can refer to a [C++
+tutorial](http://www.cplusplus.com/doc/tutorial/) to refresh their
+memories.)
+
+- non-virtual public methods,
+- virtual public methods and
+- virtual private methods
+- non-virtual private methods
+
+#### Non-Virtual Methods
+
+These are the simplest, providing a simple method which acts on the object.
+Provide a function prototype in the header and an implementation of that
+prototype in the source file.
+
+```c
+/* declaration in the header. */
+void viewer_file_open (ViewerFile *self,
+ GError **error);
+```
+
+```c
+/* implementation in the source file */
+void
+viewer_file_open (ViewerFile *self,
+ GError **error)
+{
+ g_return_if_fail (VIEWER_IS_FILE (self));
+ g_return_if_fail (error == NULL || *error == NULL);
+
+ /* do stuff here. */
+}
+```
+
+#### Virtual public methods
+
+This is the preferred way to create GObjects with overridable methods:
+
+- define the common method and its virtual function in the class structure
+ in the public header
+- define the common method in the header file and implement it in the source
+ file
+- implement a base version of the virtual function in the source file and
+ initialize the virtual function pointer to this implementation in the
+ object’s `class_init` function; or leave it as `NULL` for a ‘pure virtual’
+ method which must be overridden by derived classes
+- re-implement the virtual function in each derived class which needs to
+ override it
+
+Note that virtual functions can only be defined if the class is derivable,
+declared using `G_DECLARE_DERIVABLE_TYPE` so the class structure can be
+defined.
+
+```c
+/* declaration in viewer-file.h. */
+#define VIEWER_TYPE_FILE viewer_file_get_type ()
+G_DECLARE_DERIVABLE_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject)
+
+struct _ViewerFileClass
+{
+ GObjectClass parent_class;
+
+ /* stuff */
+ void (*open) (ViewerFile *self,
+ GError **error);
+
+ /* Padding to allow adding up to 12 new virtual functions without
+ * breaking ABI. */
+ gpointer padding[12];
+};
+
+void viewer_file_open (ViewerFile *self,
+ GError **error);
+```
+
+```c
+/* implementation in viewer-file.c */
+void
+viewer_file_open (ViewerFile *self,
+ GError **error)
+{
+ ViewerFileClass *klass;
+
+ g_return_if_fail (VIEWER_IS_FILE (self));
+ g_return_if_fail (error == NULL || *error == NULL);
+
+ klass = VIEWER_FILE_GET_CLASS (self);
+ g_return_if_fail (klass->open != NULL);
+
+ klass->open (self, error);
+}
+```
+
+The code above simply redirects the open call to the relevant virtual
+function.
+
+It is possible to provide a default implementation for this class method in
+the object's `class_init` function: initialize the `klass->open` field to a
+pointer to the actual implementation. By default, class methods that are not
+inherited are initialized to `NULL`, and thus are to be considered "pure
+virtual".
+
+```c
+static void
+viewer_file_real_close (ViewerFile *self,
+ GError **error)
+{
+ /* Default implementation for the virtual method. */
+}
+
+static void
+viewer_file_class_init (ViewerFileClass *klass)
+{
+ /* this is not necessary, except for demonstration purposes.
+ *
+ * pure virtual method: mandates implementation in children.
+ */
+ klass->open = NULL;
+
+ /* merely virtual method. */
+ klass->close = viewer_file_real_close;
+}
+
+void
+viewer_file_open (ViewerFile *self,
+ GError **error)
+{
+ ViewerFileClass *klass;
+
+ g_return_if_fail (VIEWER_IS_FILE (self));
+ g_return_if_fail (error == NULL || *error == NULL);
+
+ klass = VIEWER_FILE_GET_CLASS (self);
+
+ /* if the method is purely virtual, then it is a good idea to
+ * check that it has been overridden before calling it, and,
+ * depending on the intent of the class, either ignore it silently
+ * or warn the user.
+ */
+ g_return_if_fail (klass->open != NULL);
+ klass->open (self, error);
+}
+
+void
+viewer_file_close (ViewerFile *self,
+ GError **error)
+{
+ ViewerFileClass *klass;
+
+ g_return_if_fail (VIEWER_IS_FILE (self));
+ g_return_if_fail (error == NULL || *error == NULL);
+
+ klass = VIEWER_FILE_GET_CLASS (self);
+ if (klass->close != NULL)
+ klass->close (self, error);
+}
+```
+
+#### Virtual private Methods
+
+These are very similar to virtual public methods. They just don't have a
+public function to call directly. The header file contains only a
+declaration of the virtual function:
+
+```c
+/* declaration in viewer-file.h. */
+struct _ViewerFileClass
+{
+ GObjectClass parent;
+
+ /* Public virtual method as before. */
+ void (*open) (ViewerFile *self,
+ GError **error);
+
+ /* Private helper function to work out whether the file can be loaded via
+ * memory mapped I/O, or whether it has to be read as a stream. */
+ gboolean (*can_memory_map) (ViewerFile *self);
+
+ /* Padding to allow adding up to 12 new virtual functions without
+ * breaking ABI. */
+ gpointer padding[12];
+};
+
+void viewer_file_open (ViewerFile *self, GError **error);
+```
+
+These virtual functions are often used to delegate part of the job to child classes:
+
+```c
+/* this accessor function is static: it is not exported outside of this file. */
+static gboolean
+viewer_file_can_memory_map (ViewerFile *self)
+{
+ return VIEWER_FILE_GET_CLASS (self)->can_memory_map (self);
+}
+
+void
+viewer_file_open (ViewerFile *self,
+ GError **error)
+{
+ g_return_if_fail (VIEWER_IS_FILE (self));
+ g_return_if_fail (error == NULL || *error == NULL);
+
+ /*
+ * Try to load the file using memory mapped I/O, if the implementation of the
+ * class determines that is possible using its private virtual method.
+ */
+ if (viewer_file_can_memory_map (self))
+ {
+ /* Load the file using memory mapped I/O. */
+ }
+ else
+ {
+ /* Fall back to trying to load the file using streaming I/O… */
+ }
+}
+```
+
+Again, it is possible to provide a default implementation for this private virtual function:
+
+```c
+static gboolean
+viewer_file_real_can_memory_map (ViewerFile *self)
+{
+ /* As an example, always return false. Or, potentially return true if the
+ * file is local. */
+ return FALSE;
+}
+
+static void
+viewer_file_class_init (ViewerFileClass *klass)
+{
+ /* non-pure virtual method; does not have to be implemented in children. */
+ klass->can_memory_map = viewer_file_real_can_memory_map;
+}
+```
+
+Derived classes can then override the method with code such as:
+
+```c
+static void
+viewer_audio_file_class_init (ViewerAudioFileClass *klass)
+{
+ ViewerFileClass *file_class = VIEWER_FILE_CLASS (klass);
+
+ /* implement pure virtual function. */
+ file_class->can_memory_map = viewer_audio_file_can_memory_map;
+}
+```
+
+### Chaining up
+
+Chaining up is often loosely defined by the following set of conditions:
+
+- parent class A defines a public virtual method named `foo` and provides a
+ default implementation
+- child class B re-implements method `foo`
+- B’s implementation of `foo` calls (‘chains up to’) its parent class A’s
+ implementation of `foo`
+
+There are various uses of this idiom:
+
+- you need to extend the behaviour of a class without modifying its code.
+ You create a subclass to inherit its implementation, re-implement a public
+ virtual method to modify the behaviour and chain up to ensure that the
+ previous behaviour is not really modified, just extended
+- you need to implement the
+ [Chain of Responsibility pattern](https://en.wikipedia.org/wiki/Chain-of-responsibility_pattern):
+ each object of the inheritance tree chains up to its parent (typically, at the
+ beginning or the end of the method) to ensure that each handler is run in turn
+
+To explicitly chain up to the implementation of the virtual method in the
+parent class, you first need a handle to the original parent class
+structure. This pointer can then be used to access the original virtual
+function pointer and invoke it directly
+
+The "original" adjective used in the sentence above is not innocuous. To
+fully understand its meaning, recall how class structures are initialized:
+for each object type, the class structure associated with this object is
+created by first copying the class structure of its parent type (a simple
+memcpy) and then by invoking the `class_init` callback on the resulting class
+structure. Since the `class_init` callback is responsible for overwriting the
+class structure with the user re-implementations of the class methods, the
+modified copy of the parent class structure stored in the derived instance
+cannot be used. A copy of the class structure of an instance of the parent
+class is needed.
+
+To chain up, you can use the `parent_class` pointer created and initialized
+by the `G_DEFINE_TYPE` family of macros, for instance:
+
+```c
+static void
+b_method_to_call (B *obj, int some_param)
+{
+ /* do stuff before chain up */
+
+ /* call the method_to_call() virtual function on the
+ * parent of BClass, AClass.
+ *
+ * remember the explicit cast to AClass*
+ */
+ A_CLASS (b_parent_class)->method_to_call (obj, some_param);
+
+ /* do stuff after chain up */
+}
+```
+
+## How to define and implement interfaces
+
+### Defining interfaces
+
+The theory behind how GObject interfaces work is given in the section called
+["Non-instantiatable classed types:
+interfaces"](concepts.html#non-instantiatable-classed-types-interfaces);
+this section covers how to define and implement an interface.
+
+The first step is to get the header right. This interface defines three
+methods:
+
+```c
+/*
+ * Copyright/Licensing information.
+ */
+
+#pragma once
+
+#include
+
+G_BEGIN_DECLS
+
+#define VIEWER_TYPE_EDITABLE viewer_editable_get_type()
+G_DECLARE_INTERFACE (ViewerEditable, viewer_editable, VIEWER, EDITABLE, GObject)
+
+struct _ViewerEditableInterface
+{
+ GTypeInterface parent_iface;
+
+ void (*save) (ViewerEditable *self,
+ GError **error);
+ void (*undo) (ViewerEditable *self,
+ guint n_steps);
+ void (*redo) (ViewerEditable *self,
+ guint n_steps);
+};
+
+void viewer_editable_save (ViewerEditable *self,
+ GError **error);
+void viewer_editable_undo (ViewerEditable *self,
+ guint n_steps);
+void viewer_editable_redo (ViewerEditable *self,
+ guint n_steps);
+
+G_END_DECLS
+```
+
+This code is the same as the code for a normal GType which derives from a
+GObject except for a few details:
+
+- the `_GET_CLASS` function is called `_GET_IFACE` (and is defined by `G_DECLARE_INTERFACE`)
+- the instance type, `ViewerEditable`, is not fully defined: it is used merely as an abstract type which represents an instance of whatever object which implements the interface
+- the parent of the `ViewerEditableInterface` is `GTypeInterface`, not `GObjectClass`
+
+The implementation of the `ViewerEditable` type itself is trivial:
+
+- `G_DEFINE_INTERFACE` creates a `viewer_editable_get_type` function which registers the type in the type system. The third argument is used to define a prerequisite interface (which we'll talk about more later). Just pass 0 for this argument when an interface has no prerequisite
+- `viewer_editable_default_init` is expected to register the interface's signals if there are any (we will see a bit later how to use them)
+- the interface methods `viewer_editable_save`, `viewer_editable_undo` and `viewer_editable_redo` dereference the interface structure to access its associated interface function and call it
+
+```c
+G_DEFINE_INTERFACE (ViewerEditable, viewer_editable, G_TYPE_OBJECT)
+
+static void
+viewer_editable_default_init (ViewerEditableInterface *iface)
+{
+ /* add properties and signals to the interface here */
+}
+
+void
+viewer_editable_save (ViewerEditable *self,
+ GError **error)
+{
+ ViewerEditableInterface *iface;
+
+ g_return_if_fail (VIEWER_IS_EDITABLE (self));
+ g_return_if_fail (error == NULL || *error == NULL);
+
+ iface = VIEWER_EDITABLE_GET_IFACE (self);
+ g_return_if_fail (iface->save != NULL);
+ iface->save (self, error);
+}
+
+void
+viewer_editable_undo (ViewerEditable *self,
+ guint n_steps)
+{
+ ViewerEditableInterface *iface;
+
+ g_return_if_fail (VIEWER_IS_EDITABLE (self));
+
+ iface = VIEWER_EDITABLE_GET_IFACE (self);
+ g_return_if_fail (iface->undo != NULL);
+ iface->undo (self, n_steps);
+}
+
+void
+viewer_editable_redo (ViewerEditable *self,
+ guint n_steps)
+{
+ ViewerEditableInterface *iface;
+
+ g_return_if_fail (VIEWER_IS_EDITABLE (self));
+
+ iface = VIEWER_EDITABLE_GET_IFACE (self);
+ g_return_if_fail (iface->redo != NULL);
+ iface->redo (self, n_steps);
+}
+```
+
+### Implementing interfaces
+
+Once the interface is defined, implementing it is rather trivial.
+
+The first step is to define a normal final GObject class exactly as usual.
+
+The second step is to implement `ViewerFile` by defining it using
+`G_DEFINE_TYPE_WITH_CODE` and `G_IMPLEMENT_INTERFACE` instead of
+`G_DEFINE_TYPE`:
+
+```c
+static void viewer_file_editable_interface_init (ViewerEditableInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (ViewerFile, viewer_file, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE,
+ viewer_file_editable_interface_init))
+```
+
+This definition is very much like all the similar functions seen previously.
+The only interface-specific code present here is the use of
+`G_IMPLEMENT_INTERFACE`.
+
+Classes can implement multiple interfaces by using multiple calls to
+`G_IMPLEMENT_INTERFACE` inside the call to `G_DEFINE_TYPE_WITH_CODE`.
+
+`viewer_file_editable_interface_init` is the interface initialization
+function: inside it, every virtual method of the interface must be assigned
+to its implementation:
+
+```c
+static void
+viewer_file_editable_save (ViewerFile *self,
+ GError **error)
+{
+ g_print ("File implementation of editable interface save method: %s.\n",
+ self->filename);
+}
+
+static void
+viewer_file_editable_undo (ViewerFile *self,
+ guint n_steps)
+{
+ g_print ("File implementation of editable interface undo method: %s.\n",
+ self->filename);
+}
+
+static void
+viewer_file_editable_redo (ViewerFile *self,
+ guint n_steps)
+{
+ g_print ("File implementation of editable interface redo method: %s.\n",
+ self->filename);
+}
+
+static void
+viewer_file_editable_interface_init (ViewerEditableInterface *iface)
+{
+ iface->save = viewer_file_editable_save;
+ iface->undo = viewer_file_editable_undo;
+ iface->redo = viewer_file_editable_redo;
+}
+
+static void
+viewer_file_init (ViewerFile *self)
+{
+ /* Instance variable initialisation code. */
+}
+```
+
+If the object is not of final type, e.g. was declared using
+`G_DECLARE_DERIVABLE_TYPE` then `G_ADD_PRIVATE` macro should be added. The
+private structure should be declared exactly as for a normal derivable
+object.
+
+```c
+G_DEFINE_TYPE_WITH_CODE (ViewerFile, viewer_file, G_TYPE_OBJECT,
+ G_ADD_PRIVATE (ViewerFile)
+ G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE,
+ viewer_file_editable_interface_init))
+```
+
+### Interface definition prerequisites
+
+To specify that an interface requires the presence of other interfaces when
+implemented, GObject introduces the concept of prerequisites: it is possible
+to associate a list of prerequisite types to an interface. For example, if
+object A wishes to implement interface I1, and if interface I1 has a
+prerequisite on interface I2, A has to implement both I1 and I2.
+
+The mechanism described above is, in practice, very similar to Java's
+interface I1 extends interface I2. The example below shows the GObject
+equivalent:
+
+```
+/* Make the ViewerEditableLossy interface require ViewerEditable interface. */
+G_DEFINE_INTERFACE (ViewerEditableLossy, viewer_editable_lossy, VIEWER_TYPE_EDITABLE)
+```
+
+In the `G_DEFINE_INTERFACE` call above, the third parameter defines the
+prerequisite type. This is the GType of either an interface or a class. In
+this case the `ViewerEditable` interface is a prerequisite of
+`ViewerEditableLossy`. The code below shows how an implementation can
+implement both interfaces and register their implementations:
+
+```c
+static void
+viewer_file_editable_lossy_compress (ViewerEditableLossy *editable)
+{
+ ViewerFile *self = VIEWER_FILE (editable);
+
+ g_print ("File implementation of lossy editable interface compress method: %s.\n",
+ self->filename);
+}
+
+static void
+viewer_file_editable_lossy_interface_init (ViewerEditableLossyInterface *iface)
+{
+ iface->compress = viewer_file_editable_lossy_compress;
+}
+
+static void
+viewer_file_editable_save (ViewerEditable *editable,
+ GError **error)
+{
+ ViewerFile *self = VIEWER_FILE (editable);
+
+ g_print ("File implementation of editable interface save method: %s.\n",
+ self->filename);
+}
+
+static void
+viewer_file_editable_undo (ViewerEditable *editable,
+ guint n_steps)
+{
+ ViewerFile *self = VIEWER_FILE (editable);
+
+ g_print ("File implementation of editable interface undo method: %s.\n",
+ self->filename);
+}
+
+static void
+viewer_file_editable_redo (ViewerEditable *editable,
+ guint n_steps)
+{
+ ViewerFile *self = VIEWER_FILE (editable);
+
+ g_print ("File implementation of editable interface redo method: %s.\n",
+ self->filename);
+}
+
+static void
+viewer_file_editable_interface_init (ViewerEditableInterface *iface)
+{
+ iface->save = viewer_file_editable_save;
+ iface->undo = viewer_file_editable_undo;
+ iface->redo = viewer_file_editable_redo;
+}
+
+static void
+viewer_file_class_init (ViewerFileClass *klass)
+{
+ /* Nothing here. */
+}
+
+static void
+viewer_file_init (ViewerFile *self)
+{
+ /* Instance variable initialisation code. */
+}
+
+G_DEFINE_TYPE_WITH_CODE (ViewerFile, viewer_file, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE,
+ viewer_file_editable_interface_init)
+ G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE_LOSSY,
+ viewer_file_editable_lossy_interface_init))
+```
+
+It is very important to notice that the order in which interface
+implementations are added to the main object is not random:
+`g_type_add_interface_static()`, which is called by `G_IMPLEMENT_INTERFACE`, must
+be invoked first on the interfaces which have no prerequisites and then on
+the others.
+
+### Interface properties
+
+GObject interfaces can also have properties. Declaration of the interface
+properties is similar to declaring the properties of ordinary GObject types
+as explained in the section called ["Object
+properties"](concepts.html#object-properties), except that
+`g_object_interface_install_property()` is used to declare the properties
+instead of `g_object_class_install_property()`.
+
+To include a property named 'autosave-frequency' of type gdouble in the
+`ViewerEditable` interface example code above, we only need to add one call in
+`viewer_editable_default_init()` as shown below:
+
+```c
+static void
+viewer_editable_default_init (ViewerEditableInterface *iface)
+{
+ g_object_interface_install_property (iface,
+ g_param_spec_double ("autosave-frequency",
+ "Autosave frequency",
+ "Frequency (in per-seconds) to autosave backups of the editable content at. "
+ "Or zero to disable autosaves.",
+ 0.0, /* minimum */
+ G_MAXDOUBLE, /* maximum */
+ 0.0, /* default */
+ G_PARAM_READWRITE));
+}
+```
+
+One point worth noting is that the declared property wasn't assigned an
+integer ID. The reason being that integer IDs of properties are used only
+inside the `get_property` and `set_property` virtual methods. Since interfaces
+declare but do not implement properties, there is no need to assign integer
+IDs to them.
+
+An implementation declares and defines its properties in the usual way as
+explained in the section called “Object properties”, except for one small
+change: it can declare the properties of the interface it implements using
+`g_object_class_override_property()` instead of `g_object_class_install_property()`.
+The following code snippet shows the modifications needed in the `ViewerFile`
+declaration and implementation above:
+
+```c
+struct _ViewerFile
+{
+ GObject parent_instance;
+
+ double autosave_frequency;
+};
+
+enum
+{
+ PROP_AUTOSAVE_FREQUENCY = 1,
+ N_PROPERTIES
+};
+
+static void
+viewer_file_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ViewerFile *file = VIEWER_FILE (object);
+
+ switch (prop_id)
+ {
+ case PROP_AUTOSAVE_FREQUENCY:
+ file->autosave_frequency = g_value_get_double (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+viewer_file_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ViewerFile *file = VIEWER_FILE (object);
+
+ switch (prop_id)
+ {
+ case PROP_AUTOSAVE_FREQUENCY:
+ g_value_set_double (value, file->autosave_frequency);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_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;
+
+ g_object_class_override_property (object_class, PROP_AUTOSAVE_FREQUENCY, "autosave-frequency");
+}
+```
+
+### Overriding interface methods
+
+If a base class already implements an interface and a derived class needs to
+implement the same interface but needs to override certain methods, you must
+reimplement the interface and set only the interface methods which need
+overriding.
+
+In this example, `ViewerAudioFile` is derived from `ViewerFile`. Both implement
+the `ViewerEditable` interface. `ViewerAudioFile` only implements one method of
+the `ViewerEditable` interface and uses the base class implementation of the
+other.
+
+```c
+static void
+viewer_audio_file_editable_save (ViewerEditable *editable,
+ GError **error)
+{
+ ViewerAudioFile *self = VIEWER_AUDIO_FILE (editable);
+
+ g_print ("Audio file implementation of editable interface save method.\n");
+}
+
+static void
+viewer_audio_file_editable_interface_init (ViewerEditableInterface *iface)
+{
+ /* Override the implementation of save(). */
+ iface->save = viewer_audio_file_editable_save;
+
+ /*
+ * Leave iface->undo and ->redo alone, they are already set to the
+ * base class implementation.
+ */
+}
+
+G_DEFINE_TYPE_WITH_CODE (ViewerAudioFile, viewer_audio_file, VIEWER_TYPE_FILE,
+ G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE,
+ viewer_audio_file_editable_interface_init))
+
+static void
+viewer_audio_file_class_init (ViewerAudioFileClass *klass)
+{
+ /* Nothing here. */
+}
+
+static void
+viewer_audio_file_init (ViewerAudioFile *self)
+{
+ /* Nothing here. */
+}
+```
+
+To access the base class interface implementation use
+`g_type_interface_peek_parent()` from within an interface's `default_init`
+function.
+
+To call the base class implementation of an interface method from a derived
+class where than interface method has been overridden, stash away the
+pointer returned from `g_type_interface_peek_parent()` in a global variable.
+
+In this example `ViewerAudioFile` overrides the save interface method. In
+its overridden method it calls the base class implementation of the same
+interface method.
+
+```c
+static ViewerEditableInterface *viewer_editable_parent_interface = NULL;
+
+static void
+viewer_audio_file_editable_save (ViewerEditable *editable,
+ GError **error)
+{
+ ViewerAudioFile *self = VIEWER_AUDIO_FILE (editable);
+
+ g_print ("Audio file implementation of editable interface save method.\n");
+
+ /* Now call the base implementation */
+ viewer_editable_parent_interface->save (editable, error);
+}
+
+static void
+viewer_audio_file_editable_interface_init (ViewerEditableInterface *iface)
+{
+ viewer_editable_parent_interface = g_type_interface_peek_parent (iface);
+
+ iface->save = viewer_audio_file_editable_save;
+}
+
+G_DEFINE_TYPE_WITH_CODE (ViewerAudioFile, viewer_audio_file, VIEWER_TYPE_FILE,
+ G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE,
+ viewer_audio_file_editable_interface_init))
+
+static void
+viewer_audio_file_class_init (ViewerAudioFileClass *klass)
+{
+ /* Nothing here. */
+}
+
+static void
+viewer_audio_file_init (ViewerAudioFile *self)
+{
+ /* Nothing here. */
+}
+```
+
+## How to create and use signals
+
+The signal system in GType is pretty complex and flexible: it is possible
+for its users to connect at runtime any number of callbacks (implemented in
+any language for which a binding exists) to any signal and to stop the
+emission of any signal at any state of the signal emission process. This
+flexibility makes it possible to use GSignal for much more than just
+emitting signals to multiple clients.
+
+### Simple use of signals
+
+The most basic use of signals is to implement event notification. For
+example, given a `ViewerFile` object with a write method, a signal could be
+emitted whenever the file is changed using that method. The code below shows
+how the user can connect a callback to the "changed" signal.
+
+```c
+file = g_object_new (VIEWER_FILE_TYPE, NULL);
+
+g_signal_connect (file, "changed", (GCallback) changed_event, NULL);
+
+viewer_file_write (file, buffer, strlen (buffer));
+```
+
+The ViewerFile signal is registered in the `class_init` function:
+
+```c
+file_signals[CHANGED] =
+ g_signal_newv ("changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
+ NULL /* closure */,
+ NULL /* accumulator */,
+ NULL /* accumulator data */,
+ NULL /* C marshaller */,
+ G_TYPE_NONE /* return_type */,
+ 0 /* n_params */,
+ NULL /* param_types */);
+```
+
+and the signal is emitted in `viewer_file_write`:
+
+```c
+void
+viewer_file_write (ViewerFile *self,
+ const guint8 *buffer,
+ gsize size)
+{
+ g_return_if_fail (VIEWER_IS_FILE (self));
+ g_return_if_fail (buffer != NULL || size == 0);
+
+ /* First write data. */
+
+ /* Then, notify user of data written. */
+ g_signal_emit (self, file_signals[CHANGED], 0 /* details */);
+}
+```
+
+As shown above, the details parameter can safely be set to zero if no detail
+needs to be conveyed. For a discussion of what it can be used for, see the
+section called [“The detail argument”](concepts.html#the-detail-argument).
+
+The C signal marshaller should always be `NULL`, in which case the best
+marshaller for the given closure type will be chosen by GLib. This may be an
+internal marshaller specific to the closure type, or
+`g_cclosure_marshal_generic()`, which implements generic conversion of arrays of
+parameters to C callback invocations. GLib used to require the user to write
+or generate a type-specific marshaller and pass that, but that has been
+deprecated in favour of automatic selection of marshallers.
+
+Note that `g_cclosure_marshal_generic()` is slower than non-generic
+marshallers, so should be avoided for performance critical code. However,
+performance critical code should rarely be using signals anyway, as signals
+are synchronous, and the emission blocks until all listeners are invoked,
+which has potentially unbounded cost.