Implementing your own message view component

Inheriting an existing one

Inheriting is the preferred way if you are using gtk+. There is an excellent base type called TnyGtkMsgView that already implements a lot of the basics of a message viewer.

When inheriting you will typically override the tny_msg_view_create_mime_part_view_for method.

This example implements a TnyMsgView that will use a TnyMyMimePartView for "my/type" mime parts. For any other, it will use the standard TnyMimePartView type as supported by the TnyMsgView implementation TnyGtkMsgView.

The code for this (tny-my-msg-view.c)

Note that the file is split up in parts that you can typically copy-paste and search-n-replace and parts that you must implement.

copy-n-paste, search-n-replace

/* Your copyright here */

#include <config.h>
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>

#include <tny-my-msg-view.h>
#include <tny-my-mime-part-view.h>

static GObjectClass *parent_class = NULL;

tny_my_msg_view_new

This constructor must return a new instance

/**
 * tny_my_msg_view_new:
 *
 * Return value: a new #TnyMsgView instance
 **/
TnyMsgView*
tny_my_msg_view_new (void)
{
	TnyMyMsgView *self = g_object_new (TNY_TYPE_MY_MSG_VIEW, NULL);
	
	return TNY_MSG_VIEW (self);
}

tny_my_msg_view_create_mime_part_view_for

This method must return a new instance of a TnyMimePartView that can (and in a near future after the method returns, will) show the TnyMimePart part. It must not also set the part (this method must not perform the tny_mime_part_view_set_part on retval).

static TnyMimePartView*
tny_my_msg_view_create_mime_part_view_for (TnyMsgView *self, TnyMimePart *part)
{
	TnyMimePartView *retval = NULL;

	g_assert (TNY_IS_MIME_PART (part));

	if (tny_mime_part_content_type_is (part, "my/type"))
		retval = tny_my_mime_part_view_new ();
	else
		retval = TNY_GTK_MSG_VIEW_CLASS (parent_class)->create_mime_part_view_for_func (self, part);

	return retval;
}

tny_my_msg_view_create_new_inline_viewer

This method must return a new instance of the same type as self unless self is a window type. For example as explained here (the decorating TnyMsgView as a GtkWindow). In that case it's recommended to return a new instance of the same type as the decorated instance. The reason for that is because an inline viewer shows a message inside of a message. You typically don't want to create a new window for a message inside of another message.

Examples of such messages are RFC822 inline messages like Forwards (FWD: Subject) and inlined Replies (RE: Subject).

static TnyMsgView*
tny_my_msg_view_create_new_inline_viewer (TnyMsgView *self)
{
	return tny_my_msg_view_new ();
}

copy-n-paste, search-n-replace

static void
tny_my_msg_view_instance_init (GTypeInstance *instance, gpointer g_class)
{
	return;
}

static void
tny_my_msg_view_finalize (GObject *object)
{
	(*parent_class->finalize) (object);

	return;
}

static void 
tny_my_msg_view_class_init (TnyMyMsgViewClass *class)
{
	GObjectClass *object_class;

	parent_class = g_type_class_peek_parent (class);
	object_class = (GObjectClass*) class;
	object_class->finalize = tny_my_msg_view_finalize;

	TNY_GTK_MSG_VIEW_CLASS (class)->create_mime_part_view_for_func = tny_my_msg_view_create_mime_part_view_for;
	TNY_GTK_MSG_VIEW_CLASS (class)->create_new_inline_viewer_func = tny_my_msg_view_create_new_inline_viewer;

	return;
}

GType 
tny_my_msg_view_get_type (void)
{
	static GType type = 0;

	if (G_UNLIKELY(type == 0))
	{
		static const GTypeInfo info = 
		{
		  sizeof (TnyMyMsgViewClass),
		  NULL,   /* base_init */
		  NULL,   /* base_finalize */
		  (GClassInitFunc) tny_my_msg_view_class_init,
		  NULL,   /* class_finalize */
		  NULL,   /* class_data */
		  sizeof (TnyMyMsgView),
		  0,      /* n_preallocs */
		  tny_my_msg_view_instance_init
		};

		type = g_type_register_static (TNY_TYPE_GTK_MSG_VIEW,
			"TnyMyMsgView",
			&info, 0);
	}

	return type;
}

The public .h file (tny-my-msg-view.h)

#ifndef TNY_MY_MSG_VIEW_H
#define TNY_MY_MSG_VIEW_H

/* Your copyright here */

#include <my/my.h>
#include <glib-object.h>
#include <tny-shared.h>

#include <tny-gtk-msg-view.h>

G_BEGIN_DECLS

#define TNY_TYPE_MY_MSG_VIEW \ 
	(tny_my_msg_view_get_type ())
#define TNY_MY_MSG_VIEW(obj) \
	(G_TYPE_CHECK_INSTANCE_CAST ((obj), TNY_TYPE_MY_MSG_VIEW, TnyMyMsgView))
#define TNY_MY_MSG_VIEW_CLASS(vtable) \
	(G_TYPE_CHECK_CLASS_CAST ((vtable), TNY_TYPE_MY_MSG_VIEW, TnyMyMsgViewClass))
#define TNY_IS_MY_MSG_VIEW(obj) \
	(G_TYPE_CHECK_INSTANCE_TYPE ((obj), TNY_TYPE_MY_MSG_VIEW))
#define TNY_IS_MY_MSG_VIEW_CLASS(vtable) \
	(G_TYPE_CHECK_CLASS_TYPE ((vtable), TNY_TYPE_MY_MSG_VIEW))
#define TNY_MY_MSG_VIEW_GET_CLASS(inst) \
	(G_TYPE_INSTANCE_GET_CLASS ((inst), TNY_TYPE_MY_MSG_VIEW, TnyMyMsgViewClass))

typedef struct _TnyMyMsgView TnyMyMsgView;
typedef struct _TnyMyMsgViewClass TnyMyMsgViewClass;

struct _TnyMyMsgView
{
	TnyGtkMsgView parent;
};

struct _TnyMyMsgViewClass
{
	TnyGtkMsgViewClass parent_class;
};

GType tny_my_msg_view_get_type (void);
TnyMsgView* tny_my_msg_view_new (void);

G_END_DECLS

#endif

References to related other documentation

TODO for this documentation document

  • Linking API with the online API documentation