How to implement a type
About
This document describes how to implement a type using an interface defined in the Tinymail framework. This documentation is useful for both application developers and people who are planning to contribute to the Tinymail framework itself.
The following websites and manuals describe the GObject type system in depth:
You can use all of the information that you can find in those three documents in the Tinymail framework too. Tinymail is, indeed, GObject based.
Check out how to add a type in case you are adding a type to the Tinymail framework.
By example
We will assume that we are going to implement a TnyType interface which requires that you implement a method called "get_something". In our libtinymail we'll find a tny-type.h that would have a TnyTypeIface class/iface structure that looks like this:
typedef struct _TnyTypeIface TnyTypeIface;
struct _TnyTypeIface
{
GTypeInterface parent;
TnySomething * (*get_something_func) (TnyType *self);
};
GType tny_type_get_type (void);
TnySomething* tny_type_get_something (TnyType *self);
Create a tny-detail-type.c in the right libtinymail-detail library directory
You can use a little tool which you can find in the tools directory of the tinymail framework for this.
cd tool/ ./gtypeinterface-h-files-to-c-file.pl TnyDetailType ../libtinymail/tny-type.h
The tool will on standard out dump a skeleton with stubs of the methods that must be implemented of the .c file. You can for example redirect the standard output of the tool to a file in your shell. Or you can copy and paste from it.
#include <config.h>
#include <glib/gi18n-lib.h>
#include <tny-detail-type.h>
static GObjectClass *parent_class = NULL;
#include "tny-detail-type-priv.h"
#define TNY_DETAIL_TYPE_GET_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), TNY_TYPE_DETAIL_TYPE, TnyDetailTypePriv))
TnySomething*
tny_detail_type_get_something (TnyDetailType *self)
{
TnyDetailTypePriv *priv = TNY_DETAIL_TYPE_GET_PRIVATE (self);
TnySomething *retval;
g_mutex_lock (priv->folder_lock);
retval = priv->something;
g_object_ref (G_OBJECT (retval));
g_mutex_unlock (priv->folder_lock);
return retval;
}
static void
tny_detail_type_finalize (GObject *object)
{
TnyDetailType *self = (TnyDetailType*) object;
TnyDetailTypePriv *priv = TNY_DETAIL_TYPE_GET_PRIVATE (self);
/* Free resources here */
/* It's possible (very likely) that you need to unref priv->something here! */
(*parent_class->finalize) (object);
return;
}
/**
* tny_detail_type_new:
*
* Create a new #TnyType instance
*
* Return value: A new #TnyType instance implemented for Detail
**/
TnyType*
tny_detail_type_new (void)
{
TnyDetailType *self = g_object_new (TNY_TYPE_DETAIL_TYPE, NULL);
return TNY_TYPE (self);
}
static void
tny_type_init (gpointer g, gpointer iface_data)
{
TnyTypeIface *klass = (TnyTypeIface *)g;
klass->get_something_func = tny_detail_type_get_something;
return;
}
static void
tny_detail_type_class_init (TnyDetailTypeClass *class)
{
GObjectClass *object_class;
parent_class = g_type_class_peek_parent (class);
object_class = (GObjectClass*) class;
object_class->finalize = tny_detail_type_finalize;
g_type_class_add_private (object_class, sizeof (TnyDetailTypePriv));
return;
}
static void
tny_detail_type_instance_init (GTypeInstance *instance, gpointer g_class)
{
TnyDetailType *self = (TnyDetailType*)instance;
TnyDetailTypePriv *priv = TNY_DETAIL_TYPE_GET_PRIVATE (self);
/* Initialize resources */
return;
}
GType
tny_detail_type_get_type (void)
{
static GType type = 0;
if (G_UNLIKELY(type == 0))
{
static const GTypeInfo info =
{
sizeof (TnyDetailTypeClass),
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) tny_detail_type_class_init, /* class_init */
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (TnyDetailType),
0, /* n_preallocs */
tny_detail_type_instance_init, /* instance_init */
NULL
};
static const GInterfaceInfo tny_type_info =
{
(GInterfaceInitFunc) tny_type_init, /* interface_init */
NULL, /* interface_finalize */
NULL /* interface_data */
};
type = g_type_register_static (G_TYPE_OBJECT,
"TnyDetailType",
&info, 0);
g_type_add_interface_static (type, TNY_TYPE_TYPE,
&tny_type_info);
}
return type;
}
Create a tny-detail-type-priv.h in the right libtinymail-detail library directory
#ifndef TNY_DETAIL_TYPE_PRIV_H
#define TNY_DETAIL_TYPE_PRIV_H
typedef struct _TnyDetailTypePriv TnyDetailTypePriv;
struct _TnyDetailTypePriv
{
TnySomething *something;
};
#endif
Create a tny-detail-type.h file in the right libtinymail-detail library directory
#ifndef TNY_DETAIL_TYPE_H
#define TNY_DETAIL_TYPE_H
#include <glib.h>
#include <glib-object.h>
#include <tny-type.h>
G_BEGIN_DECLS
#define TNY_TYPE_DETAIL_TYPE (tny_detail_type_get_type ())
#define TNY_DETAIL_TYPE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TNY_TYPE_DETAIL_TYPE, TnyDetailType))
#define TNY_DETAIL_TYPE_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), TNY_TYPE_DETAIL_TYPE, TnyDetailTypeClass))
#define TNY_IS_DETAIL_TYPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TNY_TYPE_DETAIL_TYPE))
#define TNY_IS_DETAIL_TYPE_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), TNY_TYPE_DETAIL_TYPE))
#define TNY_DETAIL_TYPE_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), TNY_TYPE_DETAIL_TYPE, TnyDetailTypeClass))
typedef struct _TnyDetailType TnyDetailType;
typedef struct _TnyDetailTypeClass TnyDetailTypeClass;
struct _TnyDetailType
{
GObject parent;
};
struct _TnyDetailTypeClass
{
GObjectClass parent;
};
GType tny_detail_type_get_type (void);
G_END_DECLS
#endif
Adapt the Makefile.am of libtinymail-detail
libtinymail_detail_1_0_headers = \
+ tny-detail-type.h \
tny-detail-mime-part.h \
tny-detail-header.h \
...
libtinymail_detail_1_0_la_SOURCES = \
+ tny-detail-type-priv.h \
+ tny-detail-type.c \
tny-detail-common.c \
tny-detail-common-priv.h \
...
