[gnome-keyring] gcr: Add support for unlocking files in gcr-viewer



commit 02dd8275c8afa984c0389da1088abb680bdb9aa3
Author: Stef Walter <stefw collabora co uk>
Date:   Wed Aug 31 15:30:58 2011 +0200

    gcr: Add support for unlocking files in gcr-viewer
    
     * Add a GcrRenderer which displays unlock widgets
     * Add method to GcrViewer which allows insertion of renderer before another
     * Functionality in GcrDisplayView for showing dialog like widgets in view
     * Fixes for removing renderer from view
     * Parser fixes for enabling all formats
     * Parser fixes for PKCS#12 parsing with locked data

 .gitignore                 |    1 +
 gcr/Makefile.am            |    1 +
 gcr/gcr-display-scrolled.c |   10 ++
 gcr/gcr-display-view.c     |  141 ++++++++++++++---
 gcr/gcr-display-view.h     |    4 +
 gcr/gcr-parser.c           |   43 +++--
 gcr/gcr-unlock-renderer.c  |  368 ++++++++++++++++++++++++++++++++++++++++++++
 gcr/gcr-unlock-renderer.h  |   69 ++++++++
 gcr/gcr-viewer-window.c    |  125 ++++++++++++++-
 gcr/gcr-viewer.c           |   56 +++++---
 gcr/gcr-viewer.h           |   27 +++-
 gcr/gcr.h                  |    1 +
 gcr/tests/Makefile.am      |    3 +-
 gcr/tests/frob-unlock.c    |  111 +++++++++++++
 14 files changed, 885 insertions(+), 75 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 186ca98..d2fc41a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -121,6 +121,7 @@ run-tests
 /gcr/tests/frob-tree-selector
 /gcr/tests/frob-unlock-options
 /gcr/tests/frob-parser
+/gcr/tests/frob-unlock
 /gcr/tests/test-certificate
 /gcr/tests/test-certificate-chain
 /gcr/tests/test-colons
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index 7d0404a..c6e626e 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -122,6 +122,7 @@ libgcr_ GCR_MAJOR@_la_SOURCES = \
 	gcr-types.h \
 	gcr-unlock-options.h \
 	gcr-unlock-options-widget.c gcr-unlock-options-widget.h \
+	gcr-unlock-renderer.c gcr-unlock-renderer.h \
 	gcr-util.c gcr-util.h \
 	gcr-viewer.c gcr-viewer.h \
 	gcr-viewer-window.c gcr-viewer-window.h \
diff --git a/gcr/gcr-display-scrolled.c b/gcr/gcr-display-scrolled.c
index 3de3111..49d2dd9 100644
--- a/gcr/gcr-display-scrolled.c
+++ b/gcr/gcr-display-scrolled.c
@@ -126,6 +126,15 @@ _gcr_display_scrolled_real_add_renderer (GcrViewer *viewer, GcrRenderer *rendere
 }
 
 static void
+_gcr_display_scrolled_real_insert_renderer (GcrViewer *viewer,
+                                            GcrRenderer *renderer,
+                                            GcrRenderer *before)
+{
+	GcrDisplayScrolled *self = GCR_DISPLAY_SCROLLED (viewer);
+	gcr_viewer_insert_renderer (self->pv->internal, renderer, before);
+}
+
+static void
 _gcr_display_scrolled_real_remove_renderer (GcrViewer *viewer, GcrRenderer *renderer)
 {
 	GcrDisplayScrolled *self = GCR_DISPLAY_SCROLLED (viewer);
@@ -150,6 +159,7 @@ static void
 _gcr_display_scrolled_viewer_iface (GcrViewerIface *iface)
 {
 	iface->add_renderer = _gcr_display_scrolled_real_add_renderer;
+	iface->insert_renderer = _gcr_display_scrolled_real_insert_renderer;
 	iface->remove_renderer = _gcr_display_scrolled_real_remove_renderer;
 	iface->count_renderers = _gcr_display_scrolled_real_count_renderers;
 	iface->get_renderer = _gcr_display_scrolled_real_get_renderer;
diff --git a/gcr/gcr-display-view.c b/gcr/gcr-display-view.c
index b6cec63..035a3a7 100644
--- a/gcr/gcr-display-view.c
+++ b/gcr/gcr-display-view.c
@@ -34,6 +34,7 @@ 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 ZWSP "\342\200\213"
 #define NORMAL_MARGIN 10
 #define FIELD_MARGIN 17
 #define COLUMN_MARGIN 6
@@ -47,6 +48,7 @@ typedef struct _GcrDisplayItem {
 	GtkTextMark *beginning;
 	GtkTextMark *ending;
 	GtkWidget *details_widget;
+	GtkTextChildAnchor *area_anchor;
 	GtkTextTag *extra_tag;
 	gint field_width;
 	GdkPixbuf *pixbuf;
@@ -63,6 +65,7 @@ struct _GcrDisplayViewPrivate {
 	GtkTextTag *content_tag;
 	GtkTextTag *heading_tag;
 	GtkTextTag *monospace_tag;
+	GtkTextTag *area_tag;
 	GcrDisplayItem *current_item;
 	gint text_height;
 	GdkCursor *cursor;
@@ -187,6 +190,7 @@ create_tag_table (GcrDisplayView *self)
 	                                      "right-margin", (ICON_MARGIN * 2) + width,
 	                                      "left-margin", FIELD_MARGIN,
 	                                      "pixels-below-lines", 3,
+	                                      "wrap-mode", GTK_WRAP_WORD,
 	                                      NULL);
 	gtk_text_tag_table_add (tags, self->pv->content_tag);
 
@@ -204,6 +208,12 @@ create_tag_table (GcrDisplayView *self)
 	                                        NULL);
 	gtk_text_tag_table_add (tags, self->pv->monospace_tag);
 
+	self->pv->area_tag = g_object_new (GTK_TYPE_TEXT_TAG,
+	                                   "name", "area",
+	                                   "justification", GTK_JUSTIFY_CENTER,
+	                                   NULL);
+	gtk_text_tag_table_add (tags, self->pv->area_tag);
+
 	return tags;
 }
 
@@ -277,7 +287,7 @@ create_display_item (GcrDisplayView *self, GcrRenderer *renderer)
 	gtk_text_tag_table_add (tags, item->details_tag);
 
 	/*
-	 * Add two zero width spaces that delimit this from later items. The
+	 * Add two lines space that delimit this from later items. The
 	 * item will live between the two zero width spaces.
 	 */
 	gtk_text_buffer_get_end_iter (self->pv->buffer, &iter);
@@ -316,8 +326,6 @@ create_display_item (GcrDisplayView *self, GcrRenderer *renderer)
 	if (gtk_widget_get_realized (GTK_WIDGET (self)))
 		style_display_item (GTK_WIDGET (self), item);
 
-	/* TODO: Initialize the rest of the fields */
-
 	return item;
 }
 
