[gnome-keyring/ui-widgets: 47/49] [gcr] Rework the architecture of viewers.



commit 22f5fee4f2da40eecf296038b5edf2b420e20b37
Author: Stef Walter <stef memberwebs com>
Date:   Mon Aug 30 13:45:41 2010 +0000

    [gcr] Rework the architecture of viewers.
    
     * GcrRenderer renders data like a certificate.
     * GcrViewer is what the renderers render to.
     * GcrXxxWidget are helper classes for quick instatiation.

 gcr/Makefile.am                    |   12 +-
 gcr/gcr-certificate-renderer.c     |  540 +++++++++++++++++++++++++++++++++
 gcr/gcr-certificate-renderer.h     |   67 ++++
 gcr/gcr-certificate-widget.c       |  395 +++----------------------
 gcr/gcr-certificate-widget.h       |    9 +-
 gcr/gcr-display-view.c             |  585 ++++++++++++++++++++++++++----------
 gcr/gcr-display-view.h             |   13 +-
 gcr/gcr-key-renderer.c             |  342 +++++++++++++++++++++
 gcr/gcr-key-renderer.h             |   62 ++++
 gcr/gcr-key-widget.c               |  239 +++------------
 gcr/gcr-key-widget.h               |    6 +-
 gcr/{gcr-view.c => gcr-renderer.c} |   87 ++++--
 gcr/gcr-renderer.h                 |   73 +++++
 gcr/gcr-view.h                     |   53 ----
 gcr/gcr-viewer.c                   |   99 ++++++
 gcr/gcr-viewer.h                   |   73 +++++
 gcr/tests/ui-test-certificate.c    |    1 -
 gcr/tests/ui-test-key.c            |    3 +-
 18 files changed, 1849 insertions(+), 810 deletions(-)
---
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index e9b55eb..86b0891 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -17,13 +17,16 @@ incdir = $(includedir)/gcr
 inc_HEADERS = \
 	gcr.h \
 	gcr-certificate.h \
+	gcr-certificate-renderer.h \
 	gcr-certificate-widget.h \
+	gcr-key-renderer.h \
 	gcr-key-widget.h \
 	gcr-importer.h \
 	gcr-parser.h \
+	gcr-renderer.h \
 	gcr-types.h \
 	gcr-unlock-options-widget.h \
-	gcr-view.h
+	gcr-viewer.h
 
 # ------------------------------------------------------------------
 # LIBRARY
@@ -44,19 +47,22 @@ lib_LTLIBRARIES = libgcr.la
 
 libgcr_la_SOURCES = \
 	gcr-certificate.c gcr-certificate.h \
+	gcr-certificate-renderer.c gcr-certificate-renderer.h \
 	gcr-certificate-widget.c gcr-certificate-widget.h \
-	gcr-key-widget.c gcr-key-widget.h \
 	gcr-display-view.c gcr-display-view.h \
 	gcr-icons.c gcr-icons.h \
 	gcr-import-dialog.c gcr-import-dialog.h \
 	gcr-importer.c gcr-importer.h  \
 	gcr-internal.h \
+	gcr-key-renderer.c gcr-key-renderer.h \
+	gcr-key-widget.c gcr-key-widget.h \
 	gcr-library.c \
 	gcr-parser.c gcr-parser.h \
+	gcr-renderer.c gcr-renderer.h \
 	gcr-simple-certificate.c gcr-simple-certificate.h \
 	gcr-types.h \
 	gcr-unlock-options-widget.c gcr-unlock-options-widget.h \
-	gcr-view.c gcr-view.h \
+	gcr-viewer.c gcr-viewer.h \
 	$(BUILT_SOURCES)
 
 libgcr_la_CFLAGS = \
