## 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:

    1
    2
    /* 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:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    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.