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