diff --git a/gcr/gcr-certificate-renderer.c b/gcr/gcr-certificate-renderer.c
new file mode 100644
index 0000000..a0432ae
--- /dev/null
+++ b/gcr/gcr-certificate-renderer.c
@@ -0,0 +1,540 @@
+/*
+ * Copyright (C) 2010 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gcr-certificate.h"
+#include "gcr-certificate-renderer.h"
+#include "gcr-display-view.h"
+#include "gcr-icons.h"
+#include "gcr-simple-certificate.h"
+#include "gcr-renderer.h"
+
+#include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
+#include "egg/egg-dn.h"
+#include "egg/egg-oid.h"
+#include "egg/egg-hex.h"
+
+#include "gck/gck.h"
+
+#include <gdk/gdk.h>
+#include <glib/gi18n-lib.h>
+
+enum {
+	PROP_0,
+	PROP_CERTIFICATE,
+	PROP_LABEL,
+	PROP_ATTRIBUTES
+};
+
+struct _GcrCertificateRendererPrivate {
+	GcrCertificate *certificate;
+	GckAttributes *attributes;
+	guint key_size;
+	gchar *label;
+};
+
+static void gcr_renderer_iface_init (GcrRendererIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GcrCertificateRenderer, gcr_certificate_renderer, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (GCR_TYPE_RENDERER, gcr_renderer_iface_init));
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static gchar*
+calculate_label (GcrCertificateRenderer *self, GNode *asn)
+{
+	gchar *label;
+
+	if (self->pv->label)
+		return g_strdup (self->pv->label);
+
+	if (self->pv->attributes) {
+		if (gck_attributes_find_string (self->pv->attributes, CKA_LABEL, &label))
+			return label;
+	}
+
+	if (asn != NULL) {
+		label = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL), "CN");
+		if (label != NULL)
+			return label;
+	}
+
+	return g_strdup (_("Certificate"));
+}
+
+static gboolean
+append_extension (GcrCertificateRenderer *self, GcrDisplayView *view,
+                  GNode *asn, const guchar *data, gsize n_data, gint index)
+{
+	GcrRenderer *renderer = GCR_RENDERER (self);
+	GNode *node;
+	GQuark oid;
+	gchar *display;
+	gsize n_value;
+	const guchar *value;
+	const gchar *text;
+	gboolean critical;
+
+	/* Make sure it is present */
+	node = egg_asn1x_node (asn, "tbsCertificate", "extensions", index, NULL);
+	if (node == NULL)
+		return FALSE;
+
+	/* Dig out the OID */
+	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "extnID", NULL));
+	g_return_val_if_fail (oid, FALSE);
+
+	_gcr_display_view_append_heading (view, renderer, _("Extension"));
+
+
+	/* Extension type */
+	text = egg_oid_get_description (oid);
+	_gcr_display_view_append_value (view, renderer, _("Identifier"), text, FALSE);
+
+
+	/* Extension value */
+	value = egg_asn1x_get_raw_value (egg_asn1x_node (node, "extnValue", NULL), &n_value);
+
+	/* TODO: Parsing of extensions that we understand */
+	display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
+	_gcr_display_view_append_value (view, renderer, _("Value"), display, TRUE);
+	g_free (display);
+
+
+	/* Critical */
+	if (egg_asn1x_get_boolean (egg_asn1x_node (node, "critical", NULL), &critical))
+		_gcr_display_view_append_value (view, renderer, _("Critical"), critical ? _("Yes") : _("No"), FALSE);
+
+	return TRUE;
+}
+
+typedef struct _on_parsed_dn_args {
+	GcrCertificateRenderer *renderer;
+	GcrDisplayView *view;
+} on_parsed_dn_args;
+
+static void
+on_parsed_dn_part (guint index, GQuark oid, const guchar *value,
+                   gsize n_value, gpointer user_data)
+{
+	GcrCertificateRenderer *self = ((on_parsed_dn_args*)user_data)->renderer;
+	GcrDisplayView *view = ((on_parsed_dn_args*)user_data)->view;
+	const gchar *attr;
+	const gchar *desc;
+	gchar *field;
+	gchar *display;
+
+	g_return_if_fail (GCR_IS_CERTIFICATE_RENDERER (self));
+
+	attr = egg_oid_get_name (oid);
+	desc = egg_oid_get_description (oid);
+
+	/* Combine them into something sane */
+	if (attr && desc) {
+		if (strcmp (attr, desc) == 0)
+			field = g_strdup (attr);
+		else
+			field = g_strdup_printf ("%s (%s)", attr, desc);
+	} else if (!attr && !desc) {
+		field = g_strdup ("");
+	} else if (attr) {
+		field = g_strdup (attr);
+	} else if (desc) {
+		field = g_strdup (desc);
+	} else {
+		g_assert_not_reached ();
+	}
+
+	display = egg_dn_print_value (oid, value, n_value);
+	if (display == NULL)
+		display = g_strdup ("");
+
+	_gcr_display_view_append_value (view, GCR_RENDERER (self), field, display, FALSE);
+	g_free (field);
+	g_free (display);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static void
+gcr_certificate_renderer_init (GcrCertificateRenderer *self)
+{
+	self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_CERTIFICATE_RENDERER, GcrCertificateRendererPrivate));
+}
+
+static void
+gcr_certificate_renderer_dispose (GObject *obj)
+{
+	GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj);
+
+	if (self->pv->certificate)
+		g_object_unref (self->pv->certificate);
+	self->pv->certificate = NULL;
+
+	G_OBJECT_CLASS (gcr_certificate_renderer_parent_class)->dispose (obj);
+}
+
+static void
+gcr_certificate_renderer_finalize (GObject *obj)
+{
+	GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj);
+
+	g_assert (!self->pv->certificate);
+
+	if (self->pv->attributes)
+		gck_attributes_unref (self->pv->attributes);
+	self->pv->attributes = NULL;
+
+	g_free (self->pv->label);
+	self->pv->label = NULL;
+
+	G_OBJECT_CLASS (gcr_certificate_renderer_parent_class)->finalize (obj);
+}
+
+static void
+gcr_certificate_renderer_set_property (GObject *obj, guint prop_id, const GValue *value,
+                                     GParamSpec *pspec)
+{
+	GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj);
+
+	switch (prop_id) {
+	case PROP_CERTIFICATE:
+		gcr_certificate_renderer_set_certificate (self, g_value_get_object (value));
+		break;
+	case PROP_LABEL:
+		g_free (self->pv->label);
+		self->pv->label = g_value_dup_string (value);
+		g_object_notify (obj, "label");
+		gcr_renderer_emit_data_changed (GCR_RENDERER (self));
+		break;
+	case PROP_ATTRIBUTES:
+		gcr_certificate_renderer_set_attributes (self, g_value_get_boxed (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gcr_certificate_renderer_get_property (GObject *obj, guint prop_id, GValue *value,
+                                     GParamSpec *pspec)
+{
+	GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj);
+
+	switch (prop_id) {
+	case PROP_CERTIFICATE:
+		g_value_set_object (value, self->pv->certificate);
+		break;
+	case PROP_LABEL:
+		g_value_take_string (value, calculate_label (self, NULL));
+		break;
+	case PROP_ATTRIBUTES:
+		g_value_set_boxed (value, self->pv->attributes);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gcr_certificate_renderer_class_init (GcrCertificateRendererClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckAttributes *registered;
+
+	gcr_certificate_renderer_parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (GcrCertificateRendererPrivate));
+
+	gobject_class->dispose = gcr_certificate_renderer_dispose;
+	gobject_class->finalize = gcr_certificate_renderer_finalize;
+	gobject_class->set_property = gcr_certificate_renderer_set_property;
+	gobject_class->get_property = gcr_certificate_renderer_get_property;
+
+	g_object_class_install_property (gobject_class, PROP_CERTIFICATE,
+	           g_param_spec_object("certificate", "Certificate", "Certificate to display.",
+	                               GCR_TYPE_CERTIFICATE, G_PARAM_READWRITE));
+
+	g_object_class_override_property (gobject_class, PROP_LABEL, "label");
+	g_object_class_override_property (gobject_class, PROP_ATTRIBUTES, "attributes");
+
+	_gcr_icons_register ();
+
+	/* Register this as a renderer which can be loaded */
+	registered = gck_attributes_new ();
+	gck_attributes_add_ulong (registered, CKA_CLASS, CKO_CERTIFICATE);
+	gcr_renderer_register (GCR_TYPE_CERTIFICATE_RENDERER, registered);
+	gck_attributes_unref (registered);
+}
+
+static void
+gcr_certificate_renderer_real_render (GcrRenderer *renderer, GcrViewer *viewer)
+{
+	GcrCertificateRenderer *self;
+	const guchar *data, *value;
+	gsize n_data, n_value, n_raw;
+	GcrDisplayView *view;
+	on_parsed_dn_args args;
+	const gchar *text;
+	gpointer raw;
+	gulong version;
+	guint bits, index;
+	gchar *display;
+	GNode *asn;
+	GQuark oid;
+	GDate date;
+
+	self = GCR_CERTIFICATE_RENDERER (renderer);
+
+	if (GCR_IS_DISPLAY_VIEW (viewer)) {
+		view = GCR_DISPLAY_VIEW (viewer);
+
+	} else {
+		g_warning ("GcrCertificateRenderer only works with internal specific "
+		           "GcrViewer returned by gcr_viewer_new().");
+		return;
+	}
+
+	_gcr_display_view_clear (view, renderer);
+
+	if (!self->pv->certificate)
+		return;
+
+	_gcr_display_view_set_stock_image (view, GCR_RENDERER (self), GCR_ICON_CERTIFICATE);
+
+	data = gcr_certificate_get_der_data (self->pv->certificate, &n_data);
+	g_return_if_fail (data);
+
+	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data, n_data);
+	g_return_if_fail (asn);
+
+	display = calculate_label (self, asn);
+	_gcr_display_view_append_title (view, renderer, display);
+	g_free (display);
+
+	display = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL), "CN");
+	_gcr_display_view_append_content (view, renderer, _("Identity"), display);
+	g_free (display);
+
+	display = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL), "CN");
+	_gcr_display_view_append_content (view, renderer, _("Verified by"), display);
+	g_free (display);
+
+	if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notAfter", NULL), &date)) {
+		display = g_malloc0 (128);
+		if (!g_date_strftime (display, 128, "%x", &date))
+			g_return_if_reached ();
+		_gcr_display_view_append_content (view, renderer, _("Expires"), display);
+		g_free (display);
+	}
+
+	_gcr_display_view_start_details (view, renderer);
+
+	args.renderer = self;
+	args.view = view;
+
+	/* The subject */
+	_gcr_display_view_append_heading (view, renderer, _("Subject Name"));
+	egg_dn_parse (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL), on_parsed_dn_part, &args);
+
+	/* The Issuer */
+	_gcr_display_view_append_heading (view, renderer, _("Issuer Name"));
+	egg_dn_parse (egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL), on_parsed_dn_part, &args);
+
+	/* The Issued Parameters */
+	_gcr_display_view_append_heading (view, renderer, _("Issued Certificate"));
+
+	if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "tbsCertificate", "version", NULL), &version))
+		g_return_if_reached ();
+	display = g_strdup_printf ("%lu", version + 1);
+	_gcr_display_view_append_value (view, renderer, _("Version"), display, FALSE);
+	g_free (display);
+
+	raw = egg_asn1x_get_integer_as_raw (egg_asn1x_node (asn, "tbsCertificate", "serialNumber", NULL), NULL, &n_raw);
+	g_return_if_fail (raw);
+	display = egg_hex_encode_full (raw, n_raw, TRUE, ' ', 1);
+	_gcr_display_view_append_value (view, renderer, _("Serial Number"), display, TRUE);
+	g_free (display);
+	g_free (raw);
+
+	display = g_malloc0 (128);
+	if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notBefore", NULL), &date)) {
+		if (!g_date_strftime (display, 128, "%Y-%m-%d", &date))
+			g_return_if_reached ();
+		_gcr_display_view_append_value (view, renderer, _("Not Valid Before"), display, FALSE);
+	}
+	if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notAfter", NULL), &date)) {
+		if (!g_date_strftime (display, 128, "%Y-%m-%d", &date))
+			g_return_if_reached ();
+		_gcr_display_view_append_value (view, renderer, _("Not Valid After"), display, FALSE);
+	}
+	g_free (display);
+
+	/* Signature */
+	_gcr_display_view_append_heading (view, renderer, ("Signature"));
+
+	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "signatureAlgorithm", "algorithm", NULL));
+	text = egg_oid_get_description (oid);
+	_gcr_display_view_append_value (view, renderer, _("Signature Algorithm"), text, FALSE);
+
+	value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "signatureAlgorithm", "parameters", NULL), &n_value);
+	if (value && n_value) {
+		display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
+		_gcr_display_view_append_value (view, renderer, _("Signature Parameters"), display, TRUE);
+		g_free (display);
+	}
+
+	raw = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "signature", NULL), NULL, &bits);
+	g_return_if_fail (raw);
+	display = egg_hex_encode_full (raw, bits / 8, TRUE, ' ', 1);
+	_gcr_display_view_append_value (view, renderer, _("Signature"), display, TRUE);
+	g_free (display);
+	g_free (raw);
+
+	/* Public Key Info */
+	_gcr_display_view_append_heading (view, renderer, _("Public Key Info"));
+
+	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo",
+	                                                  "algorithm", "algorithm", NULL));
+	text = egg_oid_get_description (oid);
+	_gcr_display_view_append_value (view, renderer, _("Key Algorithm"), text, FALSE);
+
+	value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo",
+	                                                   "algorithm", "parameters", NULL), &n_value);
+	if (value && n_value) {
+		display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
+		_gcr_display_view_append_value (view, renderer, _("Key Parameters"), display, TRUE);
+		g_free (display);
+	}
+
+	bits = gcr_certificate_get_key_size (self->pv->certificate);
+	if (bits > 0) {
+		display = g_strdup_printf ("%u", bits);
+		_gcr_display_view_append_value (view, renderer, _("Key Size"), display, FALSE);
+		g_free (display);
+	}
+
+	raw = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo",
+	                                                 "subjectPublicKey", NULL), NULL, &bits);
+	g_return_if_fail (raw);
+	display = egg_hex_encode_full (raw, bits / 8, TRUE, ' ', 1);
+	_gcr_display_view_append_value (view, renderer, _("Public Key"), display, TRUE);
+	g_free (display);
+	g_free (raw);
+
+	/* Fingerprints */
+	_gcr_display_view_append_heading (view, renderer, _("Fingerprints"));
+
+	_gcr_display_view_append_fingerprint (view, renderer, data, n_data, "SHA1", G_CHECKSUM_SHA1);
+	_gcr_display_view_append_fingerprint (view, renderer, data, n_data, "MD5", G_CHECKSUM_MD5);
+
+	/* Extensions */
+	for (index = 1; TRUE; ++index) {
+		if (!append_extension (self, view, asn, data, n_data, index))
+			break;
+	}
+
+	egg_asn1x_destroy (asn);
+}
+
+static void
+gcr_renderer_iface_init (GcrRendererIface *iface)
+{
+	iface->render = gcr_certificate_renderer_real_render;
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+GcrCertificateRenderer*
+gcr_certificate_renderer_new (GcrCertificate *certificate)
+{
+	return g_object_new (GCR_TYPE_CERTIFICATE_RENDERER, "certificate", certificate, NULL);
+}
+
+GcrCertificate*
+gcr_certificate_renderer_get_certificate (GcrCertificateRenderer *self)
+{
+	g_return_val_if_fail (GCR_IS_CERTIFICATE_RENDERER (self), NULL);
+	return self->pv->certificate;
+}
+
+void
+gcr_certificate_renderer_set_certificate (GcrCertificateRenderer *self, GcrCertificate *cert)
+{
+	g_return_if_fail (GCR_IS_CERTIFICATE_RENDERER (self));
+
+	if (self->pv->certificate)
+		g_object_unref (self->pv->certificate);
+	self->pv->certificate = cert;
+	if (self->pv->certificate)
+		g_object_ref (self->pv->certificate);
+
+	gcr_renderer_emit_data_changed (GCR_RENDERER (self));
+	g_object_notify (G_OBJECT (self), "certificate");
+}
+
+GckAttributes*
+gcr_certificate_renderer_get_attributes (GcrCertificateRenderer *self)
+{
+	g_return_val_if_fail (GCR_IS_CERTIFICATE_RENDERER (self), NULL);
+	return self->pv->attributes;
+}
+
+void
+gcr_certificate_renderer_set_attributes (GcrCertificateRenderer *self, GckAttributes *attrs)
+{
+	GcrCertificate *cert;
+	GckAttribute *attr;
+	gboolean emit = TRUE;
+
+	g_return_if_fail (GCR_IS_CERTIFICATE_RENDERER (self));
+
+	gck_attributes_unref (self->pv->attributes);
+	self->pv->attributes = attrs;\
+
+	if (self->pv->attributes) {
+		gck_attributes_ref (self->pv->attributes);
+		attr = gck_attributes_find (self->pv->attributes, CKA_VALUE);
+		if (attr) {
+			/* Create a new certificate object refferring to same memory */
+			cert = gcr_simple_certificate_new_static (attr->value, attr->length);
+			g_object_set_data_full (G_OBJECT (cert), "attributes",
+			                        gck_attributes_ref (self->pv->attributes),
+			                        (GDestroyNotify)gck_attributes_unref);
+			gcr_certificate_renderer_set_certificate (self, cert);
+			g_object_unref (cert);
+			emit = FALSE;
+		} else {
+			gcr_certificate_renderer_set_certificate (self, NULL);
+		}
+	}
+
+	if (emit)
+		gcr_renderer_emit_data_changed (GCR_RENDERER (self));
+
+}
diff --git a/gcr/gcr-certificate-renderer.h b/gcr/gcr-certificate-renderer.h
new file mode 100644
index 0000000..685c04e
--- /dev/null
+++ b/gcr/gcr-certificate-renderer.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GCR_CERTIFICATE_RENDERER_H__
+#define __GCR_CERTIFICATE_RENDERER_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gcr-certificate.h"
+#include "gcr-types.h"
+
+G_BEGIN_DECLS
+
+#define GCR_TYPE_CERTIFICATE_RENDERER               (gcr_certificate_renderer_get_type ())
+#define GCR_CERTIFICATE_RENDERER(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_CERTIFICATE_RENDERER, GcrCertificateRenderer))
+#define GCR_CERTIFICATE_RENDERER_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_CERTIFICATE_RENDERER, GcrCertificateRendererClass))
+#define GCR_IS_CERTIFICATE_RENDERER(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_CERTIFICATE_RENDERER))
+#define GCR_IS_CERTIFICATE_RENDERER_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_CERTIFICATE_RENDERER))
+#define GCR_CERTIFICATE_RENDERER_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_CERTIFICATE_RENDERER, GcrCertificateRendererClass))
+
+typedef struct _GcrCertificateRenderer GcrCertificateRenderer;
+typedef struct _GcrCertificateRendererClass GcrCertificateRendererClass;
+typedef struct _GcrCertificateRendererPrivate GcrCertificateRendererPrivate;
+
+struct _GcrCertificateRenderer {
+	GObject parent;
+	GcrCertificateRendererPrivate *pv;
+};
+
+struct _GcrCertificateRendererClass {
+	GObjectClass parent_class;
+};
+
+GType                     gcr_certificate_renderer_get_type           (void);
+
+GcrCertificateRenderer*   gcr_certificate_renderer_new                (GcrCertificate *cert);
+
+GcrCertificate*           gcr_certificate_renderer_get_certificate    (GcrCertificateRenderer *self);
+
+void                      gcr_certificate_renderer_set_certificate    (GcrCertificateRenderer *self,
+                                                                       GcrCertificate *cert);
+
+struct _GckAttributes*    gcr_certificate_renderer_get_attributes     (GcrCertificateRenderer *self);
+
+void                      gcr_certificate_renderer_set_attributes     (GcrCertificateRenderer *self,
+                                                                       struct _GckAttributes *attrs);
+
+G_END_DECLS
+
+#endif /* __GCR_CERTIFICATE_RENDERER_H__ */
diff --git a/gcr/gcr-certificate-widget.c b/gcr/gcr-certificate-widget.c
index f1ee235..8e61063 100644
--- a/gcr/gcr-certificate-widget.c
+++ b/gcr/gcr-certificate-widget.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Stefan Walter
+ * Copyright (C) 2010 Stefan Walter
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as
@@ -20,17 +20,10 @@
 #include "config.h"
 
 #include "gcr-certificate.h"
+#include "gcr-certificate-renderer.h"
 #include "gcr-certificate-widget.h"
-#include "gcr-display-view.h"
-#include "gcr-icons.h"
-#include "gcr-simple-certificate.h"
-#include "gcr-view.h"
-
-#include "egg/egg-asn1x.h"
-#include "egg/egg-asn1-defs.h"
-#include "egg/egg-dn.h"
-#include "egg/egg-oid.h"
-#include "egg/egg-hex.h"
+#include "gcr-renderer.h"
+#include "gcr-viewer.h"
 
 #include "gck/gck.h"
 
@@ -40,287 +33,15 @@
 enum {
 	PROP_0,
 	PROP_CERTIFICATE,
-	PROP_LABEL,
 	PROP_ATTRIBUTES
 };
 
 struct _GcrCertificateWidgetPrivate {
-	GcrCertificate *certificate;
-	GcrDisplayView *view;
-	guint key_size;
-	gchar *label;
-	GckAttributes *attributes;
+	GcrViewer *viewer;
+	GcrCertificateRenderer *renderer;
 };
 
-static void gcr_view_iface_init (GcrViewIface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (GcrCertificateWidget, gcr_certificate_widget, GTK_TYPE_ALIGNMENT,
-                         G_IMPLEMENT_INTERFACE (GCR_TYPE_VIEW, gcr_view_iface_init));
-
-/* -----------------------------------------------------------------------------
- * INTERNAL
- */
-
-static gchar*
-calculate_label (GcrCertificateWidget *self, GNode *asn)
-{
-	gchar *label;
-
-	if (self->pv->label)
-		return g_strdup (self->pv->label);
-
-	if (self->pv->attributes) {
-		if (gck_attributes_find_string (self->pv->attributes, CKA_LABEL, &label))
-			return label;
-	}
-
-	if (asn != NULL) {
-		label = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL), "CN");
-		if (label != NULL)
-			return label;
-	}
-
-	return g_strdup (_("Certificate"));
-}
-
-static gboolean
-append_extension (GcrCertificateWidget *self, GNode *asn,
-                  const guchar *data, gsize n_data, gint index)
-{
-	GNode *node;
-	GQuark oid;
-	gchar *display;
-	gsize n_value;
-	const guchar *value;
-	const gchar *text;
-	gboolean critical;
-
-	/* Make sure it is present */
-	node = egg_asn1x_node (asn, "tbsCertificate", "extensions", index, NULL);
-	if (node == NULL)
-		return FALSE;
-
-	/* Dig out the OID */
-	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "extnID", NULL));
-	g_return_val_if_fail (oid, FALSE);
-
-	_gcr_display_view_append_heading (self->pv->view, _("Extension"));
-
-
-	/* Extension type */
-	text = egg_oid_get_description (oid);
-	_gcr_display_view_append_value (self->pv->view, _("Identifier"), text, FALSE);
-
-
-	/* Extension value */
-	value = egg_asn1x_get_raw_value (egg_asn1x_node (node, "extnValue", NULL), &n_value);
-
-	/* TODO: Parsing of extensions that we understand */
-	display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
-	_gcr_display_view_append_value (self->pv->view, _("Value"), display, TRUE);
-	g_free (display);
-
-
-	/* Critical */
-	if (egg_asn1x_get_boolean (egg_asn1x_node (node, "critical", NULL), &critical))
-		_gcr_display_view_append_value (self->pv->view, _("Critical"), critical ? _("Yes") : _("No"), FALSE);
-
-	return TRUE;
-}
-
-static void
-on_parsed_dn_part (guint index, GQuark oid, const guchar *value,
-                   gsize n_value, gpointer user_data)
-{
-	GcrCertificateWidget *self = user_data;
-	const gchar *attr;
-	const gchar *desc;
-	gchar *field;
-	gchar *display;
-
-	g_return_if_fail (GCR_IS_CERTIFICATE_WIDGET (self));
-
-	attr = egg_oid_get_name (oid);
-	desc = egg_oid_get_description (oid);
-
-	/* Combine them into something sane */
-	if (attr && desc) {
-		if (strcmp (attr, desc) == 0)
-			field = g_strdup (attr);
-		else
-			field = g_strdup_printf ("%s (%s)", attr, desc);
-	} else if (!attr && !desc) {
-		field = g_strdup ("");
-	} else if (attr) {
-		field = g_strdup (attr);
-	} else if (desc) {
-		field = g_strdup (desc);
-	} else {
-		g_assert_not_reached ();
-	}
-
-	display = egg_dn_print_value (oid, value, n_value);
-	if (display == NULL)
-		display = g_strdup ("");
-
-	_gcr_display_view_append_value (self->pv->view, field, display, FALSE);
-	g_free (field);
-	g_free (display);
-}
-
-static void
-refresh_display (GcrCertificateWidget *self)
-{
-	const guchar *data, *value;
-	gsize n_data, n_value, n_raw;
-	const gchar *text;
-	gpointer raw;
-	gulong version;
-	guint bits, index;
-	gchar *display;
-	GNode *asn;
-	GQuark oid;
-	GDate date;
-
-	if (!self->pv->view)
-		return;
-
-	_gcr_display_view_clear (self->pv->view);
-
-	if (!self->pv->certificate)
-		return;
-
-	data = gcr_certificate_get_der_data (self->pv->certificate, &n_data);
-	g_return_if_fail (data);
-
-	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data, n_data);
-	g_return_if_fail (asn);
-
-	display = calculate_label (self, asn);
-	_gcr_display_view_append_title (self->pv->view, display);
-	g_free (display);
-
-	display = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL), "CN");
-	_gcr_display_view_append_content (self->pv->view, _("Identity"), display);
-	g_free (display);
-
-	display = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL), "CN");
-	_gcr_display_view_append_content (self->pv->view, _("Verified by"), display);
-	g_free (display);
-
-	if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notAfter", NULL), &date)) {
-		display = g_malloc0 (128);
-		if (!g_date_strftime (display, 128, "%x", &date))
-			g_return_if_reached ();
-		_gcr_display_view_append_content (self->pv->view, _("Expires"), display);
-		g_free (display);
-	}
-
-	_gcr_display_view_start_details (self->pv->view);
-
-	/* The subject */
-	_gcr_display_view_append_heading (self->pv->view, _("Subject Name"));
-	egg_dn_parse (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL), on_parsed_dn_part, self);
-
-	/* The Issuer */
-	_gcr_display_view_append_heading (self->pv->view, _("Issuer Name"));
-	egg_dn_parse (egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL), on_parsed_dn_part, self);
-
-	/* The Issued Parameters */
-	_gcr_display_view_append_heading (self->pv->view, _("Issued Certificate"));
-
-	if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "tbsCertificate", "version", NULL), &version))
-		g_return_if_reached ();
-	display = g_strdup_printf ("%lu", version + 1);
-	_gcr_display_view_append_value (self->pv->view, _("Version"), display, FALSE);
-	g_free (display);
-
-	raw = egg_asn1x_get_integer_as_raw (egg_asn1x_node (asn, "tbsCertificate", "serialNumber", NULL), NULL, &n_raw);
-	g_return_if_fail (raw);
-	display = egg_hex_encode_full (raw, n_raw, TRUE, ' ', 1);
-	_gcr_display_view_append_value (self->pv->view, _("Serial Number"), display, TRUE);
-	g_free (display);
-	g_free (raw);
-
-	display = g_malloc0 (128);
-	if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notBefore", NULL), &date)) {
-		if (!g_date_strftime (display, 128, "%Y-%m-%d", &date))
-			g_return_if_reached ();
-		_gcr_display_view_append_value (self->pv->view, _("Not Valid Before"), display, FALSE);
-	}
-	if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notAfter", NULL), &date)) {
-		if (!g_date_strftime (display, 128, "%Y-%m-%d", &date))
-			g_return_if_reached ();
-		_gcr_display_view_append_value (self->pv->view, _("Not Valid After"), display, FALSE);
-	}
-	g_free (display);
-
-	/* Signature */
-	_gcr_display_view_append_heading (self->pv->view, _("Signature"));
-
-	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "signatureAlgorithm", "algorithm", NULL));
-	text = egg_oid_get_description (oid);
-	_gcr_display_view_append_value (self->pv->view, _("Signature Algorithm"), text, FALSE);
-
-	value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "signatureAlgorithm", "parameters", NULL), &n_value);
-	if (value && n_value) {
-		display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
-		_gcr_display_view_append_value (self->pv->view, _("Signature Parameters"), display, TRUE);
-		g_free (display);
-	}
-
-	raw = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "signature", NULL), NULL, &bits);
-	g_return_if_fail (raw);
-	display = egg_hex_encode_full (raw, bits / 8, TRUE, ' ', 1);
-	_gcr_display_view_append_value (self->pv->view, _("Signature"), display, TRUE);
-	g_free (display);
-	g_free (raw);
-
-	/* Public Key Info */
-	_gcr_display_view_append_heading (self->pv->view, _("Public Key Info"));
-
-	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo",
-	                                                  "algorithm", "algorithm", NULL));
-	text = egg_oid_get_description (oid);
-	_gcr_display_view_append_value (self->pv->view, _("Key Algorithm"), text, FALSE);
-
-	value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo",
-	                                                   "algorithm", "parameters", NULL), &n_value);
-	if (value && n_value) {
-		display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
-		_gcr_display_view_append_value (self->pv->view, _("Key Parameters"), display, TRUE);
-		g_free (display);
-	}
-
-	bits = gcr_certificate_get_key_size (self->pv->certificate);
-	if (bits > 0) {
-		display = g_strdup_printf ("%u", bits);
-		_gcr_display_view_append_value (self->pv->view, _("Key Size"), display, FALSE);
-		g_free (display);
-	}
-
-	raw = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo",
-	                                                 "subjectPublicKey", NULL), NULL, &bits);
-	g_return_if_fail (raw);
-	display = egg_hex_encode_full (raw, bits / 8, TRUE, ' ', 1);
-	_gcr_display_view_append_value (self->pv->view, _("Public Key"), display, TRUE);
-	g_free (display);
-	g_free (raw);
-
-	/* Fingerprints */
-	_gcr_display_view_append_heading (self->pv->view, _("Fingerprints"));
-
-	_gcr_display_view_append_fingerprint (self->pv->view, data, n_data, "SHA1", G_CHECKSUM_SHA1);
-	_gcr_display_view_append_fingerprint (self->pv->view, data, n_data, "MD5", G_CHECKSUM_MD5);
-
-	/* Extensions */
-	for (index = 1; TRUE; ++index) {
-		if (!append_extension (self, asn, data, n_data, index))
-			break;
-	}
-
-	egg_asn1x_destroy (asn);
-}
+G_DEFINE_TYPE (GcrCertificateWidget, gcr_certificate_widget, GTK_TYPE_ALIGNMENT);
 
 /* -----------------------------------------------------------------------------
  * OBJECT
@@ -337,17 +58,17 @@ gcr_certificate_widget_constructor (GType type, guint n_props, GObjectConstructP
 
 	self = GCR_CERTIFICATE_WIDGET (obj);
 
-	self->pv->view = _gcr_display_view_new ();
-	_gcr_display_view_set_stock_image (self->pv->view, GCR_ICON_CERTIFICATE);
+	self->pv->viewer = gcr_viewer_new ();
 
 	scroll = gtk_scrolled_window_new (NULL, NULL);
 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_ETCHED_IN);
 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-	gtk_container_add (GTK_CONTAINER (scroll), GTK_WIDGET (self->pv->view));
+	gtk_container_add (GTK_CONTAINER (scroll), GTK_WIDGET (self->pv->viewer));
 
 	gtk_container_add (GTK_CONTAINER (self), scroll);
 	gtk_widget_show_all (scroll);
 
+	gcr_viewer_add_renderer (self->pv->viewer, GCR_RENDERER (self->pv->renderer));
 	return obj;
 }
 
@@ -355,18 +76,7 @@ static void
 gcr_certificate_widget_init (GcrCertificateWidget *self)
 {
 	self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_CERTIFICATE_WIDGET, GcrCertificateWidgetPrivate));
-}
-
-static void
-gcr_certificate_widget_dispose (GObject *obj)
-{
-	GcrCertificateWidget *self = GCR_CERTIFICATE_WIDGET (obj);
-
-	if (self->pv->certificate)
-		g_object_unref (self->pv->certificate);
-	self->pv->certificate = NULL;
-
-	G_OBJECT_CLASS (gcr_certificate_widget_parent_class)->dispose (obj);
+	self->pv->renderer = gcr_certificate_renderer_new (NULL);
 }
 
 static void
@@ -374,14 +84,12 @@ gcr_certificate_widget_finalize (GObject *obj)
 {
 	GcrCertificateWidget *self = GCR_CERTIFICATE_WIDGET (obj);
 
-	g_assert (!self->pv->certificate);
+	g_assert (self->pv->renderer);
+	g_object_unref (self->pv->renderer);
+	self->pv->renderer = NULL;
 
-	if (self->pv->attributes)
-		gck_attributes_unref (self->pv->attributes);
-	self->pv->attributes = NULL;
-
-	g_free (self->pv->label);
-	self->pv->label = NULL;
+	g_assert (self->pv->viewer);
+	self->pv->viewer = NULL;
 
 	G_OBJECT_CLASS (gcr_certificate_widget_parent_class)->finalize (obj);
 }
@@ -391,35 +99,13 @@ gcr_certificate_widget_set_property (GObject *obj, guint prop_id, const GValue *
                                      GParamSpec *pspec)
 {
 	GcrCertificateWidget *self = GCR_CERTIFICATE_WIDGET (obj);
-	GcrCertificate *cert;
-	GckAttribute *attr;
 
 	switch (prop_id) {
 	case PROP_CERTIFICATE:
 		gcr_certificate_widget_set_certificate (self, g_value_get_object (value));
 		break;
-	case PROP_LABEL:
-		g_free (self->pv->label);
-		self->pv->label = g_value_dup_string (value);
-		g_object_notify (obj, "label");
-		refresh_display (self);
-		break;
 	case PROP_ATTRIBUTES:
-		g_return_if_fail (!self->pv->attributes);
-		self->pv->attributes = g_value_dup_boxed (value);
-		if (self->pv->attributes) {
-			attr = gck_attributes_find (self->pv->attributes, CKA_VALUE);
-			if (attr) {
-				/* Create a new certificate object refferring to same memory */
-				cert = gcr_simple_certificate_new_static (attr->value, attr->length);
-				g_object_set_data_full (G_OBJECT (cert), "attributes",
-				                        gck_attributes_ref (self->pv->attributes),
-				                        (GDestroyNotify)gck_attributes_unref);
-				gcr_certificate_widget_set_certificate (self, cert);
-				g_object_unref (cert);
-				refresh_display (self);
-			}
-		}
+		gcr_certificate_widget_set_attributes (self, g_value_get_boxed (value));
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -435,13 +121,10 @@ gcr_certificate_widget_get_property (GObject *obj, guint prop_id, GValue *value,
 
 	switch (prop_id) {
 	case PROP_CERTIFICATE:
-		g_value_set_object (value, self->pv->certificate);
-		break;
-	case PROP_LABEL:
-		g_value_take_string (value, calculate_label (self, NULL));
+		g_value_set_object (value, gcr_certificate_widget_get_certificate (self));
 		break;
 	case PROP_ATTRIBUTES:
-		g_value_set_boxed (value, self->pv->attributes);
+		g_value_set_boxed (value, gcr_certificate_widget_get_attributes (self));
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -459,7 +142,6 @@ gcr_certificate_widget_class_init (GcrCertificateWidgetClass *klass)
 	g_type_class_add_private (klass, sizeof (GcrCertificateWidgetPrivate));
 
 	gobject_class->constructor = gcr_certificate_widget_constructor;
-	gobject_class->dispose = gcr_certificate_widget_dispose;
 	gobject_class->finalize = gcr_certificate_widget_finalize;
 	gobject_class->set_property = gcr_certificate_widget_set_property;
 	gobject_class->get_property = gcr_certificate_widget_get_property;
@@ -468,24 +150,17 @@ gcr_certificate_widget_class_init (GcrCertificateWidgetClass *klass)
 	           g_param_spec_object("certificate", "Certificate", "Certificate to display.",
 	                               GCR_TYPE_CERTIFICATE, G_PARAM_READWRITE));
 
-	g_object_class_override_property (gobject_class, PROP_LABEL, "label");
-	g_object_class_override_property (gobject_class, PROP_ATTRIBUTES, "attributes");
+	g_object_class_install_property (gobject_class, PROP_ATTRIBUTES,
+	         g_param_spec_boxed ("attributes", "Attributes", "Attributes which contain the certificate",
+	                             GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE));
 
-	_gcr_icons_register ();
-
-	/* Register this as a view which can be loaded */
+	/* Register this as a renderer which can be loaded */
 	registered = gck_attributes_new ();
 	gck_attributes_add_ulong (registered, CKA_CLASS, CKO_CERTIFICATE);
-	gcr_view_register (GCR_TYPE_CERTIFICATE_WIDGET, registered);
+	gcr_renderer_register (GCR_TYPE_CERTIFICATE_WIDGET, registered);
 	gck_attributes_unref (registered);
 }
 