@@ -325,6 +333,7 @@ static void
 destroy_display_item (gpointer data)
 {
 	GcrDisplayItem *item = data;
+	GtkTextIter iter, end;
 	GtkTextTagTable *tags;
 	GcrDisplayView *self;
 
@@ -348,12 +357,22 @@ destroy_display_item (gpointer data)
 	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_clear_object (&item->area_anchor);
 
+	g_return_if_fail (!gtk_text_mark_get_deleted (item->beginning));
 	g_return_if_fail (!gtk_text_mark_get_deleted (item->ending));
+
+	/* Setup iters to encompass our delemiter characters see create_display_item() */
+	gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->beginning);
+	gtk_text_iter_backward_char (&iter);
+	gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &end, item->ending);
+	gtk_text_iter_forward_char (&end);
+	gtk_text_buffer_delete (self->pv->buffer, &iter, &end);
+
+	gtk_text_buffer_delete_mark (self->pv->buffer, item->beginning);
 	gtk_text_buffer_delete_mark (self->pv->buffer, item->ending);
+
+	g_object_unref (item->beginning);
 	g_object_unref (item->ending);
 
 	g_free (item);
@@ -392,10 +411,17 @@ find_item_at_iter (GcrDisplayView *self, GtkTextIter *iter)
 }
 
 static void
-on_renderer_data_changed (GcrRenderer *renderer, GcrViewer *self)
+on_renderer_data_changed (GcrRenderer *renderer,
+                          gpointer user_data)
 {
+	GcrDisplayView *self = GCR_DISPLAY_VIEW (user_data);
+
+	/* Item may be removed, but not yet destroyed */
+	if (!g_hash_table_lookup (self->pv->items, renderer))
+		return;
+
 	/* Just ask the renderer to render itself on us */
-	gcr_renderer_render_view (renderer, self);
+	gcr_renderer_render_view (renderer, GCR_VIEWER (self));
 }
 
 static void
@@ -443,20 +469,26 @@ paint_item_border (GcrDisplayView *self,
 {
 	GdkRGBA color;
 	GtkTextView *view;
-	GtkTextIter iter;
+	GtkTextIter iter, end;
 	GdkRectangle location;
 
 	if (index == 0)
 		return;
 
+	view = GTK_TEXT_VIEW (self);
+	gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->beginning);
+	gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &end, item->ending);
+
+	/* Don't paint for non-visible items */
+	if (gtk_text_iter_compare (&iter, &end) == 0)
+		return;
+
 	ensure_text_height (self);
 
 	gtk_style_context_get_background_color (context,
 	                                        GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED,
 	                                        &color);
 
-	view = GTK_TEXT_VIEW (self);
-	gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->beginning);
 	gtk_text_view_get_iter_location (view, &iter, &location);
 
 	location.height = 2;
@@ -728,13 +760,39 @@ _gcr_display_view_class_init (GcrDisplayViewClass *klass)
 }
 
 static void
-_gcr_display_view_real_add_renderer (GcrViewer *viewer, GcrRenderer *renderer)
+_gcr_display_view_real_insert_renderer (GcrViewer *viewer,
+                                        GcrRenderer *renderer,
+                                        GcrRenderer *before)
 {
 	GcrDisplayView *self = GCR_DISPLAY_VIEW (viewer);
 	GcrDisplayItem *item;
+	guint i;
+
+	if (before != NULL)
+		g_return_if_fail (g_hash_table_lookup (self->pv->items, before) != NULL);
 
 	item = create_display_item (self, renderer);
-	g_ptr_array_add (self->pv->renderers, g_object_ref (renderer));
+	g_object_ref (renderer);
+
+	/* Insert it at the right place */
+	if (before != NULL) {
+		g_ptr_array_add (self->pv->renderers, NULL);
+		for (i = self->pv->renderers->len; i > 0; i--) {
+			self->pv->renderers->pdata[i] = self->pv->renderers->pdata[i - 1];
+			if (self->pv->renderers->pdata[i] == before) {
+				self->pv->renderers->pdata[i - 1] = renderer;
+				break;
+			}
+		}
+
+		/* Must have been found */
+		g_assert (i > 0);
+
+	/* No before, just add to end */
+	} else {
+		g_ptr_array_add (self->pv->renderers, renderer);
+	}
+
 	g_hash_table_insert (self->pv->items, renderer, item);
 
 	gcr_renderer_render_view (renderer, viewer);
@@ -743,6 +801,12 @@ _gcr_display_view_real_add_renderer (GcrViewer *viewer, GcrRenderer *renderer)
 }
 
 static void
+_gcr_display_view_real_add_renderer (GcrViewer *viewer, GcrRenderer *renderer)
+{
+	_gcr_display_view_real_insert_renderer (viewer, renderer, NULL);
+}
+
+static void
 _gcr_display_view_real_remove_renderer (GcrViewer *viewer, GcrRenderer *renderer)
 {
 	GcrDisplayView *self = GCR_DISPLAY_VIEW (viewer);
@@ -782,6 +846,7 @@ static void
 _gcr_display_view_viewer_iface (GcrViewerIface *iface)
 {
 	iface->add_renderer = (gpointer)_gcr_display_view_real_add_renderer;
+	iface->insert_renderer = (gpointer)_gcr_display_view_real_insert_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;
@@ -803,13 +868,27 @@ _gcr_display_view_begin (GcrDisplayView *self,
 {
 	GtkTextIter start, iter;
 	GcrDisplayItem *item;
+	GList *widgets, *l;
 
 	g_return_if_fail (GCR_IS_DISPLAY_VIEW (self));
 	item = lookup_display_item (self, renderer);
 	g_return_if_fail (item);
 
+	/* Remove the details widget so it doesn't get destroyed */
 	if (gtk_widget_get_parent (item->details_widget))
 		gtk_container_remove (GTK_CONTAINER (self), item->details_widget);
+
+	/* Remove area widgets so they don't get destroyed unnecessarily */
+	if (item->area_anchor) {
+		g_assert (!gtk_text_child_anchor_get_deleted (item->area_anchor));
+		widgets = gtk_text_child_anchor_get_widgets (item->area_anchor);
+		for (l = widgets; l != NULL; l = g_list_next (l))
+			gtk_container_remove (GTK_CONTAINER (self), l->data);
+		g_list_free (widgets);
+		g_object_unref (item->area_anchor);
+		item->area_anchor = NULL;
+	}
+
 	gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &start, item->beginning);
 	gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->ending);
 	gtk_text_buffer_delete (self->pv->buffer, &start, &iter);
@@ -823,20 +902,11 @@ void
 _gcr_display_view_end (GcrDisplayView *self,
                        GcrRenderer *renderer)
 {
-	GtkTextIter start, iter;
 	GcrDisplayItem *item;
 
 	g_return_if_fail (GCR_IS_DISPLAY_VIEW (self));
 	item = lookup_display_item (self, renderer);
 	g_return_if_fail (item);
-
-	gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &start, item->beginning);
-	gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->ending);
-
-#if 0
-	if (gtk_text_iter_compare (&start, &iter) != 0)
-		gtk_text_buffer_insert (self->pv->buffer, &iter, "\n", 1);
-#endif
 }
 
 void
