How to define and implement a new GObject

Boilerplate header code
Boilerplate code
Object construction
Object destruction
Object methods
Non-virtual public methods
Virtual public methods
Virtual private Methods
Chaining up

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.

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: maman-bar.h and maman-bar.c (this is the convention used by Nautilus and most GNOME libraries).

  • use an underscore to separate the prefix from the typename: maman_bar.h and maman_bar.c.

  • Do not separate the prefix from the typename: mamanbar.h and mamanbar.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 called “Conventions”.

If you want to declare a type named ‘bar’ in namespace ‘maman’, name the type instance MamanBar and its class MamanBarClass (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).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*
 * Copyright/Licensing information.
 */

/* inclusion guard */
#ifndef __MAMAN_BAR_H__
#define __MAMAN_BAR_H__

#include <glib-object.h>
/*
 * Potentially, include other headers on which this header depends.
 */

G_BEGIN_DECLS

/*
 * Type declaration.
 */
#define MAMAN_TYPE_BAR maman_bar_get_type ()
G_DECLARE_FINAL_TYPE (MamanBar, maman_bar, MAMAN, BAR, GObject)

/*
 * Method definitions.
 */
MamanBar *maman_bar_new (void);

G_END_DECLS

#endif /* __MAMAN_BAR_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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/*
 * Copyright/Licensing information.
 */

/* inclusion guard */
#ifndef __MAMAN_BAR_H__
#define __MAMAN_BAR_H__

#include <glib-object.h>
/*
 * Potentially, include other headers on which this header depends.
 */

G_BEGIN_DECLS

/*
 * Type declaration.
 */
#define MAMAN_TYPE_BAR maman_bar_get_type ()
G_DECLARE_DERIVABLE_TYPE (MamanBar, maman_bar, MAMAN, BAR, GObject)

struct _MamanBarClass
{
  GObjectClass parent_class;

  /* Class virtual function fields. */
  void (* handle_frob)  (MamanBar *bar,
                         guint     n_frobs);

  /* Padding to allow adding up to 12 new virtual functions without
   * breaking ABI. */
  gpointer padding[12];
};

/*
 * Method definitions.
 */
MamanBar *maman_bar_new (void);

G_END_DECLS

#endif /* __MAMAN_BAR_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 "maman-bar.h", without needing to know the prerequisites for maman-bar.h.