-static void
-gcr_view_iface_init (GcrViewIface *iface)
-{
-	/* Nothing to do */
-}
-
 /* -----------------------------------------------------------------------------
  * PUBLIC
  */
@@ -500,20 +175,26 @@ GcrCertificate*
 gcr_certificate_widget_get_certificate (GcrCertificateWidget *self)
 {
 	g_return_val_if_fail (GCR_IS_CERTIFICATE_WIDGET (self), NULL);
-	return self->pv->certificate;
+	return gcr_certificate_renderer_get_certificate (self->pv->renderer);
 }
 
 void
 gcr_certificate_widget_set_certificate (GcrCertificateWidget *self, GcrCertificate *cert)
 {
 	g_return_if_fail (GCR_IS_CERTIFICATE_WIDGET (self));
+	gcr_certificate_renderer_set_certificate (self->pv->renderer, cert);
+}
 
-	if (self->pv->certificate)
-		g_object_unref (self->pv->certificate);
-	self->pv->certificate = cert;
-	if (self->pv->certificate)
-		g_object_ref (self->pv->certificate);
+GckAttributes*
+gcr_certificate_widget_get_attributes (GcrCertificateWidget *self)
+{
+	g_return_val_if_fail (GCR_IS_CERTIFICATE_WIDGET (self), NULL);
+	return gcr_certificate_renderer_get_attributes (self->pv->renderer);
+}
 
-	refresh_display (self);
-	g_object_notify (G_OBJECT (self), "certificate");
+void
+gcr_certificate_widget_set_attributes (GcrCertificateWidget *self, GckAttributes* attrs)
+{
+	g_return_if_fail (GCR_IS_CERTIFICATE_WIDGET (self));
+	gcr_certificate_renderer_set_attributes (self->pv->renderer, attrs);
 }
diff --git a/gcr/gcr-certificate-widget.h b/gcr/gcr-certificate-widget.h
index e363e59..c88284e 100644
--- a/gcr/gcr-certificate-widget.h
+++ b/gcr/gcr-certificate-widget.h
@@ -52,11 +52,16 @@ GType                   gcr_certificate_widget_get_type               (void);
 
 GcrCertificateWidget*   gcr_certificate_widget_new                    (GcrCertificate *cert);
 
-GcrCertificate*         gcr_certificate_widget_get_certificate        (GcrCertificateWidget *details);
+GcrCertificate*         gcr_certificate_widget_get_certificate        (GcrCertificateWidget *self);
 