@@ -1073,3 +1143,30 @@ _gcr_display_view_set_icon (GcrDisplayView *self, GcrRenderer *renderer, GIcon *
 		gtk_icon_info_free (info);
 	}
 }
+
+void
+_gcr_display_view_add_widget_area (GcrDisplayView *self,
+                                   GcrRenderer *renderer,
+                                   GtkWidget *area)
+{
+	GtkTextIter iter, start;
+	GcrDisplayItem *item;
+
+	g_return_if_fail (GCR_IS_DISPLAY_VIEW (self));
+	g_return_if_fail (GTK_IS_WIDGET (area));
+
+	item = lookup_display_item (self, renderer);
+	g_return_if_fail (item != NULL);
+	g_return_if_fail (item->area_anchor == NULL);
+
+	gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &start, item->ending);
+	iter = start;
+
+	gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, "\n" ZWSP, -1, self->pv->area_tag, NULL);
+	gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->ending);
+
+	item->area_anchor = gtk_text_buffer_create_child_anchor (self->pv->buffer, &iter);
+	g_object_ref (item->area_anchor);
+	gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (self), area, item->area_anchor);
+	gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, ZWSP "\n", -1, self->pv->area_tag, NULL);
+}
diff --git a/gcr/gcr-display-view.h b/gcr/gcr-display-view.h
index f697e59..d1c84f7 100644
--- a/gcr/gcr-display-view.h
+++ b/gcr/gcr-display-view.h
@@ -100,6 +100,10 @@ void             _gcr_display_view_set_icon                    (GcrDisplayView *
                                                                 GcrRenderer *renderer,
                                                                 GIcon *icon);
 
+void             _gcr_display_view_add_widget_area             (GcrDisplayView *self,
+                                                                GcrRenderer *render,
+                                                                GtkWidget *area);
+
 G_END_DECLS
 
 #endif /* __GCR_DISPLAY_VIEW_H__ */
diff --git a/gcr/gcr-parser.c b/gcr/gcr-parser.c
index 2ad68ab..00c7e39 100644
--- a/gcr/gcr-parser.c
+++ b/gcr/gcr-parser.c
@@ -1004,7 +1004,7 @@ handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
 		
 		/* We assume unrecognized data is a bad encryption key */	
 	}
-		
+
 done:
 	if (cih)
 		gcry_cipher_close (cih);
@@ -1077,8 +1077,10 @@ handle_pkcs12_safe (GcrParser *self, const guchar *data, gsize n_data)
 			g_warning ("unrecognized type of safe content in pkcs12: %s", g_quark_to_string (oid));
 			r = GCR_ERROR_UNRECOGNIZED;
 		}
-		
-		if (r == GCR_ERROR_FAILURE || r == GCR_ERROR_CANCELLED) {
+
+		if (r == GCR_ERROR_FAILURE ||
+		    r == GCR_ERROR_CANCELLED ||
+		    r == GCR_ERROR_LOCKED) {
 			ret = r;
 			goto done;
 		}
@@ -1134,8 +1136,12 @@ parse_der_pkcs12 (GcrParser *self, const guchar *data, gsize n_data)
 	if (!content)
 		goto done;
 
+	parsing_begin (self, 0, data, n_data);
+
 	ret = handle_pkcs12_safe (self, content, n_content);
 
+	parsing_end (self);
+
 done:
 	g_free (content);
 	egg_asn1x_destroy (asn_content);
@@ -1762,28 +1768,29 @@ gcr_parser_parse_data (GcrParser *self, gconstpointer data,
 void
 gcr_parser_format_enable (GcrParser *self, gint format_id)
 {
-	ParserFormat *format;
+	const ParserFormat *format;
+	guint i;
 
 	g_return_if_fail (GCR_IS_PARSER (self));
 
-	if (format_id == -1) {
-		if (self->pv->specific_formats)
-			g_tree_destroy (self->pv->specific_formats);
-		self->pv->specific_formats = NULL;
-		self->pv->normal_formats = TRUE;
-		return;
+	if (format_id != -1) {
+		format = parser_format_lookup (format_id);
+		g_return_if_fail (format);
 	}
 
-	format = parser_format_lookup (format_id);
-	g_return_if_fail (format);
-
-	if (!self->pv->specific_formats) {
-		if (self->pv->normal_formats)
-			return;
+	if (!self->pv->specific_formats)
 		self->pv->specific_formats = g_tree_new (compare_pointers);
-	}
 
-	g_tree_insert (self->pv->specific_formats, format, format);
+	if (format_id != -1) {
+		g_tree_insert (self->pv->specific_formats,
+		               (gpointer)format, (gpointer)format);
+	} else {
+		for (i = 0; i < G_N_ELEMENTS (parser_formats); i++) {
+			format = &parser_formats[i];
+			g_tree_insert (self->pv->specific_formats, (gpointer)format,
+			               (gpointer)format);
+		}
+	}
 }
 
 /**
diff --git a/gcr/gcr-unlock-renderer.c b/gcr/gcr-unlock-renderer.c
new file mode 100644
index 0000000..b30d922
--- /dev/null
+++ b/gcr/gcr-unlock-renderer.c
@@ -0,0 +1,368 @@
+/*
+ * 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-display-view.h"
+#include "gcr-icons.h"
+#include "gcr-parser.h"
+#include "gcr-unlock-renderer.h"
+
+#include "egg/egg-entry-buffer.h"
+
+#include <gdk/gdk.h>
+#include <glib/gi18n-lib.h>
+
+enum {
+	PROP_0,
+	PROP_LABEL,
+	PROP_ATTRIBUTES
+};
+
+struct _GcrUnlockRendererPrivate {
+	GtkEntry *entry;
+	GtkLabel *warning;
+
+	gpointer locked_data;
+	gsize n_locked_data;
+	gchar *label;
+	gboolean unlocked;
+	GList *renderers;
+	guint unlock_tries;
+
+	/* block widget destroys during render */
+	gint no_destroy;
+};
+
+static void gcr_renderer_iface_init (GcrRendererIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GcrUnlockRenderer, _gcr_unlock_renderer, GTK_TYPE_ALIGNMENT,
+	G_IMPLEMENT_INTERFACE (GCR_TYPE_RENDERER, gcr_renderer_iface_init);
+);
+
+static gchar*
+calculate_label (GcrUnlockRenderer *self)
+{
+	if (self->pv->label)
+		return g_strdup_printf (_("Unlock: %s"), self->pv->label);
+
+	return g_strdup (_("Unlock"));
+}
+
+static gboolean
+on_parser_authenticate (GcrParser *parser,
+                        gint count,
+                        gpointer user_data)
+{
+	GcrUnlockRenderer *self = GCR_UNLOCK_RENDERER (user_data);
+
+	/* On the first try, pass unlock password back to parser */
+	if (count == 0)
+		gcr_parser_add_password (parser, gtk_entry_get_text (self->pv->entry));
+
+	return TRUE;
+}
+
+static void
+on_parser_parsed (GcrParser *parser,
+                  gpointer user_data)
+{
+	GcrUnlockRenderer *self = GCR_UNLOCK_RENDERER (user_data);
+	GcrRenderer *renderer;
+
+	/* Create a new renderer for this piece of data */
+	renderer = gcr_renderer_create (gcr_parser_get_parsed_label (parser),
+	                                gcr_parser_get_parsed_attributes (parser));
+
+	/* And save this renderer for placing in viewer later */
+	if (renderer != NULL)
+		self->pv->renderers = g_list_prepend (self->pv->renderers, renderer);
+}
+
+static void
+show_warning (GcrUnlockRenderer *self,
+              const gchar *message)
+{
+	gchar *text;
+
+	text = g_strdup_printf ("<i>%s</i>", message);
+	gtk_label_set_markup (self->pv->warning, text);
+	g_free (text);
+
+	gtk_widget_show (GTK_WIDGET (self->pv->warning));
+}
+
+static void
+on_unlock_button_clicked (GtkButton *button,
+                          gpointer user_data)
+{
+	GcrUnlockRenderer *self = GCR_UNLOCK_RENDERER (user_data);
+	GcrParser *parser;
+	GError *error = NULL;
+
+	/* Clear out any renderers somehow sitting around */
+	g_list_free_full (self->pv->renderers, g_object_unref);
+	self->pv->renderers = NULL;
+
+	parser = gcr_parser_new ();
+	gcr_parser_format_enable (parser, -1); /* all enabled */
+	g_signal_connect (parser, "parsed", G_CALLBACK (on_parser_parsed), self);
+	g_signal_connect (parser, "authenticate", G_CALLBACK (on_parser_authenticate), self);
+	if (gcr_parser_parse_data (parser, self->pv->locked_data,
+	                           self->pv->n_locked_data, &error)) {
+
+		/* If we unlocked successfully, then hide ourselves, and add other renderers */
+		self->pv->unlocked = TRUE;
+
+	} else if (g_error_matches (error, GCR_DATA_ERROR, GCR_ERROR_LOCKED)){
+		self->pv->unlock_tries++;
+		show_warning (self, _("The password was incorrect"));
+		g_error_free (error);
+
+	} else {
+		show_warning (self, error->message);
+		g_error_free (error);
+	}
+
+	gcr_renderer_emit_data_changed (GCR_RENDERER (self));
+}
+
+static void
+on_entry_activated (GtkEntry *entry,
+                    gpointer user_data)
+{
+	GtkButton *button = GTK_BUTTON (user_data);
+	gtk_button_clicked (button);
+}
+
+static void
+_gcr_unlock_renderer_init (GcrUnlockRenderer *self)
+{
+	GtkWidget *box, *vbox;
+	GtkWidget *button;
+	GtkEntryBuffer *buffer;
+
+	self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_UNLOCK_RENDERER,
+	                                         GcrUnlockRendererPrivate));
+
+	box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+
+	buffer = egg_entry_buffer_new ();
+	self->pv->entry = GTK_ENTRY (gtk_entry_new_with_buffer (buffer));
+	gtk_entry_set_visibility (self->pv->entry, FALSE);
+	gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (self->pv->entry), TRUE, FALSE, 0);
+	gtk_widget_show (GTK_WIDGET (self->pv->entry));
+	g_object_unref (buffer);
+
+	button = gtk_button_new_with_label (_("Unlock"));
+	gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
+	g_signal_connect (button, "clicked", G_CALLBACK (on_unlock_button_clicked), self);
+	g_signal_connect (self->pv->entry, "activate", G_CALLBACK (on_entry_activated), button);
+	gtk_widget_show (button);
+
+	vbox = gtk_vbox_new (GTK_ORIENTATION_VERTICAL, 6);
+	gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 0);
+	gtk_widget_show (box);
+
+	self->pv->warning = GTK_LABEL (gtk_label_new (""));
+	gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (self->pv->warning), FALSE, FALSE, 0);
+	gtk_widget_hide (GTK_WIDGET (self->pv->warning));
+
+	gtk_container_add (GTK_CONTAINER (self), vbox);
+	gtk_widget_show (vbox);
+}
+
+static void
+_gcr_unlock_renderer_finalize (GObject *obj)
+{
+	GcrUnlockRenderer *self = GCR_UNLOCK_RENDERER (obj);
+
+	g_free (self->pv->locked_data);
+	g_free (self->pv->label);
+	g_list_free_full (self->pv->renderers, g_object_unref);
+
+	G_OBJECT_CLASS (_gcr_unlock_renderer_parent_class)->finalize (obj);
+}
+
+static void
+_gcr_unlock_renderer_set_property (GObject *obj,
+                                   guint prop_id,
+                                   const GValue *value,
+                                   GParamSpec *pspec)
+{
+	GcrUnlockRenderer *self = GCR_UNLOCK_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:
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+_gcr_unlock_renderer_get_property (GObject *obj,
+                                   guint prop_id,
+                                   GValue *value,
+                                   GParamSpec *pspec)
+{
+	GcrUnlockRenderer *self = GCR_UNLOCK_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, NULL);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+_gcr_unlock_renderer_class_init (GcrUnlockRendererClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (GcrUnlockRendererPrivate));
+
+	gobject_class->finalize = _gcr_unlock_renderer_finalize;
+	gobject_class->set_property = _gcr_unlock_renderer_set_property;
+	gobject_class->get_property = _gcr_unlock_renderer_get_property;
+
+	g_object_class_install_property (gobject_class, PROP_LABEL,
+	           g_param_spec_string ("label", "Label", "Unlock Label",
+	                                "", G_PARAM_READWRITE));
+
+	g_object_class_install_property (gobject_class, PROP_ATTRIBUTES,
+	           g_param_spec_boxed ("attributes", "Attributes", "Certificate pkcs11 attributes",
+	                               GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE));
+
+	_gcr_icons_register ();
+}
+
+static void
+gcr_unlock_renderer_render (GcrRenderer *renderer,
+                            GcrViewer *viewer)
+{
+	GcrUnlockRenderer *self = GCR_UNLOCK_RENDERER (renderer);
+	GcrDisplayView *view;
+	gchar *display;
+	GList *renderers;
+	GIcon *icon;
+	GList *l;
+
+	if (GCR_IS_DISPLAY_VIEW (viewer)) {
+		view = GCR_DISPLAY_VIEW (viewer);
+
+	} else {
+		g_warning ("GcrUnlockRenderer only works with internal specific "
+		           "GcrViewer returned by gcr_viewer_new().");
+		return;
+	}
+
+	/*
+	 * If we were successfully unlocked, then this will contain a list of
+	 * renderers to add to the viewer.
+	 */
+	if (self->pv->unlocked) {
+
+		/* We used prepend above, so list is backwards */
+		renderers = g_list_reverse (self->pv->renderers);
+		self->pv->renderers = NULL;
+
+		for (l = renderers; l != NULL; l = g_list_next (l))
+			gcr_viewer_insert_renderer (viewer, l->data, renderer);
+		g_list_free_full (renderers, g_object_unref);
+
+		/* And finally remove ourselves from the viewer */
+		gcr_viewer_remove_renderer (viewer, GCR_RENDERER (self));
+	/*
+	 * Not yet unlocked, display the unlock dialog.
+	 */
+	} else {
+
+		_gcr_display_view_begin (view, renderer);
+
+		icon = g_themed_icon_new ("emblem-readonly");
+		_gcr_display_view_set_icon (view, renderer, icon);
+		g_object_unref (icon);
+
+		display = calculate_label (self);
+		_gcr_display_view_append_title (view, renderer, display);
+		g_free (display);
+
+		if (self->pv->label)
+			display = g_strdup_printf (_("The contents of '%s' are locked. In order to view the contents, enter a the correct password."),
+			                           self->pv->label);
+		else
+			display = g_strdup (_("The contents are locked. In order to view the contents, enter a the correct password."));
+		_gcr_display_view_append_content (view, renderer, display, NULL);
+		g_free (display);
+
+		_gcr_display_view_add_widget_area (view, renderer, GTK_WIDGET (self));
+		gtk_widget_show (GTK_WIDGET (self));
+
+		_gcr_display_view_end (view, renderer);
+	}
+}
+
+static void
+gcr_renderer_iface_init (GcrRendererIface *iface)
+{
+	iface->render_view = gcr_unlock_renderer_render;
+}
+
+GcrUnlockRenderer*
+_gcr_unlock_renderer_new (const gchar *label,
+                          gconstpointer locked_data,
+                          gsize n_locked_data)
+{
+	GcrUnlockRenderer *renderer;
+
+	renderer = g_object_new (GCR_TYPE_UNLOCK_RENDERER,
+	                         "label", label,
+	                         NULL);
+	g_object_ref_sink (renderer);
+
+	renderer->pv->locked_data = g_memdup (locked_data, n_locked_data);
+	renderer->pv->n_locked_data = n_locked_data;
+
+	return renderer;
+}
+
+GcrUnlockRenderer *
+_gcr_unlock_renderer_new_for_parsed (GcrParser *parser)
+{
+	gconstpointer block;
+	gsize n_block;
+
+	block = gcr_parser_get_parsed_block (parser, &n_block);
+	return _gcr_unlock_renderer_new (gcr_parser_get_parsed_label (parser),
+	                                 block, n_block);
+}
diff --git a/gcr/gcr-unlock-renderer.h b/gcr/gcr-unlock-renderer.h
new file mode 100644
index 0000000..54e0e46
--- /dev/null
+++ b/gcr/gcr-unlock-renderer.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * 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.
+ *
+ * Author: Stef Walter <stefw collabora co uk>
+ */
+
+#if !defined (__GCR_H_INSIDE__) && !defined (GCR_COMPILATION)
+#error "Only <gcr/gcr.h> can be included directly."
+#endif
+
+#ifndef __GCR_UNLOCK_RENDERER_H__
+#define __GCR_UNLOCK_RENDERER_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gcr-renderer.h"
+#include "gcr-types.h"
+
+G_BEGIN_DECLS
+
+#define GCR_TYPE_UNLOCK_RENDERER               (_gcr_unlock_renderer_get_type ())
+#define GCR_UNLOCK_RENDERER(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_UNLOCK_RENDERER, GcrUnlockRenderer))
+#define GCR_UNLOCK_RENDERER_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_UNLOCK_RENDERER, GcrUnlockRendererClass))
+#define GCR_IS_UNLOCK_RENDERER(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_UNLOCK_RENDERER))
+#define GCR_IS_UNLOCK_RENDERER_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_UNLOCK_RENDERER))
+#define GCR_UNLOCK_RENDERER_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_UNLOCK_RENDERER, GcrUnlockRendererClass))
+
+typedef struct _GcrUnlockRenderer GcrUnlockRenderer;
+typedef struct _GcrUnlockRendererClass GcrUnlockRendererClass;
+typedef struct _GcrUnlockRendererPrivate GcrUnlockRendererPrivate;
+
+struct _GcrUnlockRenderer {
+	/*< private >*/
+	GtkAlignment parent;
+	GcrUnlockRendererPrivate *pv;
+};
+
+struct _GcrUnlockRendererClass {
+	/*< private >*/
+	GtkAlignmentClass parent_class;
+};
+
+GType                  _gcr_unlock_renderer_get_type          (void);
+
+GcrUnlockRenderer *    _gcr_unlock_renderer_new               (const gchar *label,
+                                                               gconstpointer locked_data,
+                                                               gsize n_locked_data);
+
+GcrUnlockRenderer *    _gcr_unlock_renderer_new_for_parsed    (GcrParser *parser);
+
+G_END_DECLS
+
+#endif /* __GCR_UNLOCK_RENDERER_H__ */
diff --git a/gcr/gcr-viewer-window.c b/gcr/gcr-viewer-window.c
index a85a757..cb6140c 100644
--- a/gcr/gcr-viewer-window.c
+++ b/gcr/gcr-viewer-window.c
@@ -25,6 +25,7 @@
 
 #include "gcr-parser.h"
 #include "gcr-renderer.h"