-void                    gcr_certificate_widget_set_certificate        (GcrCertificateWidget *details,
+void                    gcr_certificate_widget_set_certificate        (GcrCertificateWidget *self,
                                                                        GcrCertificate *cert);
 
+struct _GckAttributes*  gcr_certificate_widget_get_attributes         (GcrCertificateWidget *self);
+
+void                    gcr_certificate_widget_set_attributes         (GcrCertificateWidget *self,
+                                                                       struct _GckAttributes* attrs);
+
 G_END_DECLS
 
 #endif /* __GCR_CERTIFICATE_WIDGET_H__ */
diff --git a/gcr/gcr-display-view.c b/gcr/gcr-display-view.c
index a733fe6..23f5db1 100644
--- a/gcr/gcr-display-view.c
+++ b/gcr/gcr-display-view.c
@@ -20,28 +20,45 @@
 #include "config.h"
 
 #include "gcr-display-view.h"
+#include "gcr-renderer.h"
+#include "gcr-viewer.h"
 
 #include "egg/egg-oid.h"
 #include "egg/egg-hex.h"
 
 #include <gdk/gdk.h>
 
-G_DEFINE_TYPE (GcrDisplayView, _gcr_display_view, GTK_TYPE_TEXT_VIEW);
+static void _gcr_display_view_viewer_iface (GcrViewerIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GcrDisplayView, _gcr_display_view, GTK_TYPE_TEXT_VIEW,
+                         G_IMPLEMENT_INTERFACE (GCR_TYPE_VIEWER, _gcr_display_view_viewer_iface));
 
 #define NORMAL_MARGIN 10
 #define FIELD_MARGIN 17
 #define COLUMN_MARGIN 6
 #define ICON_MARGIN 8
 
-struct _GcrDisplayViewPrivate {
-	GtkTextBuffer *buffer;
-	GtkTextTag *field_tag;
-	GtkTextTag *details_tag;
+typedef struct _GcrDisplayItem {
+	GcrDisplayView *display_view;
+	GtkTextMark *beginning;
+	GtkTextMark *ending;
 	GtkWidget *details_widget;
-	GtkTextChildAnchor *details_anchor;
-	const gchar *extra_tag;
+	GtkTextTag *extra_tag;
 	gint field_width;
 	GdkPixbuf *pixbuf;
+	GtkTextTag *field_tag;
+	GtkTextTag *details_tag;
+	gulong data_changed_id;
+} GcrDisplayItem;
+
+struct _GcrDisplayViewPrivate {
+	GtkTextBuffer *buffer;
+	GPtrArray *renderers;
+	GHashTable *items;
+	GtkTextTag *title_tag;
+	GtkTextTag *content_tag;
+	GtkTextTag *heading_tag;
+	GtkTextTag *monospace_tag;
 };
 
 /* -----------------------------------------------------------------------------
@@ -52,7 +69,6 @@ static GtkTextTagTable*
 create_tag_table (GcrDisplayView *self)
 {
 	GtkTextTagTable *tags;
-	GtkTextTag *tag;
 	gint width, height;
 
 	g_assert (GCR_IS_DISPLAY_VIEW (self));
@@ -62,63 +78,41 @@ create_tag_table (GcrDisplayView *self)
 	if (!gtk_icon_size_lookup (GTK_ICON_SIZE_DIALOG, &width, &height))
 		width = 48;
 
-	tag = g_object_new (GTK_TYPE_TEXT_TAG,
-	                    "name", "title",
-	                    "scale", PANGO_SCALE_LARGE,
-	                    "right-margin", (ICON_MARGIN * 2) + width,
-	                    "pixels-above-lines", 9,
-	                    "pixels-below-lines", 6,
-	                    "weight", PANGO_WEIGHT_BOLD,
-	                    NULL);
-	gtk_text_tag_table_add (tags, tag);
-	g_object_unref (tag);
-
-	tag = g_object_new (GTK_TYPE_TEXT_TAG,
-	                    "name", "content",
-	                    "right-margin", (ICON_MARGIN * 2) + width,
-	                    "left-margin", FIELD_MARGIN,
-	                    "pixels-below-lines", 3,
-	                    NULL);
-	gtk_text_tag_table_add (tags, tag);
-	g_object_unref (tag);
-
-	tag = g_object_new (GTK_TYPE_TEXT_TAG,
-	                    "name", "heading",
-	                    "pixels-above-lines", 9,
-	                    "pixels-below-lines", 3,
-	                    "weight", PANGO_WEIGHT_BOLD,
-	                    NULL);
-	gtk_text_tag_table_add (tags, tag);
-	g_object_unref (tag);
-
-	tag = g_object_new (GTK_TYPE_TEXT_TAG,
-	                    "name", "monospace",
-	                    "family", "monospace",
-	                    NULL);
-	gtk_text_tag_table_add (tags, tag);
-	g_object_unref (tag);
-
-	g_assert (!self->pv->field_tag);
-	self->pv->field_width = 0;
-	self->pv->field_tag = g_object_new (GTK_TYPE_TEXT_TAG,
-	                                    "name", "field",
-	                                    "left-margin", self->pv->field_width + FIELD_MARGIN,
-	                                    "indent", self->pv->field_width,
-	                                    "pixels-below-lines", 3,
-	                                    "wrap-mode", GTK_WRAP_WORD_CHAR,
+	self->pv->title_tag = g_object_new (GTK_TYPE_TEXT_TAG,
+	                                    "name", "title",
+	                                    "scale", PANGO_SCALE_LARGE,
+	                                    "right-margin", (ICON_MARGIN * 2) + width,
+	                                    "pixels-above-lines", 9,
+	                                    "pixels-below-lines", 6,
+	                                    "weight", PANGO_WEIGHT_BOLD,
 	                                    NULL);
-	gtk_text_tag_table_add (tags, self->pv->field_tag);
+	gtk_text_tag_table_add (tags, self->pv->title_tag);
+
+	self->pv->content_tag = g_object_new (GTK_TYPE_TEXT_TAG,
+	                                      "name", "content",
+	                                      "right-margin", (ICON_MARGIN * 2) + width,
+	                                      "left-margin", FIELD_MARGIN,
+	                                      "pixels-below-lines", 3,
+	                                      NULL);
+	gtk_text_tag_table_add (tags, self->pv->content_tag);
 
-	g_assert (!self->pv->details_tag);
-	self->pv->details_tag = g_object_new (GTK_TYPE_TEXT_TAG,
-	                                      "name", "details",
+	self->pv->heading_tag = g_object_new (GTK_TYPE_TEXT_TAG,
+	                                      "name", "heading",
+	                                      "pixels-above-lines", 9,
+	                                      "pixels-below-lines", 3,
+	                                      "weight", PANGO_WEIGHT_BOLD,
 	                                      NULL);
-	gtk_text_tag_table_add (tags, self->pv->details_tag);
+	gtk_text_tag_table_add (tags, self->pv->heading_tag);
+
+	self->pv->monospace_tag = g_object_new (GTK_TYPE_TEXT_TAG,
+	                                        "name", "monospace",
+	                                        "family", "monospace",
+	                                        NULL);
+	gtk_text_tag_table_add (tags, self->pv->monospace_tag);
 
 	return tags;
 }
 
-
 static void
 on_expander_realize (GtkWidget *widget, gpointer user_data)
 {
@@ -131,12 +125,137 @@ static void
 on_expander_expanded (GObject *object, GParamSpec *param_spec, gpointer user_data)
 {
 	GtkExpander *expander = GTK_EXPANDER (object);
-	GcrDisplayView *self = GCR_DISPLAY_VIEW (user_data);
-	g_object_set (self->pv->details_tag,
+	GcrDisplayItem *item = user_data;
+	g_object_set (item->details_tag,
 	              "invisible", gtk_expander_get_expanded (expander) ? FALSE : TRUE,
 	              NULL);
 }
 
+static void
+style_display_item (GtkWidget *widget, GcrDisplayItem *item)
+{
+	GtkStyle *style = gtk_widget_get_style (widget);
+	gtk_widget_modify_bg (item->details_widget, GTK_STATE_NORMAL, &style->base[GTK_STATE_NORMAL]);
+}
+
+static GcrDisplayItem*
+create_display_item (GcrDisplayView *self)
+{
+	GcrDisplayItem *item;
+	GtkTextTagTable *tags;
+	GtkTextIter iter;
+	GtkWidget *widget;
+	GtkWidget *label;
+	GtkWidget *alignment;
+
+	item = g_new0 (GcrDisplayItem, 1);
+	item->display_view = self;
+
+	tags = gtk_text_buffer_get_tag_table (self->pv->buffer);
+
+	g_assert (!item->field_tag);
+	item->field_width = 0;
+	item->field_tag = g_object_new (GTK_TYPE_TEXT_TAG,
+	                                "left-margin", item->field_width + FIELD_MARGIN,
+	                                "indent", item->field_width,
+	                                "pixels-below-lines", 3,
+	                                "wrap-mode", GTK_WRAP_WORD_CHAR,
+	                                NULL);
+	gtk_text_tag_table_add (tags, item->field_tag);
+
+	g_assert (!item->details_tag);
+	item->details_tag = g_object_new (GTK_TYPE_TEXT_TAG, NULL);
+	gtk_text_tag_table_add (tags, item->details_tag);
+
+	/* The mark that determines the beginning of this item, with left gravity. */
+	gtk_text_buffer_get_end_iter (self->pv->buffer, &iter);
+	item->beginning = gtk_text_buffer_create_mark (self->pv->buffer, NULL, &iter, TRUE);
+	g_object_ref (item->beginning);
+
+	/* The mark that determines the end of this item, with right gravity. */
+	gtk_text_buffer_get_end_iter (self->pv->buffer, &iter);
+	item->ending = gtk_text_buffer_create_mark (self->pv->buffer, NULL, &iter, FALSE);
+	g_object_ref (item->ending);
+
+	widget = gtk_expander_new_with_mnemonic ("");
+	label = gtk_expander_get_label_widget (GTK_EXPANDER (widget));
+	gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), "<b>_Details</b>");
+	g_signal_connect (widget, "notify::expanded", G_CALLBACK (on_expander_expanded), item);
+	g_signal_connect (widget, "realize", G_CALLBACK (on_expander_realize), NULL);
+	on_expander_expanded (G_OBJECT (widget), NULL, item);
+
+	alignment = gtk_alignment_new (0.5, 0.5, 0.5, 0.5);
+	gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 9, 0, 0);
+	gtk_container_add (GTK_CONTAINER (alignment), widget);
+	gtk_widget_show_all (alignment);
+
+	item->details_widget = gtk_event_box_new ();
+	gtk_container_add (GTK_CONTAINER (item->details_widget), alignment);
+	g_signal_connect (item->details_widget, "realize", G_CALLBACK (on_expander_realize), NULL);
+	g_object_ref (item->details_widget);
+
+	if (gtk_widget_get_realized (GTK_WIDGET (self)))
+		style_display_item (GTK_WIDGET (self), item);
+
+	/* TODO: Initialize the rest of the fields */
+
+	return item;
+}
+
+static void
+destroy_display_item (gpointer data)
+{
+	GcrDisplayItem *item = data;
+	GtkTextTagTable *tags;
+	GcrDisplayView *self;
+
+	g_assert (item);
+
+	g_assert (GCR_IS_DISPLAY_VIEW (item->display_view));
+	self = item->display_view;
+
+	tags = gtk_text_buffer_get_tag_table (self->pv->buffer);
+	gtk_text_tag_table_remove (tags, item->field_tag);
+	gtk_text_tag_table_remove (tags, item->details_tag);
+
+	g_object_unref (item->field_tag);
+	g_object_unref (item->details_tag);
+
+	if (item->pixbuf)
+		g_object_unref (item->pixbuf);
+	item->pixbuf = NULL;
+
+	g_assert (item->details_widget);
+	g_object_unref (item->details_widget);
+	item->details_widget = NULL;
+
+	g_return_if_fail (!gtk_text_mark_get_deleted (item->beginning));
+	gtk_text_buffer_delete_mark (self->pv->buffer, item->beginning);
+	g_object_unref (item->beginning);
+
+	g_return_if_fail (!gtk_text_mark_get_deleted (item->ending));
+	gtk_text_buffer_delete_mark (self->pv->buffer, item->ending);
+	g_object_unref (item->ending);
+
+	g_free (item);
+}
+
+static GcrDisplayItem*
+lookup_display_item (GcrDisplayView *self, GcrRenderer *renderer)
+{
+	GcrDisplayItem *item = g_hash_table_lookup (self->pv->items, renderer);
+	g_return_val_if_fail (item, NULL);
+	g_assert (item->display_view == self);
+	return item;
+}
+
+static void
+on_renderer_data_changed (GcrRenderer *renderer, GcrViewer *self)
+{
+	/* Just ask the renderer to render itself on us */
+	gcr_renderer_render (renderer, self);
+}
+
 /* -----------------------------------------------------------------------------
  * OBJECT
  */
@@ -148,7 +267,6 @@ _gcr_display_view_constructor (GType type, guint n_props, GObjectConstructParam
 	GcrDisplayView *self = NULL;
 	GtkTextView *view = NULL;
 	GtkTextTagTable *tags;
-	GtkWidget *widget, *alignment, *label;
 
 	g_return_val_if_fail (obj, NULL);
 
@@ -165,26 +283,6 @@ _gcr_display_view_constructor (GType type, guint n_props, GObjectConstructParam
 	gtk_text_view_set_right_margin (view, NORMAL_MARGIN);
 	gtk_text_view_set_cursor_visible (view, FALSE);
 
-	widget = gtk_expander_new_with_mnemonic ("");
-	label = gtk_expander_get_label_widget (GTK_EXPANDER (widget));
-	gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), "<b>_Details</b>");
-	g_signal_connect_object (widget, "notify::expanded",
-	                         G_CALLBACK (on_expander_expanded), self, 0);
-	g_signal_connect_object (widget, "realize",
-	                         G_CALLBACK (on_expander_realize), self, 0);
-	on_expander_expanded (G_OBJECT (widget), NULL, self);
-
-	alignment = gtk_alignment_new (0.5, 0.5, 0.5, 0.5);
-	gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 9, 0, 0);
-	gtk_container_add (GTK_CONTAINER (alignment), widget);
-	gtk_widget_show_all (alignment);
-
-	self->pv->details_widget = gtk_event_box_new ();
-	gtk_container_add (GTK_CONTAINER (self->pv->details_widget), alignment);
-	g_signal_connect_object (self->pv->details_widget, "realize",
-	                         G_CALLBACK (on_expander_realize), self, 0);
-	g_object_ref (self->pv->details_widget);
-
 	return obj;
 }
 
@@ -192,6 +290,34 @@ static void
 _gcr_display_view_init (GcrDisplayView *self)
 {
 	self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_DISPLAY_VIEW, GcrDisplayViewPrivate));
+	self->pv->items = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, destroy_display_item);
+	self->pv->renderers = g_ptr_array_new_with_free_func (g_object_unref);
+}
+
+static void
+_gcr_display_view_dispose (GObject *obj)
+{
+	GcrDisplayView *self = GCR_DISPLAY_VIEW (obj);
+	GcrRenderer *renderer;
+	GcrDisplayItem *item;
+
+	if (self->pv->buffer)
+		g_object_unref (self->pv->buffer);
+	self->pv->buffer = NULL;
+
+	while (self->pv->renderers->len) {
+		renderer = g_ptr_array_index (self->pv->renderers, 0);
+		item = g_hash_table_lookup (self->pv->items, renderer);
+		g_return_if_fail (item);
+		g_signal_handler_disconnect (renderer, item->data_changed_id);
+		if (!g_hash_table_remove (self->pv->items, renderer))
+			g_return_if_reached ();
+		g_ptr_array_remove_index_fast (self->pv->renderers, 0);
+	}
+
+	g_assert (g_hash_table_size (self->pv->items) == 0);
+
+	G_OBJECT_CLASS (_gcr_display_view_parent_class)->finalize (obj);
 }
 
 static void
@@ -203,17 +329,30 @@ _gcr_display_view_finalize (GObject *obj)
 		g_object_unref (self->pv->buffer);
 	self->pv->buffer = NULL;
 