+#include "gcr-unlock-renderer.h"
 #include "gcr-viewer-window.h"
 #include "gcr-viewer.h"
 
@@ -61,12 +62,30 @@ struct _GcrViewerWindowPrivate {
 	GCancellable *cancellable;
 	GcrViewer *viewer;
 	gboolean loading;
+	gchar *display_name;
 };
 
 static void viewer_load_next_file (GcrViewerWindow *self);
 static void viewer_stop_loading_files (GcrViewerWindow *self);
 
-G_DEFINE_TYPE (GcrViewerWindow, gcr_viewer_window, GTK_TYPE_WINDOW);
+static void gcr_viewer_iface_init (GcrViewerIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GcrViewerWindow, gcr_viewer_window, GTK_TYPE_WINDOW,
+                         G_IMPLEMENT_INTERFACE (GCR_TYPE_VIEWER, gcr_viewer_iface_init);
+);
+
+static const gchar *
+get_parsed_label_or_display_name (GcrViewerWindow *self,
+                                  GcrParser *parser)
+{
+	const gchar *label;
+
+	label = gcr_parser_get_parsed_label (parser);
+	if (label == NULL)
+		label = self->pv->display_name;
+
+	return label;
+}
 
 static void
 on_parser_parsed (GcrParser *parser, gpointer user_data)
@@ -74,7 +93,7 @@ on_parser_parsed (GcrParser *parser, gpointer user_data)
 	GcrViewerWindow *self = GCR_VIEWER_WINDOW (user_data);
 	GcrRenderer *renderer;
 
-	renderer = gcr_renderer_create (gcr_parser_get_parsed_label (parser),
+	renderer = gcr_renderer_create (get_parsed_label_or_display_name (self, parser),
 	                                gcr_parser_get_parsed_attributes (parser));
 
 	if (renderer) {
@@ -83,6 +102,24 @@ on_parser_parsed (GcrParser *parser, gpointer user_data)
 	}
 }
 
+static gboolean
+on_parser_authenticate (GcrParser *parser,
+                        guint count,
+                        gpointer user_data)
+{
+	GcrViewerWindow *self = GCR_VIEWER_WINDOW (user_data);
+	GcrUnlockRenderer *renderer;
+
+	renderer = _gcr_unlock_renderer_new_for_parsed (parser);
+	if (renderer) {
+		g_object_set (renderer, "label", get_parsed_label_or_display_name (self, parser), NULL);
+		gcr_viewer_add_renderer (self->pv->viewer, GCR_RENDERER (renderer));
+		g_object_unref (renderer);
+	}
+
+	return TRUE;
+}
+
 static void
 gcr_viewer_window_init (GcrViewerWindow *self)
 {
@@ -94,6 +131,7 @@ gcr_viewer_window_init (GcrViewerWindow *self)
 	self->pv->cancellable = g_cancellable_new ();
 
 	g_signal_connect (self->pv->parser, "parsed", G_CALLBACK (on_parser_parsed), self);
+	g_signal_connect (self->pv->parser, "authenticate", G_CALLBACK (on_parser_authenticate), self);
 }
 
 static void
@@ -137,6 +175,7 @@ gcr_viewer_window_finalize (GObject *obj)
 	g_assert (g_queue_is_empty (self->pv->files_to_load));
 	g_queue_free (self->pv->files_to_load);
 
+	g_free (self->pv->display_name);
 	g_object_unref (self->pv->cancellable);
 	g_object_unref (self->pv->parser);
 
@@ -158,6 +197,56 @@ gcr_viewer_window_class_init (GcrViewerWindowClass *klass)
 }
 
 static void
+gcr_viewer_window_add_renderer (GcrViewer *viewer,
+                                GcrRenderer *renderer)
+{
+	GcrViewerWindow *self = GCR_VIEWER_WINDOW (viewer);
+	gcr_viewer_add_renderer (self->pv->viewer, renderer);
+}
+
+static void
+gcr_viewer_window_insert_renderer (GcrViewer *viewer,
+                                   GcrRenderer *renderer,
+                                   GcrRenderer *before)
+{
+	GcrViewerWindow *self = GCR_VIEWER_WINDOW (viewer);
+	gcr_viewer_insert_renderer (self->pv->viewer, renderer, before);
+}
+
+static void
+gcr_viewer_window_remove_renderer (GcrViewer *viewer,
+                                   GcrRenderer *renderer)
+{
+	GcrViewerWindow *self = GCR_VIEWER_WINDOW (viewer);
+	gcr_viewer_remove_renderer (self->pv->viewer, renderer);
+}
+
+static guint
+gcr_viewer_window_count_renderers (GcrViewer *viewer)
+{
+	GcrViewerWindow *self = GCR_VIEWER_WINDOW (viewer);
+	return gcr_viewer_count_renderers (self->pv->viewer);
+}
+
+static GcrRenderer *
+gcr_viewer_window_get_renderer (GcrViewer *viewer,
+                                guint index_)
+{
+	GcrViewerWindow *self = GCR_VIEWER_WINDOW (viewer);
+	return gcr_viewer_get_renderer (self->pv->viewer, index_);
+}
+
+static void
+gcr_viewer_iface_init (GcrViewerIface *iface)
+{
+	iface->add_renderer = gcr_viewer_window_add_renderer;
+	iface->insert_renderer = gcr_viewer_window_insert_renderer;
+	iface->count_renderers = gcr_viewer_window_count_renderers;
+	iface->get_renderer = gcr_viewer_window_get_renderer;
+	iface->remove_renderer = gcr_viewer_window_remove_renderer;
+}
+
+static void
 on_parser_parse_stream_returned (GObject *source, GAsyncResult *result,
                                  gpointer user_data)
 {
@@ -166,15 +255,37 @@ on_parser_parse_stream_returned (GObject *source, GAsyncResult *result,
 
 	gcr_parser_parse_stream_finish (self->pv->parser, result, &error);
 
-	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-		viewer_stop_loading_files (self);
+	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
+	    g_error_matches (error, GCR_DATA_ERROR, GCR_ERROR_CANCELLED)) {
+
+	} else if (g_error_matches (error, GCR_DATA_ERROR, GCR_ERROR_LOCKED)) {
+		viewer_load_next_file (self);
+		return;
 
 	} else if (error) {
-		g_assert_not_reached (); /* TODO; */
+		g_warning ("failed to load: %s", error->message);
+		g_error_free (error);
 
 	} else {
 		viewer_load_next_file (self);
+		return;
 	}
+
+	viewer_stop_loading_files (self);
+}
+
+static void
+update_display_name (GcrViewerWindow *self,
+                     GFile *file)
+{
+	gchar *basename;
+
+	basename = g_file_get_basename (file);
+
+	g_free (self->pv->display_name);
+	self->pv->display_name = g_filename_display_name (basename);
+
+	g_free (basename);
 }
 
 static void