-	if (self->pv->field_tag)
-		g_object_unref (self->pv->field_tag);
-	self->pv->field_tag = NULL;
+	g_assert (g_hash_table_size (self->pv->items) == 0);
+	g_hash_table_destroy (self->pv->items);
+	self->pv->items = NULL;
+
+	g_assert (self->pv->renderers);
+	g_assert (self->pv->renderers->len == 0);
+	g_ptr_array_free (self->pv->renderers, TRUE);
+	self->pv->renderers = NULL;
+
+	g_assert (self->pv->content_tag);
+	g_object_unref (self->pv->content_tag);
+	self->pv->content_tag = NULL;
 
-	if (self->pv->pixbuf)
-		g_object_unref (self->pv->pixbuf);
-	self->pv->pixbuf = NULL;
+	g_assert (self->pv->heading_tag);
+	g_object_unref (self->pv->heading_tag);
+	self->pv->heading_tag = NULL;
 
-	if (self->pv->details_widget)
-		g_object_unref (self->pv->details_widget);
-	self->pv->details_widget = NULL;
+	g_assert (self->pv->monospace_tag);
+	g_object_unref (self->pv->monospace_tag);
+	self->pv->monospace_tag = NULL;
+
+	g_assert (self->pv->title_tag);
+	g_object_unref (self->pv->title_tag);
+	self->pv->title_tag = NULL;
 
 	G_OBJECT_CLASS (_gcr_display_view_parent_class)->finalize (obj);
 }
@@ -222,13 +361,16 @@ static void
 _gcr_display_view_realize (GtkWidget *widget)
 {
 	GcrDisplayView *self = GCR_DISPLAY_VIEW (widget);
-	GtkStyle *style;
+	GHashTableIter iter;
+	gpointer value;
 
 	if (GTK_WIDGET_CLASS (_gcr_display_view_parent_class)->realize)
 		GTK_WIDGET_CLASS (_gcr_display_view_parent_class)->realize (widget);
 
-	style = gtk_widget_get_style (widget);
-	gtk_widget_modify_bg (self->pv->details_widget, GTK_STATE_NORMAL, &style->base[GTK_STATE_NORMAL]);
+	/* Set style on all the items */
+	g_hash_table_iter_init (&iter, self->pv->items);
+	while (g_hash_table_iter_next (&iter, NULL, &value))
+		style_display_item (widget, value);
 }
 
 static gboolean
@@ -238,33 +380,49 @@ _gcr_display_view_expose_event (GtkWidget *widget, GdkEventExpose *event)
 	GtkTextView *view = GTK_TEXT_VIEW (widget);
 	gboolean handled = FALSE;
 	GdkRectangle visible;
-	GdkRectangle position;
+	GdkRectangle location;
+	GHashTableIter hit;
+	GcrDisplayItem *item;
+	gpointer value;
+	GtkTextIter iter;
 	cairo_t *cr;
 
 	/* Have GtkTextView draw the text first. */
 	if (GTK_WIDGET_CLASS (_gcr_display_view_parent_class)->expose_event)
 		handled = GTK_WIDGET_CLASS (_gcr_display_view_parent_class)->expose_event (widget, event);
 
-	if (self->pv->pixbuf == NULL)
-		return handled;
-
 	/* Render the pixbuf if it's available */
 	if (event->window == gtk_text_view_get_window (view, GTK_TEXT_WINDOW_TEXT)) {
 
-		position.height = gdk_pixbuf_get_height (self->pv->pixbuf);
-		position.width = gdk_pixbuf_get_width (self->pv->pixbuf);
-
 		gtk_text_view_get_visible_rect (view, &visible);
 
-		gtk_text_view_buffer_to_window_coords (view, GTK_TEXT_WINDOW_TEXT,
-		                                       visible.width - position.width - ICON_MARGIN, ICON_MARGIN,
-		                                       &position.x, &position.y);
+		g_hash_table_iter_init (&hit, self->pv->items);
+		while (g_hash_table_iter_next (&hit, NULL, &value)) {
 
-		cr = gdk_cairo_create (event->window);
-		gdk_cairo_set_source_pixbuf (cr, self->pv->pixbuf, 0, 0);
-		cairo_rectangle (cr, position.x, position.y, position.width, position.height);
-		cairo_fill (cr);
-		cairo_destroy (cr);
+			item = value;
+			if (item->pixbuf == NULL)
+				continue;
+
+			gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->beginning);
+			gtk_text_view_get_iter_location (view, &iter, &location);
+
+			location.height = gdk_pixbuf_get_height (item->pixbuf);
+			location.width = gdk_pixbuf_get_width (item->pixbuf);
+			location.x = visible.width - location.width - ICON_MARGIN;
+
+			if (!gdk_rectangle_intersect (&visible, &location, NULL))
+				continue;
+
+			gtk_text_view_buffer_to_window_coords (view, GTK_TEXT_WINDOW_TEXT,
+			                                       location.x, location.y,
+			                                       &location.x, &location.y);
+
+			cr = gdk_cairo_create (event->window);
+			gdk_cairo_set_source_pixbuf (cr, item->pixbuf, location.x, location.y);
+			cairo_rectangle (cr, location.x, location.y, location.width, location.height);
+			cairo_fill (cr);
+			cairo_destroy (cr);
+		}
 	}
 
 	return handled;
@@ -280,12 +438,73 @@ _gcr_display_view_class_init (GcrDisplayViewClass *klass)
 	g_type_class_add_private (klass, sizeof (GcrDisplayViewPrivate));
 
 	gobject_class->constructor = _gcr_display_view_constructor;
+	gobject_class->dispose = _gcr_display_view_dispose;
 	gobject_class->finalize = _gcr_display_view_finalize;
 
 	widget_class->realize = _gcr_display_view_realize;
 	widget_class->expose_event = _gcr_display_view_expose_event;
 }
 
+static void
+_gcr_display_view_real_add_renderer (GcrViewer *viewer, GcrRenderer *renderer)
+{
+	GcrDisplayView *self = GCR_DISPLAY_VIEW (viewer);
+	GcrDisplayItem *item;
+
+	item = create_display_item (self);
+	g_ptr_array_add (self->pv->renderers, g_object_ref (renderer));
+	g_hash_table_insert (self->pv->items, renderer, item);
+
+	gcr_renderer_render (renderer, viewer);
+	item->data_changed_id = g_signal_connect (renderer, "data-changed",
+	                                          G_CALLBACK (on_renderer_data_changed), self);
+}
+
+static void
+_gcr_display_view_real_remove_renderer (GcrViewer *viewer, GcrRenderer *renderer)
+{
+	GcrDisplayView *self = GCR_DISPLAY_VIEW (viewer);
+	GcrDisplayItem *item;
+
+	item = lookup_display_item (self, renderer);
+	g_return_if_fail (item);
+
+	/* Unhook the callback */
+	g_signal_handler_disconnect (renderer, item->data_changed_id);
+
+	/* Destroys the display item */
+	g_assert (item->display_view == self);
+	g_hash_table_remove (self->pv->items, renderer);
+
+	/* Unrefs the renderer */
+	if (!g_ptr_array_remove (self->pv->renderers, renderer))
+		g_return_if_reached ();
+}
+
+static guint
+_gcr_display_view_real_count_renderers (GcrViewer *viewer)
+{
+	GcrDisplayView *self = GCR_DISPLAY_VIEW (viewer);
+	return self->pv->renderers->len;
+}
+
+static GcrRenderer*
+_gcr_display_view_real_get_renderer (GcrViewer *viewer, guint index_)
+{
+	GcrDisplayView *self = GCR_DISPLAY_VIEW (viewer);
+	g_return_val_if_fail (index_ < self->pv->renderers->len, NULL);
+	return g_ptr_array_index (self->pv->renderers, index_);
+}
+
+static void
+_gcr_display_view_viewer_iface (GcrViewerIface *iface)
+{
+	iface->add_renderer = (gpointer)_gcr_display_view_real_add_renderer;
+	iface->remove_renderer = (gpointer)_gcr_display_view_real_remove_renderer;
+	iface->count_renderers = (gpointer)_gcr_display_view_real_count_renderers;
+	iface->get_renderer = (gpointer)_gcr_display_view_real_get_renderer;
+}
+
 /* -----------------------------------------------------------------------------
  * PUBLIC
  */
@@ -297,64 +516,87 @@ _gcr_display_view_new (void)
 }
 
 void
-_gcr_display_view_clear (GcrDisplayView *self)
+_gcr_display_view_clear (GcrDisplayView *self, GcrRenderer *renderer)
 {
 	GtkTextIter start, iter;
-	if (gtk_widget_get_parent (self->pv->details_widget))
-		gtk_container_remove (GTK_CONTAINER (self), self->pv->details_widget);
+	GcrDisplayItem *item;
+
+	g_return_if_fail (GCR_IS_DISPLAY_VIEW (self));
+	item = lookup_display_item (self, renderer);
+	g_return_if_fail (item);
+
+	if (gtk_widget_get_parent (item->details_widget))
+		gtk_container_remove (GTK_CONTAINER (self), item->details_widget);
 	gtk_text_buffer_get_start_iter (self->pv->buffer, &start);
 	gtk_text_buffer_get_end_iter (self->pv->buffer, &iter);
 	gtk_text_buffer_delete (self->pv->buffer, &start, &iter);
-	self->pv->extra_tag = NULL;
-	self->pv->field_width = 0;
+	item->extra_tag = NULL;
+	item->field_width = 0;
 }
 
 void
-_gcr_display_view_start_details (GcrDisplayView *self)
+_gcr_display_view_start_details (GcrDisplayView *self, GcrRenderer *renderer)
 {
 	GtkTextChildAnchor *anchor;
+	GcrDisplayItem *item;
 	GtkTextIter iter;
 
-	self->pv->extra_tag = "details";
+	g_return_if_fail (GCR_IS_DISPLAY_VIEW (self));
+	item = lookup_display_item (self, renderer);
+	g_return_if_fail (item);
+
+	item->extra_tag = item->details_tag;
 
 	gtk_text_buffer_get_end_iter (self->pv->buffer, &iter);
 	anchor = gtk_text_buffer_create_child_anchor (self->pv->buffer, &iter);
-	gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (self), self->pv->details_widget, anchor);
-	gtk_widget_show_all (self->pv->details_widget);
+	gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (self), item->details_widget, anchor);
+	gtk_widget_show_all (item->details_widget);
 	gtk_text_buffer_insert (self->pv->buffer, &iter, "\n", 1);
 }
 
 void
-_gcr_display_view_append_content (GcrDisplayView *self, const gchar *content, const gchar *details)
+_gcr_display_view_append_content (GcrDisplayView *self, GcrRenderer *renderer,
+                                  const gchar *content, const gchar *details)
 {
+	GcrDisplayItem *item;
 	GtkTextIter iter;
 	gchar *memory = NULL;
 
 	g_return_if_fail (GCR_IS_DISPLAY_VIEW (self));
 	g_return_if_fail (content);
 
+	item = lookup_display_item (self, renderer);
+	g_return_if_fail (item);
+
 	if (details)
 		content = memory = g_strdup_printf ("%s: %s", content, details);
 
-	gtk_text_buffer_get_end_iter (self->pv->buffer, &iter);
-	gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, content, -1,
-	                                          "content", self->pv->extra_tag, NULL);
-	gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, "\n", 1,
-	                                          self->pv->extra_tag, NULL);
+	gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->ending);
+	gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, content, -1,
+	                                  self->pv->content_tag, item->extra_tag, NULL);
+	gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, "\n", 1,
+	                                  item->extra_tag, NULL);
 
 	g_free (memory);
 }
 
 void
-_gcr_display_view_append_value (GcrDisplayView *self, const gchar *field,
+_gcr_display_view_append_value (GcrDisplayView *self, GcrRenderer *renderer, const gchar *field,
                                 const gchar *value, gboolean monospace)
 {
+	GcrDisplayItem *item;
 	PangoRectangle extents;
 	PangoTabArray *tabs;
 	PangoLayout *layout;
 	GtkTextIter iter;
 	gchar *text;
 
+	g_return_if_fail (GCR_IS_DISPLAY_VIEW (self));
+	g_return_if_fail (field);
+
+	item = lookup_display_item (self, renderer);
+	g_return_if_fail (item);
+
 	text = g_strdup_printf ("%s:", field);
 	if (value == NULL)
 		value = "";
@@ -366,58 +608,75 @@ _gcr_display_view_append_value (GcrDisplayView *self, const gchar *field,
 	g_object_unref (layout);
 
 	/* Make the tab wide enough to accomodate */
-	if (extents.width > self->pv->field_width) {
-		self->pv->field_width = extents.width + COLUMN_MARGIN;
+	if (extents.width > item->field_width) {
+		item->field_width = extents.width + COLUMN_MARGIN;
 		tabs = pango_tab_array_new (1, TRUE);
-		pango_tab_array_set_tab (tabs, 0, PANGO_TAB_LEFT, self->pv->field_width);
-		g_object_set (self->pv->field_tag,
+		pango_tab_array_set_tab (tabs, 0, PANGO_TAB_LEFT, item->field_width);
+		g_object_set (item->field_tag,
 		              "left-margin", FIELD_MARGIN,
-		              "indent", 0 - self->pv->field_width,
+		              "indent", 0 - item->field_width,
 		              "tabs", tabs,
 		              NULL);
 		pango_tab_array_free (tabs);
 	}
 
-	gtk_text_buffer_get_end_iter (self->pv->buffer, &iter);
-	gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, text, -1,
-	                                          "field", self->pv->extra_tag, NULL);
-	gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, "\t", 1,
-	                                          self->pv->extra_tag, NULL);
-	gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, value, -1, "field",
-	                                          monospace ? "monospace" : self->pv->extra_tag,
-	                                          monospace ? self->pv->extra_tag : NULL, NULL);
-	gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, "\n", 1,
-	                                          self->pv->extra_tag, NULL);
+	gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->ending);
+	gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, text, -1,
+	                                  item->field_tag, item->extra_tag, NULL);
+	gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, "\t", 1,
+	                                  item->extra_tag, NULL);
+	gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, value, -1, item->field_tag,
+	                                  monospace ? self->pv->monospace_tag : item->extra_tag,
+	                                  monospace ? item->extra_tag : NULL, NULL);
+	gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, "\n", 1,
+	                                  item->extra_tag, NULL);
 
 	g_free (text);
 }
 
 void
-_gcr_display_view_append_title (GcrDisplayView *self, const gchar *title)
+_gcr_display_view_append_title (GcrDisplayView *self, GcrRenderer *renderer, const gchar *title)
 {
+	GcrDisplayItem *item;
 	GtkTextIter iter;
 
-	gtk_text_buffer_get_end_iter (self->pv->buffer, &iter);
-	gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, title, -1,
-	                                          "title", self->pv->extra_tag, NULL);
-	gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, "\n", 1,
-	                                          self->pv->extra_tag, NULL);
+	g_return_if_fail (GCR_IS_DISPLAY_VIEW (self));
+	g_return_if_fail (title);
+
+	item = lookup_display_item (self, renderer);
+	g_return_if_fail (item);
+
+	g_return_if_fail (GCR_IS_DISPLAY_VIEW (self));
+	g_return_if_fail (item && item->display_view == self);
+
+	gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->ending);
+	gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, title, -1,
+	                                  self->pv->title_tag, item->extra_tag, NULL);
+	gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, "\n", 1,
+	                                  item->extra_tag, NULL);
 }
 
 void
-_gcr_display_view_append_heading (GcrDisplayView *self, const gchar *heading)
+_gcr_display_view_append_heading (GcrDisplayView *self, GcrRenderer *renderer, const gchar *heading)
 {
+	GcrDisplayItem *item;
 	GtkTextIter iter;
 
-	gtk_text_buffer_get_end_iter (self->pv->buffer, &iter);
-	gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, heading, -1,
-	                                          "heading", self->pv->extra_tag, NULL);
-	gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, "\n", 1,
-	                                          self->pv->extra_tag, NULL);
+	g_return_if_fail (GCR_IS_DISPLAY_VIEW (self));
+	g_return_if_fail (heading);
+
+	item = lookup_display_item (self, renderer);
+	g_return_if_fail (item);
+
+	gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->ending);
+	gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, heading, -1,
+	                                  self->pv->heading_tag, item->extra_tag, NULL);
+	gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, "\n", 1,
+	                                  item->extra_tag, NULL);
 }
 
 void
-_gcr_display_view_append_fingerprint (GcrDisplayView *self, const guchar *data,
+_gcr_display_view_append_fingerprint (GcrDisplayView *self, GcrRenderer *renderer, const guchar *data,
                                       gsize n_data, const gchar *name, GChecksumType type)
 {
 	GChecksum *checksum;
@@ -425,6 +684,8 @@ _gcr_display_view_append_fingerprint (GcrDisplayView *self, const guchar *data,
 	gsize n_buffer;
 	gchar *display;
 
+	g_return_if_fail (GCR_IS_DISPLAY_VIEW (self));
+
 	checksum = g_checksum_new (type);
 	g_return_if_fail (checksum);
 	g_checksum_update (checksum, data, n_data);
@@ -437,16 +698,26 @@ _gcr_display_view_append_fingerprint (GcrDisplayView *self, const guchar *data,
 	g_checksum_free (checksum);
 
 	display = egg_hex_encode_full (buffer, n_buffer, TRUE, ' ', 1);
-	_gcr_display_view_append_value (self, name, display, TRUE);
+	_gcr_display_view_append_value (self, renderer, name, display, TRUE);
 	g_free (display);
 
 	g_free (buffer);
 }
 
 void
-_gcr_display_view_set_stock_image (GcrDisplayView *self, const gchar *stock_id)
+_gcr_display_view_set_stock_image (GcrDisplayView *self, GcrRenderer *renderer,
+                                   const gchar *stock_id)
 {
-	if (self->pv->pixbuf)
-		g_object_unref (self->pv->pixbuf);
-	self->pv->pixbuf = gtk_widget_render_icon (GTK_WIDGET (self), stock_id, GTK_ICON_SIZE_DIALOG, NULL);
+	GcrDisplayItem *item;
+
+	g_return_if_fail (GCR_IS_DISPLAY_VIEW (self));
+	item = lookup_display_item (self, renderer);
+	g_return_if_fail (item);
+
+	if (item->pixbuf)
+		g_object_unref (item->pixbuf);
+	if (stock_id)
+		item->pixbuf = gtk_widget_render_icon (GTK_WIDGET (self), stock_id, GTK_ICON_SIZE_DIALOG, NULL);
+	else
+		item->pixbuf = NULL;
 }
diff --git a/gcr/gcr-display-view.h b/gcr/gcr-display-view.h
index f47aecf..c5f83a6 100644
--- a/gcr/gcr-display-view.h
+++ b/gcr/gcr-display-view.h
@@ -25,6 +25,7 @@
 
 #include "gcr-certificate.h"
 #include "gcr-types.h"
+#include "gcr-viewer.h"
 
 G_BEGIN_DECLS
 
@@ -52,32 +53,40 @@ GType            _gcr_display_view_get_type                    (void);
 
 GcrDisplayView*  _gcr_display_view_new                         (void);
 
-void             _gcr_display_view_clear                       (GcrDisplayView *self);
+void             _gcr_display_view_clear                       (GcrDisplayView *self,
+                                                                GcrRenderer *renderer);
 
 void             _gcr_display_view_append_value                (GcrDisplayView *self,
+                                                                GcrRenderer *renderer,
                                                                 const gchar *field,
                                                                 const gchar *value,
                                                                 gboolean monospace);
 
 void             _gcr_display_view_append_title                (GcrDisplayView *self,
+                                                                GcrRenderer *renderer,
                                                                 const gchar *title);
 
 void             _gcr_display_view_append_content              (GcrDisplayView *self,
+                                                                GcrRenderer *renderer,
                                                                 const gchar *content,
                                                                 const gchar *details);
 
-void             _gcr_display_view_start_details               (GcrDisplayView *self);
+void             _gcr_display_view_start_details               (GcrDisplayView *self,
+                                                                GcrRenderer *renderer);
 
 void             _gcr_display_view_append_heading              (GcrDisplayView *self,
+                                                                GcrRenderer *renderer,
                                                                 const gchar *heading);
 
 void             _gcr_display_view_append_fingerprint          (GcrDisplayView *self,
+                                                                GcrRenderer *renderer,
                                                                 const guchar *data,
                                                                 gsize n_data,
                                                                 const gchar *name,
                                                                 GChecksumType type);
 
 void             _gcr_display_view_set_stock_image             (GcrDisplayView *self,
+                                                                GcrRenderer *renderer,
                                                                 const gchar *stock_id);
 
 G_END_DECLS
diff --git a/gcr/gcr-key-renderer.c b/gcr/gcr-key-renderer.c
new file mode 100644
index 0000000..262dde3
--- /dev/null
+++ b/gcr/gcr-key-renderer.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2010 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gcr-key-renderer.h"
+#include "gcr-display-view.h"
+#include "gcr-icons.h"
+#include "gcr-renderer.h"
+#include "gcr-viewer.h"
+
+#include "egg/egg-hex.h"
+
+#include "gck/gck.h"
+
+#include <gdk/gdk.h>
+#include <glib/gi18n-lib.h>
+
+enum {
+	PROP_0,
+	PROP_LABEL,
+	PROP_ATTRIBUTES
+};
+
+struct _GcrKeyRendererPrivate {
+	guint key_size;
+	gchar *label;
+	GckAttributes *attributes;
+};
+
+static void gcr_key_renderer_renderer_iface (GcrRendererIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GcrKeyRenderer, gcr_key_renderer, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (GCR_TYPE_RENDERER, gcr_key_renderer_renderer_iface));
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static gchar*
+calculate_label (GcrKeyRenderer *self)
+{
+	gchar *label;
+
+	if (self->pv->label)
+		return g_strdup (self->pv->label);
+
+	if (self->pv->attributes) {
+		if (gck_attributes_find_string (self->pv->attributes, CKA_LABEL, &label))
+			return label;
+	}
+
+	return g_strdup (_("Key"));
+}
+
+static gint
+calculate_rsa_key_size (GckAttributes *attrs)
+{
+	GckAttribute *attr;
+	gulong bits;
+
+	attr = gck_attributes_find (attrs, CKA_MODULUS);
+
+	/* Calculate the bit length, and remove the complement */
+	if (attr != NULL)
+		return (attr->length / 2) * 2 * 8;
+
+	if (gck_attributes_find_ulong (attrs, CKA_MODULUS_BITS, &bits))
+		return (gint)bits;
+
+	return -1;
+}
+
+static guint
+calculate_dsa_key_size (GckAttributes *attrs)
+{
+	GckAttribute *attr;
+	gulong bits;
+
+	attr = gck_attributes_find (attrs, CKA_PRIME);
+
+	/* Calculate the bit length, and remove the complement */
+	if (attr != NULL)
+		return (attr->length / 2) * 2 * 8;
+
+	if (gck_attributes_find_ulong (attrs, CKA_PRIME_BITS, &bits))
+		return (gint)bits;
+
+	return -1;
+}
+
+static gint
+calculate_key_size (GckAttributes *attrs, gulong key_type)
+{
+	if (key_type == CKK_RSA)
+		return calculate_rsa_key_size (attrs);
+	else if (key_type == CKK_DSA)
+		return calculate_dsa_key_size (attrs);
+	else
+		return -1;
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static void
+gcr_key_renderer_init (GcrKeyRenderer *self)
+{
+	self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_KEY_RENDERER, GcrKeyRendererPrivate));
+}
+
+static void
+gcr_key_renderer_dispose (GObject *obj)
+{
+	G_OBJECT_CLASS (gcr_key_renderer_parent_class)->dispose (obj);
+}
+
+static void
+gcr_key_renderer_finalize (GObject *obj)
+{
+	GcrKeyRenderer *self = GCR_KEY_RENDERER (obj);
+
+	if (self->pv->attributes)
+		gck_attributes_unref (self->pv->attributes);
+	self->pv->attributes = NULL;
+
+	g_free (self->pv->label);
+	self->pv->label = NULL;
+
+	G_OBJECT_CLASS (gcr_key_renderer_parent_class)->finalize (obj);
+}
+
+static void
+gcr_key_renderer_set_property (GObject *obj, guint prop_id, const GValue *value,
+                               GParamSpec *pspec)
+{
+	GcrKeyRenderer *self = GCR_KEY_RENDERER (obj);
+
+	switch (prop_id) {
+	case PROP_LABEL:
+		g_free (self->pv->label);
+		self->pv->label = g_value_dup_string (value);
+		g_object_notify (obj, "label");
+		gcr_renderer_emit_data_changed (GCR_RENDERER (self));
+		break;
+	case PROP_ATTRIBUTES:
+		g_return_if_fail (!self->pv->attributes);
+		self->pv->attributes = g_value_dup_boxed (value);
+		gcr_renderer_emit_data_changed (GCR_RENDERER (self));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gcr_key_renderer_get_property (GObject *obj, guint prop_id, GValue *value,
+                               GParamSpec *pspec)
+{
+	GcrKeyRenderer *self = GCR_KEY_RENDERER (obj);
+
+	switch (prop_id) {
+	case PROP_LABEL:
+		g_value_take_string (value, calculate_label (self));
+		break;
+	case PROP_ATTRIBUTES:
+		g_value_set_boxed (value, self->pv->attributes);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gcr_key_renderer_class_init (GcrKeyRendererClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckAttributes *registered;
+
+	gcr_key_renderer_parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (GcrKeyRendererPrivate));
+
+	gobject_class->dispose = gcr_key_renderer_dispose;
+	gobject_class->finalize = gcr_key_renderer_finalize;
+	gobject_class->set_property = gcr_key_renderer_set_property;
+	gobject_class->get_property = gcr_key_renderer_get_property;
+
+	g_object_class_override_property (gobject_class, PROP_LABEL, "label");
+	g_object_class_override_property (gobject_class, PROP_ATTRIBUTES, "attributes");
+
+	_gcr_icons_register ();
+
+	/* Register this as a view which can be loaded */
+	registered = gck_attributes_new ();
+	gck_attributes_add_ulong (registered, CKA_CLASS, CKO_PRIVATE_KEY);
+	gcr_renderer_register (GCR_TYPE_KEY_RENDERER, registered);
+	gck_attributes_unref (registered);
+}
+
+static void
+gcr_key_renderer_real_render (GcrRenderer *renderer, GcrViewer *viewer)
+{
+	GcrKeyRenderer *self;
+	GcrDisplayView *view;
+	const gchar *text;
+	gchar *display;
+	gulong klass;
+	gulong key_type;
+	gint size;
+
+	self = GCR_KEY_RENDERER (renderer);
+
+	if (GCR_IS_DISPLAY_VIEW (viewer)) {
+		view = GCR_DISPLAY_VIEW (viewer);
+
+	} else {
+		g_warning ("GcrKeyRenderer only works with internal specific "
+		           "GcrViewer returned by gcr_viewer_new().");
+		return;
+	}
+
+	_gcr_display_view_clear (view, renderer);
+
+	if (!self->pv->attributes)
+		return;
+
+	_gcr_display_view_set_stock_image (view, renderer, GTK_STOCK_DIALOG_AUTHENTICATION);
+
+	if (!gck_attributes_find_ulong (self->pv->attributes, CKA_CLASS, &klass) ||
+	    !gck_attributes_find_ulong (self->pv->attributes, CKA_KEY_TYPE, &key_type)) {
+		g_warning ("private key does not have the CKA_CLASS and CKA_KEY_TYPE attributes");
+		return;
+	}
+
+	display = calculate_label (self);
+	_gcr_display_view_append_title (view, renderer, display);
+	g_free (display);
+
+	if (klass == CKO_PRIVATE_KEY) {
+		if (key_type == CKK_RSA)
+			text = _("Private RSA Key");
+		else if (key_type == CKK_DSA)
+			text = _("Private DSA Key");
+		else
+			text = _("Private Key");
+	} else if (klass == CKO_PUBLIC_KEY) {
+		if (key_type == CKK_RSA)
+			text = _("Public DSA Key");
+		else if (key_type == CKK_DSA)
+			text = _("Public DSA Key");
+		else
+			text = _("Public Key");
+	}
+
+	_gcr_display_view_append_content (view, renderer, text, NULL);
+
+	size = calculate_key_size (self->pv->attributes, key_type);
+	if (size >= 0) {
+		display = g_strdup_printf (_("%d bits"), size);
+		_gcr_display_view_append_content (view, renderer, _("Strength"), display);
+		g_free (display);
+	}
+
+	_gcr_display_view_start_details (view, renderer);
+
+
+	if (key_type == CKK_RSA)
+		text = _("RSA");
+	else if (key_type == CKK_DSA)
+		text = _("DSA");
+	else
+		text = _("Unknown");
+	_gcr_display_view_append_value (view, renderer, _("Algorithm"), text, FALSE);
+
+	size = calculate_key_size (self->pv->attributes, key_type);
+	if (size < 0)
+		display = g_strdup (_("Unknown"));
+	else
+		display = g_strdup_printf ("%d", size);
+	_gcr_display_view_append_value (view, renderer, _("Size"), display, FALSE);
+	g_free (display);
+
+	/* TODO: We need to have consistent key fingerprints. */
+	_gcr_display_view_append_value (view, renderer, _("Fingerprint"), "XX XX XX XX XX XX XX XX XX XX", TRUE);
+}
+
+static void
+gcr_key_renderer_renderer_iface (GcrRendererIface *iface)
+{
+	iface->render = gcr_key_renderer_real_render;
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+GcrKeyRenderer*
+gcr_key_renderer_new (const gchar *label, GckAttributes *attrs)
+{
+	return g_object_new (GCR_TYPE_KEY_RENDERER, "label", label, "attributes", attrs, NULL);
+}
+
+void
+gcr_key_renderer_set_attributes (GcrKeyRenderer *self, GckAttributes *attrs)
+{
+	g_return_if_fail (GCR_IS_KEY_RENDERER (self));
+
+	if (self->pv->attributes)
+		gck_attributes_unref (self->pv->attributes);
+	self->pv->attributes = attrs;
+	if (self->pv->attributes)
+		gck_attributes_ref (self->pv->attributes);
+
+	g_object_notify (G_OBJECT (self), "attributes");
+	gcr_renderer_emit_data_changed (GCR_RENDERER (self));
+}
+
+GckAttributes*
+gcr_key_renderer_get_attributes (GcrKeyRenderer *self)
+{
+	g_return_val_if_fail (GCR_IS_KEY_RENDERER (self), NULL);
+	return self->pv->attributes;
+}
diff --git a/gcr/gcr-key-renderer.h b/gcr/gcr-key-renderer.h
new file mode 100644
index 0000000..1d25528
--- /dev/null
+++ b/gcr/gcr-key-renderer.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GCR_KEY_RENDERER_H__
+#define __GCR_KEY_RENDERER_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gcr-types.h"
+
+G_BEGIN_DECLS
+
+#define GCR_TYPE_KEY_RENDERER               (gcr_key_renderer_get_type ())
+#define GCR_KEY_RENDERER(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_KEY_RENDERER, GcrKeyRenderer))
+#define GCR_KEY_RENDERER_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_KEY_RENDERER, GcrKeyRendererClass))
+#define GCR_IS_KEY_RENDERER(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_KEY_RENDERER))
+#define GCR_IS_KEY_RENDERER_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_KEY_RENDERER))
+#define GCR_KEY_RENDERER_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_KEY_RENDERER, GcrKeyRendererClass))
+
+typedef struct _GcrKeyRenderer GcrKeyRenderer;
+typedef struct _GcrKeyRendererClass GcrKeyRendererClass;
+typedef struct _GcrKeyRendererPrivate GcrKeyRendererPrivate;
+
+struct _GcrKeyRenderer {
+	GObject parent;
+	GcrKeyRendererPrivate *pv;
+};
+
+struct _GcrKeyRendererClass {
+	GObjectClass parent_class;
+};
+
+GType                   gcr_key_renderer_get_type             (void);
+
+GcrKeyRenderer*         gcr_key_renderer_new                  (const gchar *label,
+                                                               struct _GckAttributes *attrs);
+
+void                    gcr_key_renderer_set_attributes       (GcrKeyRenderer *self,
+                                                               struct _GckAttributes *attrs);
+
+struct _GckAttributes*  gcr_key_renderer_get_attributes       (GcrKeyRenderer *self);
+
+G_END_DECLS
+
+#endif /* __GCR_KEY_RENDERER_H__ */
diff --git a/gcr/gcr-key-widget.c b/gcr/gcr-key-widget.c
index 8f7a7b5..53fdde9 100644
--- a/gcr/gcr-key-widget.c
+++ b/gcr/gcr-key-widget.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Stefan Walter
+ * Copyright (C) 2010 Stefan Walter
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as
@@ -19,14 +19,10 @@
 
 #include "config.h"
 
+#include "gcr-key-renderer.h"
 #include "gcr-key-widget.h"
-#include "gcr-display-view.h"
-#include "gcr-icons.h"
-#include "gcr-view.h"
-
-#include "egg/egg-asn1x.h"
-#include "egg/egg-oid.h"
-#include "egg/egg-hex.h"
+#include "gcr-renderer.h"
+#include "gcr-viewer.h"
 
 #include "gck/gck.h"
 
@@ -35,163 +31,15 @@
 
 enum {
 	PROP_0,
-	PROP_LABEL,
 	PROP_ATTRIBUTES
 };
 
 struct _GcrKeyWidgetPrivate {
-	GcrDisplayView *view;
-	guint key_size;
-	gchar *label;
-	GckAttributes *attributes;
+	GcrViewer *viewer;
+	GcrKeyRenderer *renderer;
 };
 
-static void gcr_view_iface_init (GcrViewIface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (GcrKeyWidget, gcr_key_widget, GTK_TYPE_ALIGNMENT,
-                         G_IMPLEMENT_INTERFACE (GCR_TYPE_VIEW, gcr_view_iface_init));
-
-/* -----------------------------------------------------------------------------
- * INTERNAL
- */
-
-static gchar*
-calculate_label (GcrKeyWidget *self)
-{
-	gchar *label;
-
-	if (self->pv->label)
-		return g_strdup (self->pv->label);
-
-	if (self->pv->attributes) {
-		if (gck_attributes_find_string (self->pv->attributes, CKA_LABEL, &label))
-			return label;
-	}
-
-	return g_strdup (_("Key"));
-}
-
-static gint
-calculate_rsa_key_size (GckAttributes *attrs)
-{
-	GckAttribute *attr;
-	gulong bits;
-
-	attr = gck_attributes_find (attrs, CKA_MODULUS);
-
-	/* Calculate the bit length, and remove the complement */
-	if (attr != NULL)
-		return (attr->length / 2) * 2 * 8;
-
-	if (gck_attributes_find_ulong (attrs, CKA_MODULUS_BITS, &bits))
-		return (gint)bits;
-
-	return -1;
-}
-
-static guint
-calculate_dsa_key_size (GckAttributes *attrs)
-{
-	GckAttribute *attr;
-	gulong bits;
-
-	attr = gck_attributes_find (attrs, CKA_PRIME);
-
-	/* Calculate the bit length, and remove the complement */
-	if (attr != NULL)
-		return (attr->length / 2) * 2 * 8;
-
-	if (gck_attributes_find_ulong (attrs, CKA_PRIME_BITS, &bits))
-		return (gint)bits;
-
-	return -1;
-}
-
-static gint
-calculate_key_size (GckAttributes *attrs, gulong key_type)
-{
-	if (key_type == CKK_RSA)
-		return calculate_rsa_key_size (attrs);
-	else if (key_type == CKK_DSA)
-		return calculate_dsa_key_size (attrs);
-	else
-		return -1;
-}
-
-static void
-refresh_display (GcrKeyWidget *self)
-{
-	const gchar *text;
-	gchar *display;
-	gulong klass;
-	gulong key_type;
-	gint size;
-
-	if (!self->pv->view)
-		return;
-
-	_gcr_display_view_clear (self->pv->view);
-
-	if (!self->pv->attributes)
-		return;
-
-	if (!gck_attributes_find_ulong (self->pv->attributes, CKA_CLASS, &klass) ||
-	    !gck_attributes_find_ulong (self->pv->attributes, CKA_KEY_TYPE, &key_type)) {
-		g_warning ("private key does not have the CKA_CLASS and CKA_KEY_TYPE attributes");
-		return;
-	}
-
-	display = calculate_label (self);
-	_gcr_display_view_append_title (self->pv->view, display);
-	g_free (display);
-
-	if (klass == CKO_PRIVATE_KEY) {
-		if (key_type == CKK_RSA)
-			text = _("Private RSA Key");
-		else if (key_type == CKK_DSA)
-			text = _("Private DSA Key");
-		else
-			text = _("Private Key");
-	} else if (klass == CKO_PUBLIC_KEY) {
-		if (key_type == CKK_RSA)
-			text = _("Public DSA Key");
-		else if (key_type == CKK_DSA)
-			text = _("Public DSA Key");
-		else
-			text = _("Public Key");
-	}
-
-	_gcr_display_view_append_content (self->pv->view, text, NULL);
-
-	size = calculate_key_size (self->pv->attributes, key_type);
-	if (size >= 0) {
-		display = g_strdup_printf (_("%d bits"), size);
-		_gcr_display_view_append_content (self->pv->view, _("Strength"), display);
-		g_free (display);
-	}
-
-	_gcr_display_view_start_details (self->pv->view);
-
-
-	if (key_type == CKK_RSA)
-		text = _("RSA");
-	else if (key_type == CKK_DSA)
-		text = _("DSA");
-	else
-		text = _("Unknown");
-	_gcr_display_view_append_value (self->pv->view, _("Algorithm"), text, FALSE);
-
-	size = calculate_key_size (self->pv->attributes, key_type);
-	if (size < 0)
-		display = g_strdup (_("Unknown"));
-	else
-		display = g_strdup_printf ("%d", size);
-	_gcr_display_view_append_value (self->pv->view, _("Size"), display, FALSE);
-	g_free (display);
-
-	/* TODO: We need to have consistent key fingerprints. */
-	_gcr_display_view_append_value (self->pv->view, _("Fingerprint"), "XX XX XX XX XX XX XX XX XX XX", TRUE);
-}
+G_DEFINE_TYPE (GcrKeyWidget, gcr_key_widget, GTK_TYPE_ALIGNMENT);
 
 /* -----------------------------------------------------------------------------
  * OBJECT
@@ -208,19 +56,17 @@ gcr_key_widget_constructor (GType type, guint n_props, GObjectConstructParam *pr
 
 	self = GCR_KEY_WIDGET (obj);
 
-	self->pv->view = _gcr_display_view_new ();
-	_gcr_display_view_set_stock_image (self->pv->view, GTK_STOCK_DIALOG_AUTHENTICATION);
+	self->pv->viewer = gcr_viewer_new ();
 
 	scroll = gtk_scrolled_window_new (NULL, NULL);
 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_ETCHED_IN);
-	gtk_container_add (GTK_CONTAINER (scroll), GTK_WIDGET (self->pv->view));
+	gtk_container_add (GTK_CONTAINER (scroll), GTK_WIDGET (self->pv->viewer));
 
 	gtk_container_add (GTK_CONTAINER (self), scroll);
 	gtk_widget_show_all (scroll);
 
-	refresh_display (self);
-
+	gcr_viewer_add_renderer (self->pv->viewer, GCR_RENDERER (self->pv->renderer));
 	return obj;
 }
 
@@ -228,12 +74,7 @@ static void
 gcr_key_widget_init (GcrKeyWidget *self)
 {
 	self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_KEY_WIDGET, GcrKeyWidgetPrivate));
-}
-
-static void
-gcr_key_widget_dispose (GObject *obj)
-{
-	G_OBJECT_CLASS (gcr_key_widget_parent_class)->dispose (obj);
+	self->pv->renderer = gcr_key_renderer_new (NULL, NULL);
 }
 
 static void
@@ -241,12 +82,12 @@ gcr_key_widget_finalize (GObject *obj)
 {
 	GcrKeyWidget *self = GCR_KEY_WIDGET (obj);
 
-	if (self->pv->attributes)
-		gck_attributes_unref (self->pv->attributes);
-	self->pv->attributes = NULL;
+	g_assert (self->pv->renderer);
+	g_object_unref (self->pv->renderer);
+	self->pv->renderer = NULL;
 
-	g_free (self->pv->label);
-	self->pv->label = NULL;
+	g_assert (self->pv->viewer);
+	self->pv->viewer = NULL;
 
 	G_OBJECT_CLASS (gcr_key_widget_parent_class)->finalize (obj);
 }
@@ -258,15 +99,8 @@ gcr_key_widget_set_property (GObject *obj, guint prop_id, const GValue *value,
 	GcrKeyWidget *self = GCR_KEY_WIDGET (obj);
 
 	switch (prop_id) {
-	case PROP_LABEL:
-		g_free (self->pv->label);
-		self->pv->label = g_value_dup_string (value);
-		g_object_notify (obj, "label");
-		refresh_display (self);
-		break;
 	case PROP_ATTRIBUTES:
-		g_return_if_fail (!self->pv->attributes);
-		self->pv->attributes = g_value_dup_boxed (value);
+		gcr_key_widget_set_attributes (self, g_value_get_boxed (value));
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -281,11 +115,8 @@ gcr_key_widget_get_property (GObject *obj, guint prop_id, GValue *value,
 	GcrKeyWidget *self = GCR_KEY_WIDGET (obj);
 
 	switch (prop_id) {
-	case PROP_LABEL:
-		g_value_take_string (value, calculate_label (self));
-		break;
 	case PROP_ATTRIBUTES:
-		g_value_set_boxed (value, self->pv->attributes);
+		g_value_set_boxed (value, gcr_key_widget_get_attributes (self));
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -303,35 +134,41 @@ gcr_key_widget_class_init (GcrKeyWidgetClass *klass)
 	g_type_class_add_private (klass, sizeof (GcrKeyWidgetPrivate));
 
 	gobject_class->constructor = gcr_key_widget_constructor;
-	gobject_class->dispose = gcr_key_widget_dispose;
 	gobject_class->finalize = gcr_key_widget_finalize;
 	gobject_class->set_property = gcr_key_widget_set_property;
 	gobject_class->get_property = gcr_key_widget_get_property;
 
-	g_object_class_override_property (gobject_class, PROP_LABEL, "label");
-	g_object_class_override_property (gobject_class, PROP_ATTRIBUTES, "attributes");
-
-	_gcr_icons_register ();
+	g_object_class_install_property (gobject_class, PROP_ATTRIBUTES,
+	         g_param_spec_boxed ("attributes", "Attributes", "The data displayed in the widget",
+	                             GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE));
 
 	/* Register this as a view which can be loaded */
 	registered = gck_attributes_new ();
 	gck_attributes_add_ulong (registered, CKA_CLASS, CKO_PRIVATE_KEY);
-	gcr_view_register (GCR_TYPE_KEY_WIDGET, registered);
+	gcr_renderer_register (GCR_TYPE_KEY_WIDGET, registered);
 	gck_attributes_unref (registered);
 }
 
-static void
-gcr_view_iface_init (GcrViewIface *iface)
-{
-	/* Nothing to do */
-}
-
 /* -----------------------------------------------------------------------------
  * PUBLIC
  */
 
 GcrKeyWidget*
-gcr_key_widget_new (const gchar *label, GckAttributes *attrs)
+gcr_key_widget_new (GckAttributes *attrs)
+{
+	return g_object_new (GCR_TYPE_KEY_WIDGET, "attributes", attrs, NULL);
+}
+
+void
+gcr_key_widget_set_attributes (GcrKeyWidget *self, GckAttributes *attrs)
+{
+	g_return_if_fail (GCR_IS_KEY_WIDGET (self));
+	gcr_key_renderer_set_attributes (self->pv->renderer, attrs);
+}
+
+GckAttributes*
+gcr_key_widget_get_attributes (GcrKeyWidget *self)
 {
-	return g_object_new (GCR_TYPE_KEY_WIDGET, "label", label, "attributes", attrs, NULL);
+	g_return_val_if_fail (GCR_IS_KEY_WIDGET (self), NULL);
+	return gcr_key_renderer_get_attributes (self->pv->renderer);
 }
diff --git a/gcr/gcr-key-widget.h b/gcr/gcr-key-widget.h
index 34aefa0..5393e02 100644
--- a/gcr/gcr-key-widget.h
+++ b/gcr/gcr-key-widget.h
@@ -49,9 +49,13 @@ struct _GcrKeyWidgetClass {
 
 GType                   gcr_key_widget_get_type               (void);
 
-GcrKeyWidget*           gcr_key_widget_new                    (const gchar *label,
+GcrKeyWidget*           gcr_key_widget_new                    (struct _GckAttributes *attrs);
+
+void                    gcr_key_widget_set_attributes         (GcrKeyWidget *self,
                                                                struct _GckAttributes *attrs);
 
+struct _GckAttributes*  gcr_key_widget_get_attributes         (GcrKeyWidget *self);
+
 G_END_DECLS
 
 #endif /* __GCR_KEY_WIDGET_H__ */
diff --git a/gcr/gcr-view.c b/gcr/gcr-renderer.c
similarity index 53%
rename from gcr/gcr-view.c
rename to gcr/gcr-renderer.c
index 9df6606..59ca30a 100644
--- a/gcr/gcr-view.c
+++ b/gcr/gcr-renderer.c
@@ -21,60 +21,85 @@
 
 #include "config.h"
 
-#include "gcr-view.h"
+#include "gcr-renderer.h"
 
 #include "gck/gck.h"
 
 #include <gtk/gtk.h>
 
-typedef struct _GcrRegisteredView {
+enum {
+	DATA_CHANGED,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+typedef struct _GcrRegistered {
 	GckAttributes *attrs;
-	GType view_type;
-} GcrRegisteredView;
+	GType renderer_type;
+} GcrRegistered;
 
-static GArray *registered_views = NULL;
+static GArray *registered_renderers = NULL;
 static gboolean registered_sorted = FALSE;
 
 static void
-gcr_view_base_init (gpointer gobject_iface)
+gcr_renderer_base_init (gpointer gobject_iface)
 {
 	static gboolean initialized = FALSE;
 	if (!initialized) {
 
 		g_object_interface_install_property (gobject_iface,
-		         g_param_spec_string ("label", "Label", "The label for the view",
+		         g_param_spec_string ("label", "Label", "The label for the renderer",
 		                              "", G_PARAM_READWRITE));
 
 		g_object_interface_install_property (gobject_iface,
-		         g_param_spec_boxed ("attributes", "Attributes", "The data displayed in the view",
-		                             GCK_TYPE_ATTRIBUTES, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+		         g_param_spec_boxed ("attributes", "Attributes", "The data displayed in the renderer",
+		                             GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE));
+
+		signals[DATA_CHANGED] = g_signal_new ("data-changed", GCR_TYPE_RENDERER, G_SIGNAL_RUN_LAST,
+		                                      G_STRUCT_OFFSET (GcrRendererIface, data_changed),
+		                                      NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
 
 		initialized = TRUE;
 	}
 }
 
 GType
-gcr_view_get_type (void)
+gcr_renderer_get_type (void)
 {
 	static GType type = 0;
 	if (!type) {
 		static const GTypeInfo info = {
-			sizeof (GcrViewIface),
-			gcr_view_base_init,  /* base init */
-			NULL,                /* base finalize */
+			sizeof (GcrRendererIface),
+			gcr_renderer_base_init,  /* base init */
+			NULL,                    /* base finalize */
 		};
-		type = g_type_register_static (G_TYPE_INTERFACE, "GcrViewIface", &info, 0);
-		g_type_interface_add_prerequisite (type, GTK_TYPE_WIDGET);
+		type = g_type_register_static (G_TYPE_INTERFACE, "GcrRendererIface", &info, 0);
 	}
 
 	return type;
 }
 
+void
+gcr_renderer_render (GcrRenderer *self, GcrViewer *viewer)
+{
+	g_return_if_fail (GCR_IS_RENDERER (self));
+	g_return_if_fail (GCR_RENDERER_GET_INTERFACE (self)->render);
+	GCR_RENDERER_GET_INTERFACE (self)->render (self, viewer);
+}
+
+void
+gcr_renderer_emit_data_changed (GcrRenderer *self)
+{
+	g_return_if_fail (GCR_IS_RENDERER (self));
+	g_signal_emit (self, signals[DATA_CHANGED], 0);
+}
+
 static gint
 sort_registered_by_n_attrs (gconstpointer a, gconstpointer b)
 {
-	const GcrRegisteredView *ra = a;
-	const GcrRegisteredView *rb = b;
+	const GcrRegistered *ra = a;
+	const GcrRegistered *rb = b;
 	gulong na, nb;
 
 	g_assert (a);
@@ -89,10 +114,10 @@ sort_registered_by_n_attrs (gconstpointer a, gconstpointer b)
 	return (na == nb) ? 0 : -1;
 }
 
-GcrView*
-gcr_view_create (const gchar *label, GckAttributes *attrs)
+GcrRenderer*
+gcr_renderer_create (const gchar *label, GckAttributes *attrs)
 {
-	GcrRegisteredView *registered;
+	GcrRegistered *registered;
 	gboolean matched;
 	gulong n_attrs;
 	gulong j;
@@ -100,16 +125,16 @@ gcr_view_create (const gchar *label, GckAttributes *attrs)
 
 	g_return_val_if_fail (attrs, NULL);
 
-	if (!registered_views)
+	if (!registered_renderers)
 		return NULL;
 
 	if (!registered_sorted) {
-		g_array_sort (registered_views, sort_registered_by_n_attrs);
+		g_array_sort (registered_renderers, sort_registered_by_n_attrs);
 		registered_sorted = TRUE;
 	}
 
-	for (i = 0; i < registered_views->len; ++i) {
-		registered = &(g_array_index (registered_views, GcrRegisteredView, i));
+	for (i = 0; i < registered_renderers->len; ++i) {
+		registered = &(g_array_index (registered_renderers, GcrRegistered, i));
 		n_attrs = gck_attributes_count (registered->attrs);
 
 		matched = TRUE;
@@ -122,7 +147,7 @@ gcr_view_create (const gchar *label, GckAttributes *attrs)
 		}
 
 		if (matched)
-			return g_object_new (registered->view_type, "label", label,
+			return g_object_new (registered->renderer_type, "label", label,
 			                     "attributes", attrs, NULL);
 	}
 
@@ -130,15 +155,15 @@ gcr_view_create (const gchar *label, GckAttributes *attrs)
 }
 
 void
-gcr_view_register (GType view_type, GckAttributes *attrs)
+gcr_renderer_register (GType renderer_type, GckAttributes *attrs)
 {
-	GcrRegisteredView registered;
+	GcrRegistered registered;
 
-	if (!registered_views)
-		registered_views = g_array_new (FALSE, FALSE, sizeof (GcrRegisteredView));
+	if (!registered_renderers)
+		registered_renderers = g_array_new (FALSE, FALSE, sizeof (GcrRegistered));
 
-	registered.view_type = view_type;
+	registered.renderer_type = renderer_type;
 	registered.attrs = gck_attributes_ref (attrs);
-	g_array_append_val (registered_views, registered);
+	g_array_append_val (registered_renderers, registered);
 	registered_sorted = FALSE;
 }
diff --git a/gcr/gcr-renderer.h b/gcr/gcr-renderer.h
new file mode 100644
index 0000000..9c4800a
--- /dev/null
+++ b/gcr/gcr-renderer.h
@@ -0,0 +1,73 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2010 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GCR_RENDERER_H__
+#define __GCR_RENDERER_H__
+
+#include <glib-object.h>
+
+#include "gcr-types.h"
+#include "gcr-viewer.h"
+
+G_BEGIN_DECLS
+
+#define GCR_TYPE_RENDERER                 (gcr_renderer_get_type())
+#define GCR_RENDERER(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_RENDERER, GcrRenderer))
+#define GCR_IS_RENDERER(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_RENDERER))
+#define GCR_RENDERER_GET_INTERFACE(inst)  (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GCR_TYPE_RENDERER, GcrRendererIface))
+
+typedef struct _GcrRendererIface GcrRendererIface;
+
+struct _GcrRendererIface {
+	GTypeInterface parent;
+
+	/* signals */
+	void (*data_changed) (GcrRenderer *self);
+
+	/* virtual */
+	void (*render) (GcrRenderer *self, GcrViewer *viewer);
+
+	gpointer dummy1;
+	gpointer dummy2;
+	gpointer dummy3;
+	gpointer dummy4;
+	gpointer dummy5;
+	gpointer dummy6;
+	gpointer dummy7;
+
+};
+
+GType                  gcr_renderer_get_type                      (void) G_GNUC_CONST;
+
+void                   gcr_renderer_render                        (GcrRenderer *self,
+                                                                   GcrViewer *viewer);
+
+void                   gcr_renderer_emit_data_changed             (GcrRenderer *self);
+
+GcrRenderer*           gcr_renderer_create                        (const gchar *label,
+                                                                   struct _GckAttributes *attrs);
+
+void                   gcr_renderer_register                      (GType renderer_type,
+                                                                   struct _GckAttributes *attrs);
+
+G_END_DECLS
+
+#endif /* __GCR_RENDERER_H__ */
diff --git a/gcr/gcr-viewer.c b/gcr/gcr-viewer.c
new file mode 100644
index 0000000..03a5a4b
--- /dev/null
+++ b/gcr/gcr-viewer.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gcr-display-view.h"
+#include "gcr-renderer.h"
+#include "gcr-viewer.h"
+
+/* -----------------------------------------------------------------------------
+ * INTERFACE
+ */
+
+static void
+gcr_viewer_base_init (gpointer gobject_iface)
+{
+	static gboolean initialized = FALSE;
+	if (!initialized) {
+
+		initialized = TRUE;
+	}
+}
+
+GType
+gcr_viewer_get_type (void)
+{
+	static GType type = 0;
+	if (!type) {
+		static const GTypeInfo info = {
+			sizeof (GcrViewerIface),
+			gcr_viewer_base_init,  /* base init */
+			NULL,                  /* base finalize */
+		};
+		type = g_type_register_static (G_TYPE_INTERFACE, "GcrViewerIface", &info, 0);
+		g_type_interface_add_prerequisite (type, GTK_TYPE_WIDGET);
+	}
+
+	return type;
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+GcrViewer*
+gcr_viewer_new (void)
+{
+	return GCR_VIEWER (_gcr_display_view_new ());
+}
+
+void
+gcr_viewer_add_renderer (GcrViewer *self, GcrRenderer *renderer)
+{
+	g_return_if_fail (GCR_IS_VIEWER (self));
+	g_return_if_fail (GCR_IS_RENDERER (renderer));
+	g_return_if_fail (GCR_VIEWER_GET_INTERFACE (self)->add_renderer);
+	GCR_VIEWER_GET_INTERFACE (self)->add_renderer (self, renderer);
+}
+
+void
+gcr_viewer_remove_renderer (GcrViewer *self, GcrRenderer *renderer)
+{
+	g_return_if_fail (GCR_IS_VIEWER (self));
+	g_return_if_fail (GCR_IS_RENDERER (renderer));
+	g_return_if_fail (GCR_VIEWER_GET_INTERFACE (self)->remove_renderer);
+	GCR_VIEWER_GET_INTERFACE (self)->remove_renderer (self, renderer);
+}
+
+guint
+gcr_viewer_count_renderers (GcrViewer *self)
+{
+	g_return_val_if_fail (GCR_IS_VIEWER (self), 0);
+	g_return_val_if_fail (GCR_VIEWER_GET_INTERFACE (self)->count_renderers, 0);
+	return GCR_VIEWER_GET_INTERFACE (self)->count_renderers (self);
+}
+
+GcrRenderer*
+gcr_viewer_get_renderer (GcrViewer *self, guint index_)
+{
+	g_return_val_if_fail (GCR_IS_VIEWER (self), NULL);
+	g_return_val_if_fail (GCR_VIEWER_GET_INTERFACE (self)->get_renderer, NULL);
+	return GCR_VIEWER_GET_INTERFACE (self)->get_renderer (self, index_);
+}
diff --git a/gcr/gcr-viewer.h b/gcr/gcr-viewer.h
new file mode 100644
index 0000000..6f53bdb
--- /dev/null
+++ b/gcr/gcr-viewer.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GCR_VIEWER_H__
+#define __GCR_VIEWER_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gcr-types.h"
+
+G_BEGIN_DECLS
+
+#define GCR_TYPE_VIEWER                 (gcr_viewer_get_type())
+#define GCR_VIEWER(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_VIEWER, GcrViewer))
+#define GCR_IS_VIEWER(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_VIEWER))
+#define GCR_VIEWER_GET_INTERFACE(inst)  (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GCR_TYPE_VIEWER, GcrViewerIface))
+
+typedef struct _GcrRenderer    GcrRenderer;
+typedef struct _GcrViewer      GcrViewer;
+typedef struct _GcrViewerIface GcrViewerIface;
+
+struct _GcrViewerIface {
+	GTypeInterface parent;
+
+	void (*add_renderer) (GcrViewer *self, GcrRenderer *viewer);
+
+	void (*remove_renderer) (GcrViewer *self, GcrRenderer *viewer);
+
+	guint (*count_renderers) (GcrViewer *self);
+
+	GcrRenderer* (*get_renderer) (GcrViewer *self, guint index_);
+
+	gpointer dummy1;
+	gpointer dummy2;
+	gpointer dummy3;
+	gpointer dummy4;
+};
+
+GType                   gcr_viewer_get_type               (void);
+
+GcrViewer*              gcr_viewer_new                    (void);
+
+void                    gcr_viewer_add_renderer           (GcrViewer *self,
+                                                           GcrRenderer *renderer);
+
+void                    gcr_viewer_remove_renderer        (GcrViewer *self,
+                                                           GcrRenderer *renderer);
+
+guint                   gcr_viewer_count_renderers        (GcrViewer *self);
+
+GcrRenderer*            gcr_viewer_get_renderer           (GcrViewer *self,
+                                                           guint at);
+
+G_END_DECLS
+
+#endif /* __GCR_VIEWER_H__ */
diff --git a/gcr/tests/ui-test-certificate.c b/gcr/tests/ui-test-certificate.c
index fdec278..bf12e72 100644
--- a/gcr/tests/ui-test-certificate.c
+++ b/gcr/tests/ui-test-certificate.c
@@ -41,7 +41,6 @@ on_parser_parsed (GcrParser *parser, gpointer unused)
 	g_object_ref_sink (dialog);
 
 	details = g_object_new (GCR_TYPE_CERTIFICATE_WIDGET,
-	                        "label", "Google's Certificate",
 	                        "attributes", gcr_parser_get_parsed_attributes (parser),
 	                        NULL);
 
diff --git a/gcr/tests/ui-test-key.c b/gcr/tests/ui-test-key.c
index e54c7b4..4ccba3e 100644
--- a/gcr/tests/ui-test-key.c
+++ b/gcr/tests/ui-test-key.c
@@ -40,8 +40,7 @@ on_parser_parsed (GcrParser *parser, gpointer unused)
 	dialog = GTK_DIALOG (gtk_dialog_new ());
 	g_object_ref_sink (dialog);
 
-	details = gcr_key_widget_new ("My Private Key",
-	                              gcr_parser_get_parsed_attributes (parser));
+	details = gcr_key_widget_new (gcr_parser_get_parsed_attributes (parser));
 	gtk_widget_show (GTK_WIDGET (details));
 	gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (dialog)), GTK_WIDGET (details));
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]