@@ -186,7 +297,7 @@ on_file_read_returned (GObject *source, GAsyncResult *result, gpointer user_data
 	GFileInputStream *fis;
 
 	fis = g_file_read_finish (file, result, &error);
-	g_object_unref (file);
+	update_display_name (self, file);
 
 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
 		viewer_stop_loading_files (self);
@@ -222,6 +333,8 @@ viewer_load_next_file (GcrViewerWindow *self)
 
 	g_file_read_async (file, G_PRIORITY_DEFAULT, self->pv->cancellable,
 	                   on_file_read_returned, self);
+
+	g_object_unref (file);
 }
 
 /**
diff --git a/gcr/gcr-viewer.c b/gcr/gcr-viewer.c
index e3b5c68..26b65df 100644
--- a/gcr/gcr-viewer.c
+++ b/gcr/gcr-viewer.c
@@ -49,6 +49,7 @@
  * GcrViewerIface:
  * @parent: The parent interface
  * @add_renderer: Virtual method to add a renderer
+ * @insert_renderer: Virtual method to insert a renderer
  * @remove_renderer: Virtual method to remove a renderer
  * @count_renderers: Virtual method to count renderers
  * @get_renderer: Virtual method to get a renderer
@@ -119,55 +120,69 @@ gcr_viewer_new_scrolled (void)
 
 /**
  * gcr_viewer_add_renderer:
- * @self: The viewer
+ * @viewer: The viewer
  * @renderer: The renderer to add
  *
  * Add a renderer to this viewer.
  */
 void
-gcr_viewer_add_renderer (GcrViewer *self, GcrRenderer *renderer)
+gcr_viewer_add_renderer (GcrViewer *viewer,
+                         GcrRenderer *renderer)
 {
-	g_return_if_fail (GCR_IS_VIEWER (self));
+	g_return_if_fail (GCR_IS_VIEWER (viewer));
 	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);
+	g_return_if_fail (GCR_VIEWER_GET_INTERFACE (viewer)->add_renderer);
+	GCR_VIEWER_GET_INTERFACE (viewer)->add_renderer (viewer, renderer);
+}
+
+void
+gcr_viewer_insert_renderer (GcrViewer *viewer,
+                            GcrRenderer *renderer,
+                            GcrRenderer *before)
+{
+	g_return_if_fail (GCR_IS_VIEWER (viewer));
+	g_return_if_fail (GCR_IS_RENDERER (renderer));
+	g_return_if_fail (!before || GCR_IS_RENDERER (before));
+	g_return_if_fail (GCR_VIEWER_GET_INTERFACE (viewer)->insert_renderer);
+	GCR_VIEWER_GET_INTERFACE (viewer)->insert_renderer (viewer, renderer, before);
 }
 
 /**
  * gcr_viewer_remove_renderer:
- * @self: The viewer
+ * @viewer: The viewer
  * @renderer: The renderer to remove
  *
  * Remove a renderer from this viewer.
  */
 void
-gcr_viewer_remove_renderer (GcrViewer *self, GcrRenderer *renderer)
+gcr_viewer_remove_renderer (GcrViewer *viewer,
+                            GcrRenderer *renderer)
 {
-	g_return_if_fail (GCR_IS_VIEWER (self));
+	g_return_if_fail (GCR_IS_VIEWER (viewer));
 	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);
+	g_return_if_fail (GCR_VIEWER_GET_INTERFACE (viewer)->remove_renderer);
+	GCR_VIEWER_GET_INTERFACE (viewer)->remove_renderer (viewer, renderer);
 }
 
 /**
  * gcr_viewer_count_renderers:
- * @self: The viewer
+ * @viewer: The viewer
  *
  * Get the number of renderers present in the viewer.
  *
  * Returns: The number of renderers.
  */
 guint
-gcr_viewer_count_renderers (GcrViewer *self)
+gcr_viewer_count_renderers (GcrViewer *viewer)
 {
-	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);
+	g_return_val_if_fail (GCR_IS_VIEWER (viewer), 0);
+	g_return_val_if_fail (GCR_VIEWER_GET_INTERFACE (viewer)->count_renderers, 0);
+	return GCR_VIEWER_GET_INTERFACE (viewer)->count_renderers (viewer);
 }
 
 /**
  * gcr_viewer_get_renderer:
- * @self: The viewer
+ * @viewer: The viewer
  * @index_: The index of the renderer to get
  *
  * Get a pointer to the renderer at the given index. It is an error to request
@@ -176,9 +191,10 @@ gcr_viewer_count_renderers (GcrViewer *self)
  * Returns: The render, owned by the viewer.
  */
 GcrRenderer*
-gcr_viewer_get_renderer (GcrViewer *self, guint index_)
+gcr_viewer_get_renderer (GcrViewer *viewer,
+                         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_);
+	g_return_val_if_fail (GCR_IS_VIEWER (viewer), NULL);
+	g_return_val_if_fail (GCR_VIEWER_GET_INTERFACE (viewer)->get_renderer, NULL);
+	return GCR_VIEWER_GET_INTERFACE (viewer)->get_renderer (viewer, index_);
 }
diff --git a/gcr/gcr-viewer.h b/gcr/gcr-viewer.h
index 20956ee..b806cda 100644
--- a/gcr/gcr-viewer.h
+++ b/gcr/gcr-viewer.h
@@ -39,13 +39,20 @@ typedef struct _GcrViewerIface GcrViewerIface;
 struct _GcrViewerIface {
 	GTypeInterface parent;
 
-	void (*add_renderer) (GcrViewer *self, GcrRenderer *viewer);
+	void (*add_renderer) (GcrViewer *viewer,
+	                      GcrRenderer *renderer);
 
-	void (*remove_renderer) (GcrViewer *self, GcrRenderer *viewer);
+	void (*insert_renderer) (GcrViewer *viewer,
+	                         GcrRenderer *renderer,
+	                         GcrRenderer *before);
 
-	guint (*count_renderers) (GcrViewer *self);
+	void (*remove_renderer) (GcrViewer *viewer,
+	                         GcrRenderer *renderer);
 
-	GcrRenderer* (*get_renderer) (GcrViewer *self, guint index_);
+	guint (*count_renderers) (GcrViewer *viewer);
+
+	GcrRenderer* (*get_renderer) (GcrViewer *viewer,
+	                              guint index_);
 
 	/*< private >*/
 	gpointer dummy1;
@@ -60,15 +67,19 @@ GcrViewer*              gcr_viewer_new                    (void);
 
 GcrViewer*              gcr_viewer_new_scrolled           (void);
 
-void                    gcr_viewer_add_renderer           (GcrViewer *self,
+void                    gcr_viewer_add_renderer           (GcrViewer *viewer,
                                                            GcrRenderer *renderer);
 
-void                    gcr_viewer_remove_renderer        (GcrViewer *self,
+void                    gcr_viewer_insert_renderer        (GcrViewer *viewer,
+                                                           GcrRenderer *renderer,
+                                                           GcrRenderer *before);
+
+void                    gcr_viewer_remove_renderer        (GcrViewer *viewer,
                                                            GcrRenderer *renderer);
 
-guint                   gcr_viewer_count_renderers        (GcrViewer *self);
+guint                   gcr_viewer_count_renderers        (GcrViewer *viewer);
 
-GcrRenderer*            gcr_viewer_get_renderer           (GcrViewer *self,
+GcrRenderer*            gcr_viewer_get_renderer           (GcrViewer *viewer,
                                                            guint index_);
 
 G_END_DECLS
diff --git a/gcr/gcr.h b/gcr/gcr.h
index 0b789fc..e6a1238 100644
--- a/gcr/gcr.h
+++ b/gcr/gcr.h
@@ -58,6 +58,7 @@
 #include "gcr-unlock-options.h"
 #include "gcr-unlock-options-widget.h"
 #include "gcr-viewer.h"
+#include "gcr-viewer-window.h"
 
 #undef __GCR_H_INSIDE__
 
diff --git a/gcr/tests/Makefile.am b/gcr/tests/Makefile.am
index 5729c8e..ed98f4d 100644
--- a/gcr/tests/Makefile.am
+++ b/gcr/tests/Makefile.am
@@ -2,7 +2,7 @@
 INCLUDES = \
 	-I$(top_builddir) \
 	-I$(top_srcdir) \
-	-DSRCDIR="\"$(srcdir)\"" \
+	-DSRCDIR="\"@abs_srcdir \"" \
 	-DGCR_API_SUBJECT_TO_CHANGE \
 	-DGCK_API_SUBJECT_TO_CHANGE \
 	-DGCR_COMPILATION \
@@ -56,4 +56,5 @@ noinst_PROGRAMS = \
 	frob-key \
 	frob-tree-selector \
 	frob-parser \
+	frob-unlock \
 	frob-unlock-options
diff --git a/gcr/tests/frob-unlock.c b/gcr/tests/frob-unlock.c
new file mode 100644
index 0000000..3a7f511
--- /dev/null
+++ b/gcr/tests/frob-unlock.c
@@ -0,0 +1,111 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * 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.
+ *
+ * Author: Stef Walter <stefw collabora co uk>
+ */
+
+#include "config.h"
+
+#include "gcr/gcr.h"
+#include "gcr/gcr-unlock-renderer.h"
+
+#include <gtk/gtk.h>
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+static gboolean
+delete_event(GtkWidget *widget,
+             GdkEvent *event,
+             gpointer data)
+{
+	gtk_main_quit ();
+	return FALSE;
+}
+
+static void
+on_parser_parsed (GcrParser *parser, gpointer unused)
+{
+
+}
+
+static void
+on_parser_authenticate (GcrParser *parser,
+                        gint count,
+                        gpointer user_data)
+{
+	GcrUnlockRenderer *renderer;
+	GtkWindow *window;
+
+	window = GTK_WINDOW (gcr_viewer_window_new ());
+	g_object_ref_sink (window);
+
+	renderer = _gcr_unlock_renderer_new_for_parsed (parser);
+	gcr_viewer_add_renderer (GCR_VIEWER (window), GCR_RENDERER (renderer));
+	g_object_unref (renderer);
+
+	gtk_window_set_default_size (window, 550, 400);
+	gtk_container_set_border_width (GTK_CONTAINER (window), 20);
+
+	g_signal_connect (window, "delete-event", G_CALLBACK (delete_event), NULL);
+	gtk_widget_show (GTK_WIDGET (window));
+
+	gtk_main ();
+
+	g_object_unref (window);
+
+}
+
+static void
+test_key (const gchar *path)
+{
+	GcrParser *parser;
+	GError *err = NULL;
+	guchar *data;
+	gsize n_data;
+
+	if (!g_file_get_contents (path, (gchar**)&data, &n_data, NULL))
+		g_error ("couldn't read file: %s", path);
+
+	parser = gcr_parser_new ();
+	g_signal_connect (parser, "parsed", G_CALLBACK (on_parser_parsed), NULL);
+	g_signal_connect (parser, "authenticate", G_CALLBACK (on_parser_authenticate), NULL);
+	if (!gcr_parser_parse_data (parser, data, n_data, &err))
+		g_error ("couldn't parse data: %s", err->message);
+
+	g_object_unref (parser);
+	g_free (data);
+}
+
+int
+main(int argc, char *argv[])
+{
+	gtk_init (&argc, &argv);
+	g_set_prgname ("frob-unlock");
+
+	if (argc > 1) {
+		test_key (argv[1]);
+	} else {
+		test_key (SRCDIR "/files/email.p12");
+	}
+
+	return 0;
+}



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