[gnome-keyring] gcr: Complete GcrViewerWidget and GcrImportButton



commit d94dd8459298bac84b70190fd8db0ef2b480db49
Author: Stef Walter <stefw collabora co uk>
Date:   Thu Sep 22 16:59:17 2011 +0200

    gcr: Complete GcrViewerWidget and GcrImportButton
    
     * Cleanup documentation
     * Rework how the GcrViewerWindow works so that it can be used
       elsewhere.
     * Create GcrImportButton which can import certificates and widgets.

 docs/reference/gcr/Makefile.am                   |   13 +-
 docs/reference/gcr/gcr-docs.sgml                 |    2 +
 docs/reference/gcr/gcr-sections.txt              |   46 ++-
 docs/reference/gcr/gcr-widgets.c                 |   46 ++-
 docs/reference/gcr/gcr.types                     |   23 +-
 docs/reference/gcr/images/certificate-widget.png |  Bin 15090 -> 16144 bytes
 docs/reference/gcr/images/import-button.png      |  Bin 0 -> 2925 bytes
 docs/reference/gcr/images/key-widget.png         |  Bin 10159 -> 10159 bytes
 docs/reference/gcr/images/viewer-widget.png      |  Bin 0 -> 13167 bytes
 gcr/Makefile.am                                  |   15 +-
 gcr/gcr-base.h                                   |    1 +
 gcr/gcr-collection-model.c                       |    1 -
 gcr/gcr-combo-selector.c                         |    1 -
 gcr/gcr-failure-renderer.c                       |   32 +-
 gcr/gcr-failure-renderer.h                       |   11 +-
 gcr/gcr-gnupg-process.c                          |   62 ++--
 gcr/gcr-import-button.c                          |  485 ++++++++++++++++++++++
 gcr/gcr-import-button.h                          |   68 +++
 gcr/gcr-list-selector.c                          |    1 -
 gcr/gcr-marshal.list                             |    2 +
 gcr/gcr-pkcs11-importer.c                        |    2 +-
 gcr/gcr-simple-collection.c                      |    1 -
 gcr/gcr-tree-selector.c                          |    1 -
 gcr/gcr-union-collection.c                       |    1 -
 gcr/gcr-unlock-renderer.c                        |   98 ++---
 gcr/gcr-unlock-renderer.h                        |   12 +-
 gcr/gcr-viewer-tool.c                            |    6 +-
 gcr/gcr-viewer-widget.c                          |  436 +++++++++++++++++++
 gcr/gcr-viewer-widget.h                          |   53 +++
 gcr/gcr-viewer-window.c                          |  371 ++++-------------
 gcr/gcr-viewer-window.h                          |   12 +-
 gcr/gcr-viewer.c                                 |   25 +-
 gcr/gcr.h                                        |    8 +-
 gcr/tests/Makefile.am                            |    4 +
 gcr/tests/frob-unlock.c                          |    3 +-
 35 files changed, 1365 insertions(+), 477 deletions(-)
---
diff --git a/docs/reference/gcr/Makefile.am b/docs/reference/gcr/Makefile.am
index dc2d717..aa940d2 100644
--- a/docs/reference/gcr/Makefile.am
+++ b/docs/reference/gcr/Makefile.am
@@ -75,6 +75,7 @@ IGNORE_HFILES= \
 	gcr-pkcs11-renderer.h \
 	gcr-record.h \
 	gcr-unlock-renderer.h \
+	gcr-viewer-window.h \
 	gcr-xxx.h \
 	gcr-zzz.h
 
@@ -82,10 +83,12 @@ IGNORE_HFILES= \
 # e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
 HTML_IMAGES= \
 	$(srcdir)/images/certificate-widget.png \
-	$(srcdir)/images/key-widget.png \
 	$(srcdir)/images/combo-selector.png \
+	$(srcdir)/images/import-button.png \
+	$(srcdir)/images/list-selector.png \
+	$(srcdir)/images/key-widget.png \
 	$(srcdir)/images/tree-selector.png \
-	$(srcdir)/images/list-selector.png
+	$(srcdir)/images/viewer-widget.png
 
 # Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
 # e.g. content_files=running.sgml building.sgml changes-2.0.sgml
@@ -127,10 +130,12 @@ DISTCLEANFILES = tmpl/gcr-unused.sgml
 
 WIDGETS = \
 	certificate-widget \
-	key-widget \
 	combo-selector \
+	import-button \
+	key-widget \
+	list-selector \
 	tree-selector \
-	list-selector
+	viewer-widget
 
 shots: gcr-shooter
 	mkdir -p $(builddir)/images
diff --git a/docs/reference/gcr/gcr-docs.sgml b/docs/reference/gcr/gcr-docs.sgml
index 9e2f64d..8d0de72 100644
--- a/docs/reference/gcr/gcr-docs.sgml
+++ b/docs/reference/gcr/gcr-docs.sgml
@@ -35,10 +35,12 @@
 		<xi:include href="xml/gcr-key-widget.xml"/>
 		<xi:include href="xml/gcr-column.xml"/>
 		<xi:include href="xml/gcr-combo-selector.xml"/>
+		<xi:include href="xml/gcr-import-button.xml"/>
 		<xi:include href="xml/gcr-list-selector.xml"/>
 		<xi:include href="xml/gcr-tree-selector.xml"/>
 		<xi:include href="xml/gcr-renderer.xml"/>
 		<xi:include href="xml/gcr-viewer.xml"/>
+		<xi:include href="xml/gcr-viewer-widget.xml"/>
 		<chapter>
 			<title>Widget Gallery</title>
 			<xi:include href="gcr-visual-index.xml" />
diff --git a/docs/reference/gcr/gcr-sections.txt b/docs/reference/gcr/gcr-sections.txt
index 22e19b0..6f0fd8b 100644
--- a/docs/reference/gcr/gcr-sections.txt
+++ b/docs/reference/gcr/gcr-sections.txt
@@ -117,6 +117,24 @@ GcrPkcs11ImporterPrivate
 </SECTION>
 
 <SECTION>
+<FILE>gcr-import-button</FILE>
+GcrImportButton
+GcrImportButtonClass
+gcr_import_button_new
+gcr_import_button_add_parsed
+<SUBSECTION Standard>
+GCR_IMPORT_BUTTON
+GCR_IMPORT_BUTTON_CLASS
+GCR_IMPORT_BUTTON_GET_CLASS
+GCR_IS_IMPORT_BUTTON
+GCR_IS_IMPORT_BUTTON_CLASS
+gcr_import_button_get_type
+GCR_TYPE_IMPORT_BUTTON
+<SUBSECTION Private>
+GcrImportButtonPrivate
+</SECTION>
+
+<SECTION>
 <FILE>gcr-simple-certificate</FILE>
 <TITLE>GcrSimpleCertificate</TITLE>
 GcrSimpleCertificate
@@ -523,20 +541,22 @@ GcrUnlockOptionsWidgetPrivate
 </SECTION>
 
 <SECTION>
-<FILE>gcr-viewer-window</FILE>
-GcrViewerWindow
-GcrViewerWindowClass
-gcr_viewer_window_new
-gcr_viewer_window_load
+<FILE>gcr-viewer-widget</FILE>
+GcrViewerWidget
+GcrViewerWidgetClass
+gcr_viewer_widget_new
+gcr_viewer_widget_load_data
+gcr_viewer_widget_load_file
+<SUBSECTION Standard>
+gcr_viewer_widget_get_type
+GCR_TYPE_VIEWER_WIDGET
+GCR_IS_VIEWER_WIDGET
+GCR_IS_VIEWER_WIDGET_CLASS
+GCR_VIEWER_WIDGET
+GCR_VIEWER_WIDGET_CLASS
+GCR_VIEWER_WIDGET_GET_CLASS
 <SUBSECTION Private>
-gcr_viewer_window_get_type
-GcrViewerWindowPrivate
-GCR_IS_VIEWER_WINDOW
-GCR_IS_VIEWER_WINDOW_CLASS
-GCR_TYPE_VIEWER_WINDOW
-GCR_VIEWER_WINDOW
-GCR_VIEWER_WINDOW_CLASS
-GCR_VIEWER_WINDOW_GET_CLASS
+GcrViewerWidgetPrivate
 </SECTION>
 
 <SECTION>
diff --git a/docs/reference/gcr/gcr-widgets.c b/docs/reference/gcr/gcr-widgets.c
index 3f23bc5..d8458ed 100644
--- a/docs/reference/gcr/gcr-widgets.c
+++ b/docs/reference/gcr/gcr-widgets.c
@@ -177,6 +177,38 @@ create_list_selector (const gchar *name)
 	return gcr_shooter_info_new (name, align, GCR_SHOOTER_MEDIUM);
 }
 
+static GcrShooterInfo *
+create_import_button (const gchar *name)
+{
+	GcrImportButton *import;
+	GtkWidget *align;
+
+	import = gcr_import_button_new ("Import");
+
+	align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
+	gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET (import));
+
+	return gcr_shooter_info_new (name, align, GCR_SHOOTER_MEDIUM);
+}
+
+static GcrShooterInfo *
+create_viewer_widget (const gchar *name)
+{
+	GcrViewerWidget *viewer;
+	GtkWidget *align;
+	gchar *contents;
+	gsize length;
+
+	contents = load_gcr_test_file ("email.p12", &length);
+	viewer = gcr_viewer_widget_new ();
+	gcr_viewer_widget_load_data (viewer, "Email certificate", (gpointer)contents, length);
+	g_free (contents);
+
+	align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
+	gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET (viewer));
+
+	return gcr_shooter_info_new (name, align, GCR_SHOOTER_LARGE);
+}
 
 GcrShooterInfo*
 gcr_widgets_create (const gchar *name)
@@ -185,14 +217,20 @@ gcr_widgets_create (const gchar *name)
 
 	if (g_str_equal (name, "certificate-widget"))
 		return create_certificate_widget (name);
-	else if (g_str_equal (name, "key-widget"))
-		return create_key_widget (name);
 	else if (g_str_equal (name, "combo-selector"))
 		return create_combo_selector (name);
-	else if (g_str_equal (name, "tree-selector"))
-		return create_tree_selector (name);
+	else if (g_str_equal (name, "import-button"))
+		return create_import_button (name);
+	else if (g_str_equal (name, "key-widget"))
+		return create_key_widget (name);
 	else if (g_str_equal (name, "list-selector"))
 		return create_list_selector (name);
+	else if (g_str_equal (name, "tree-selector"))
+		return create_tree_selector (name);
+	else if (g_str_equal (name, "viewer-widget"))
+		return create_viewer_widget (name);
+	else
+		g_assert_not_reached ();
 
 	return NULL;
 }
diff --git a/docs/reference/gcr/gcr.types b/docs/reference/gcr/gcr.types
index a54679c..7838906 100644
--- a/docs/reference/gcr/gcr.types
+++ b/docs/reference/gcr/gcr.types
@@ -1,6 +1,23 @@
-gcr_parser_get_type
+gcr_certificate_chain_get_type
 gcr_certificate_get_type
+gcr_certificate_renderer_get_type
+gcr_certificate_widget_get_type
+gcr_collection_get_type
+gcr_collection_model_get_type
+gcr_combo_selector_get_type
+gcr_comparable_get_type
+gcr_import_button_get_type
 gcr_importer_get_type
-gcr_simple_certificate_get_type
+gcr_key_renderer_get_type
+gcr_key_widget_get_type
+gcr_list_selector_get_type
+gcr_parser_get_type
 gcr_pkcs11_certificate_get_type
-gcr_certificate_chain_get_type
\ No newline at end of file
+gcr_renderer_get_type
+gcr_simple_certificate_get_type
+gcr_simple_collection_get_type
+gcr_tree_selector_get_type
+gcr_union_collection_get_type
+gcr_unlock_options_widget_get_type
+gcr_viewer_get_type
+gcr_viewer_widget_get_type
diff --git a/docs/reference/gcr/images/certificate-widget.png b/docs/reference/gcr/images/certificate-widget.png
index 1a82626..e3c9158 100644
Binary files a/docs/reference/gcr/images/certificate-widget.png and b/docs/reference/gcr/images/certificate-widget.png differ
diff --git a/docs/reference/gcr/images/import-button.png b/docs/reference/gcr/images/import-button.png
new file mode 100644
index 0000000..9166bb8
Binary files /dev/null and b/docs/reference/gcr/images/import-button.png differ
diff --git a/docs/reference/gcr/images/key-widget.png b/docs/reference/gcr/images/key-widget.png
index 938dbbf..db3a371 100644
Binary files a/docs/reference/gcr/images/key-widget.png and b/docs/reference/gcr/images/key-widget.png differ
diff --git a/docs/reference/gcr/images/viewer-widget.png b/docs/reference/gcr/images/viewer-widget.png
new file mode 100644
index 0000000..1933e04
Binary files /dev/null and b/docs/reference/gcr/images/viewer-widget.png differ
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index 6494bc5..1f76297 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -49,7 +49,7 @@ HEADER_UI_FILES = \
 	gcr-tree-selector.h \
 	gcr-unlock-options-widget.h \
 	gcr-viewer.h \
-	gcr-viewer-window.h
+	gcr-viewer-widget.h
 
 incdir = $(includedir)/gcr- GCR_MAJOR@/gcr
 
@@ -102,12 +102,11 @@ libgcr_base_ GCR_MAJOR@_la_SOURCES = \
 	gcr-gnupg-process.c gcr-gnupg-process.h \
 	gcr-gnupg-records.c gcr-gnupg-records.h \
 	gcr-gnupg-util.c gcr-gnupg-util.h \
-	gcr-library.c gcr-library.h \
 	gcr-importer.c gcr-importer.h \
 	gcr-internal.h \
+	gcr-library.c gcr-library.h \
 	gcr-memory.c \
 	gcr-memory-icon.c gcr-memory-icon.h \
-	gcr-menu-button.c gcr-menu-button.h \
 	gcr-openpgp.c gcr-openpgp.h \
 	gcr-openssh.c gcr-openssh.h \
 	gcr-parser.c gcr-parser.h \
@@ -139,6 +138,7 @@ libgcr_ GCR_MAJOR@_la_SOURCES = \
 	gcr-gnupg-renderer.c gcr-gnupg-renderer.h \
 	gcr-gnupg-records.c gcr-gnupg-records.h \
 	gcr-icons.c gcr-icons.h \
+	gcr-import-button.c gcr-import-button.h \
 	gcr-import-dialog.c gcr-import-dialog.h \
 	gcr-key-renderer.c gcr-key-renderer.h \
 	gcr-key-widget.c gcr-key-widget.h \
@@ -146,6 +146,7 @@ libgcr_ GCR_MAJOR@_la_SOURCES = \
 	gcr-live-search.c gcr-live-search.h \
 	gcr-memory.c \
 	gcr-memory-icon.c gcr-memory-icon.h \
+	gcr-menu-button.c gcr-menu-button.h \
 	gcr-record.c gcr-record.h \
 	gcr-renderer.c gcr-renderer.h \
 	gcr-tree-selector.c gcr-tree-selector.h \
@@ -153,7 +154,7 @@ libgcr_ GCR_MAJOR@_la_SOURCES = \
 	gcr-unlock-options-widget.c gcr-unlock-options-widget.h \
 	gcr-unlock-renderer.c gcr-unlock-renderer.h \
 	gcr-viewer.c gcr-viewer.h \
-	gcr-viewer-window.c \
+	gcr-viewer-widget.c gcr-viewer-widget.h \
 	$(BUILT_UI_FILES)
 
 libgcr_base_ GCR_MAJOR@_la_CFLAGS = \
@@ -270,11 +271,13 @@ desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
 bin_PROGRAMS = gcr-viewer
 
 gcr_viewer_SOURCES = \
-	gcr-viewer-tool.c
+	gcr-viewer-tool.c \
+	gcr-viewer-window.c gcr-viewer-window.h
 
 gcr_viewer_CFLAGS = \
 	$(GTK_CFLAGS) \
-	-DLOCALEDIR=\""$(datadir)/locale"\"
+	-DLOCALEDIR=\""$(datadir)/locale"\" \
+	-DGCR_API_SUBJECT_TO_CHANGE
 
 gcr_viewer_LDADD = \
 	$(builddir)/libgcr-$(GCR_MAJOR).la \
diff --git a/gcr/gcr-base.h b/gcr/gcr-base.h
index f70720b..54cc629 100644
--- a/gcr/gcr-base.h
+++ b/gcr/gcr-base.h
@@ -39,6 +39,7 @@
 #include "gcr-deprecated-base.h"
 #include "gcr-enum-types-base.h"
 #include "gcr-icons.h"
+#include "gcr-importer.h"
 #include "gcr-library.h"
 #include "gcr-parser.h"
 #include "gcr-pkcs11-certificate.h"
diff --git a/gcr/gcr-collection-model.c b/gcr/gcr-collection-model.c
index e46bf51..c5ebe07 100644
--- a/gcr/gcr-collection-model.c
+++ b/gcr/gcr-collection-model.c
@@ -55,7 +55,6 @@
 
 /**
  * GcrCollectionModel:
- * @parent: The parent object
  *
  * A #GtkTreeModel which contains a row for each object in a #GcrCollection.
  */
diff --git a/gcr/gcr-combo-selector.c b/gcr/gcr-combo-selector.c
index 91328a2..6811139 100644
--- a/gcr/gcr-combo-selector.c
+++ b/gcr/gcr-combo-selector.c
@@ -40,7 +40,6 @@
 
 /**
  * GcrComboSelector:
- * @parent: Parent object
  *
  * A combo selector widget.
  */
diff --git a/gcr/gcr-failure-renderer.c b/gcr/gcr-failure-renderer.c
index b6f829f..8417307 100644
--- a/gcr/gcr-failure-renderer.c
+++ b/gcr/gcr-failure-renderer.c
@@ -42,30 +42,30 @@ struct _GcrFailureRendererPrivate {
 
 static void gcr_renderer_iface_init (GcrRendererIface *iface);
 
-G_DEFINE_TYPE_WITH_CODE (GcrFailureRenderer, _gcr_failure_renderer, G_TYPE_OBJECT,
+G_DEFINE_TYPE_WITH_CODE (GcrFailureRenderer, gcr_failure_renderer, G_TYPE_OBJECT,
 	G_IMPLEMENT_INTERFACE (GCR_TYPE_RENDERER, gcr_renderer_iface_init);
 );
 
 static void
-_gcr_failure_renderer_init (GcrFailureRenderer *self)
+gcr_failure_renderer_init (GcrFailureRenderer *self)
 {
 	self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_FAILURE_RENDERER,
 	                                         GcrFailureRendererPrivate));
 }
 
 static void
-_gcr_failure_renderer_finalize (GObject *obj)
+gcr_failure_renderer_finalize (GObject *obj)
 {
 	GcrFailureRenderer *self = GCR_FAILURE_RENDERER (obj);
 
 	g_error_free (self->pv->error);
 	g_free (self->pv->label);
 
-	G_OBJECT_CLASS (_gcr_failure_renderer_parent_class)->finalize (obj);
+	G_OBJECT_CLASS (gcr_failure_renderer_parent_class)->finalize (obj);
 }
 
 static void
-_gcr_failure_renderer_set_property (GObject *obj,
+gcr_failure_renderer_set_property (GObject *obj,
                                    guint prop_id,
                                    const GValue *value,
                                    GParamSpec *pspec)
@@ -88,7 +88,7 @@ _gcr_failure_renderer_set_property (GObject *obj,
 }
 
 static void
-_gcr_failure_renderer_get_property (GObject *obj,
+gcr_failure_renderer_get_property (GObject *obj,
                                    guint prop_id,
                                    GValue *value,
                                    GParamSpec *pspec)
@@ -109,28 +109,28 @@ _gcr_failure_renderer_get_property (GObject *obj,
 }
 
 static void
-_gcr_failure_renderer_class_init (GcrFailureRendererClass *klass)
+gcr_failure_renderer_class_init (GcrFailureRendererClass *klass)
 {
 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
 	g_type_class_add_private (klass, sizeof (GcrFailureRendererPrivate));
 
-	gobject_class->finalize = _gcr_failure_renderer_finalize;
-	gobject_class->set_property = _gcr_failure_renderer_set_property;
-	gobject_class->get_property = _gcr_failure_renderer_get_property;
+	gobject_class->finalize = gcr_failure_renderer_finalize;
+	gobject_class->set_property = gcr_failure_renderer_set_property;
+	gobject_class->get_property = gcr_failure_renderer_get_property;
 
 	g_object_class_install_property (gobject_class, PROP_LABEL,
 	           g_param_spec_string ("label", "Label", "Failure Label",
 	                                "", G_PARAM_READWRITE));
 
 	g_object_class_install_property (gobject_class, PROP_ATTRIBUTES,
-	           g_param_spec_boxed ("attributes", "Attributes", "Certificate pkcs11 attributes",
+	           g_param_spec_boxed ("attributes", "Attributes", "Renderer attributes",
 	                               GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE));
 }
 
 static void
 gcr_failure_renderer_render (GcrRenderer *renderer,
-                            GcrViewer *viewer)
+                             GcrViewer *viewer)
 {
 	GcrFailureRenderer *self = GCR_FAILURE_RENDERER (renderer);
 	GcrDisplayView *view;
@@ -178,8 +178,8 @@ gcr_renderer_iface_init (GcrRendererIface *iface)
 }
 
 GcrRenderer *
-_gcr_failure_renderer_new (const gchar *label,
-                           GError *error)
+gcr_failure_renderer_new (const gchar *label,
+                          GError *error)
 {
 	GcrFailureRenderer *renderer;
 
@@ -192,7 +192,7 @@ _gcr_failure_renderer_new (const gchar *label,
 }
 
 GcrRenderer *
-_gcr_failure_renderer_new_unsupported (const gchar *label)
+gcr_failure_renderer_new_unsupported (const gchar *label)
 {
 	GcrRenderer *renderer;
 	GError *error;
@@ -200,7 +200,7 @@ _gcr_failure_renderer_new_unsupported (const gchar *label)
 	error = g_error_new (GCR_DATA_ERROR, GCR_ERROR_UNRECOGNIZED,
 	                     _("Cannot display a file of this type."));
 
-	renderer = _gcr_failure_renderer_new (label, error);
+	renderer = gcr_failure_renderer_new (label, error);
 
 	g_error_free (error);
 	return renderer;
diff --git a/gcr/gcr-failure-renderer.h b/gcr/gcr-failure-renderer.h
index 0e8311e..9b70f36 100644
--- a/gcr/gcr-failure-renderer.h
+++ b/gcr/gcr-failure-renderer.h
@@ -30,11 +30,10 @@
 #include <gtk/gtk.h>
 
 #include "gcr-renderer.h"
-#include "gcr-types.h"
 
 G_BEGIN_DECLS
 
-#define GCR_TYPE_FAILURE_RENDERER               (_gcr_failure_renderer_get_type ())
+#define GCR_TYPE_FAILURE_RENDERER               (gcr_failure_renderer_get_type ())
 #define GCR_FAILURE_RENDERER(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_FAILURE_RENDERER, GcrFailureRenderer))
 #define GCR_FAILURE_RENDERER_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_FAILURE_RENDERER, GcrFailureRendererClass))
 #define GCR_IS_FAILURE_RENDERER(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_FAILURE_RENDERER))
@@ -56,12 +55,12 @@ struct _GcrFailureRendererClass {
 	GObjectClass parent_class;
 };
 
-GType                  _gcr_failure_renderer_get_type          (void);
+GType                  gcr_failure_renderer_get_type         (void);
 
-GcrRenderer *          _gcr_failure_renderer_new              (const gchar *label,
-                                                               GError *error);
+GcrRenderer *          gcr_failure_renderer_new              (const gchar *label,
+                                                              GError *error);
 
-GcrRenderer *          _gcr_failure_renderer_new_unsupported  (const gchar *label);
+GcrRenderer *          gcr_failure_renderer_new_unsupported  (const gchar *label);
 
 G_END_DECLS
 
diff --git a/gcr/gcr-gnupg-process.c b/gcr/gcr-gnupg-process.c
index 0e87ea9..81423da 100644
--- a/gcr/gcr-gnupg-process.c
+++ b/gcr/gcr-gnupg-process.c
@@ -81,6 +81,7 @@ typedef struct _GnupgSource {
 	GByteArray *input_buf;
 	GString *error_buf;
 	GString *status_buf;
+	guint source_sig;
 
 	GPid child_pid;
 	guint child_sig;
@@ -101,8 +102,6 @@ struct _GcrGnupgProcessPrivate {
 	gboolean complete;
 	GError *error;
 
-	guint source_sig;
-
 	GAsyncReadyCallback async_callback;
 	gpointer user_data;
 };
@@ -458,11 +457,6 @@ complete_run_process (GcrGnupgProcess *self)
 	self->pv->running = FALSE;
 	self->pv->complete = TRUE;
 
-	if (self->pv->source_sig) {
-		g_source_remove (self->pv->source_sig);
-		self->pv->source_sig = 0;
-	}
-
 	if (self->pv->error == NULL) {
 		_gcr_debug ("completed process");
 	} else {
@@ -472,20 +466,13 @@ complete_run_process (GcrGnupgProcess *self)
 }
 
 static gboolean
-complete_if_source_is_done (GnupgSource *gnupg_source)
+complete_source_is_done (GnupgSource *gnupg_source)
 {
-	gint i;
-
-	for (i = 0; i < NUM_FDS; ++i) {
-		if (gnupg_source->polls[i].fd >= 0)
-			return FALSE;
-	}
-
-	if (gnupg_source->child_pid)
-		return FALSE;
-
 	_gcr_debug ("all fds closed and process exited, completing");
 
+	g_assert (gnupg_source->child_sig == 0);
+	g_assert (gnupg_source->source_sig == 0);
+
 	complete_run_process (gnupg_source->process);
 	run_async_ready_callback (gnupg_source->process);
 
@@ -772,6 +759,7 @@ on_gnupg_source_dispatch (GSource *source, GSourceFunc unused, gpointer user_dat
 	GnupgSource *gnupg_source = (GnupgSource*)source;
 	GcrGnupgProcess *self = gnupg_source->process;
 	GPollFD *poll;
+	guint i;
 
 	/* Standard input, no support yet */
 	poll = &gnupg_source->polls[FD_INPUT];
@@ -829,10 +817,18 @@ on_gnupg_source_dispatch (GSource *source, GSourceFunc unused, gpointer user_dat
 		poll->revents = 0;
 	}
 
-	if (complete_if_source_is_done (gnupg_source))
-		return FALSE; /* Disconnect this source */
+	for (i = 0; i < NUM_FDS; ++i) {
+		if (gnupg_source->polls[i].fd >= 0)
+			return TRUE;
+	}
 
-	return TRUE;
+	/* Because we return below */
+	gnupg_source->source_sig = 0;
+
+	if (!gnupg_source->child_pid)
+		complete_source_is_done (gnupg_source);
+
+	return FALSE; /* Disconnect this source */
 }
 
 static GSourceFuncs gnupg_source_funcs = {
@@ -849,6 +845,7 @@ on_gnupg_process_child_exited (GPid pid, gint status, gpointer user_data)
 	GcrGnupgProcess *self = gnupg_source->process;
 	GError *error = NULL;
 	gint code;
+	guint i;
 
 	_gcr_debug ("process exited: %d", (int)pid);
 
@@ -881,7 +878,12 @@ on_gnupg_process_child_exited (GPid pid, gint status, gpointer user_data)
 		g_error_free (error);
 	}
 
-	complete_if_source_is_done (gnupg_source);
+	for (i = 0; i < NUM_FDS; ++i) {
+		if (gnupg_source->polls[i].fd >= 0)
+			return;
+	}
+
+	complete_source_is_done (gnupg_source);
 }
 
 static void
@@ -913,19 +915,17 @@ on_cancellable_cancelled (GCancellable *cancellable, gpointer user_data)
 
 	_gcr_debug ("process cancelled");
 
+	/* Set an error, which is respected when this actually completes. */
+	if (gnupg_source->process->pv->error == NULL)
+		gnupg_source->process->pv->error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED,
+		                                                        _("The operation was cancelled"));
+
 	/* Try and kill the child process */
 	if (gnupg_source->child_pid) {
 		_gcr_debug ("sending term signal to process: %d",
 		            (int)gnupg_source->child_pid);
 		kill (gnupg_source->child_pid, SIGTERM);
 	}
-
-	/* Set an error, which is respected when this actually completes. */
-	if (gnupg_source->process->pv->error == NULL)
-		gnupg_source->process->pv->error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED,
-		                                                        _("The operation was cancelled"));
-
-	complete_if_source_is_done (gnupg_source);
 }
 
 /**
@@ -1108,9 +1108,8 @@ _gcr_gnupg_process_run_async (GcrGnupgProcess *self, const gchar **argv, const g
 		                                                  (GDestroyNotify)g_source_unref);
 	}
 
-	g_assert (!self->pv->source_sig);
 	g_source_set_callback (source, unused_callback, NULL, NULL);
-	self->pv->source_sig = g_source_attach (source, g_main_context_default ());
+	gnupg_source->source_sig = g_source_attach (source, g_main_context_default ());
 
 	/* This assumes the outstanding reference to source */
 	g_assert (!gnupg_source->child_sig);
@@ -1147,7 +1146,6 @@ _gcr_gnupg_process_run_finish (GcrGnupgProcess *self, GAsyncResult *result,
 	g_assert (!self->pv->running);
 	g_assert (!self->pv->async_callback);
 	g_assert (!self->pv->user_data);
-	g_assert (!self->pv->source_sig);
 
 	if (self->pv->error) {
 		g_propagate_error (error, self->pv->error);
diff --git a/gcr/gcr-import-button.c b/gcr/gcr-import-button.c
new file mode 100644
index 0000000..15bd961
--- /dev/null
+++ b/gcr/gcr-import-button.c
@@ -0,0 +1,485 @@
+/*
+ * 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-import-button.h"
+#include "gcr-internal.h"
+#include "gcr-marshal.h"
+#include "gcr-parser.h"
+
+#include <glib/gi18n-lib.h>
+
+enum {
+	PROP_0,
+	PROP_LABEL
+};
+
+/**
+ * SECTION:gcr-import-button
+ * @title: GcrImportButton
+ * @short_description: Button which imports parsed certificates and keys
+ *
+ * A button which imports keys and certificates. Shows a spinner when the
+ * button is activated. When more than one importer is available shows
+ * a drop down to select which to import to.
+ */
+
+/**
+ * GcrImportButton:
+ *
+ * Button which imports parsed certificates and keys.
+ */
+
+/**
+ * GcrImportButtonClass:
+ * @parent_class: The parent class
+ * @imported: Emitted when the import completes, or fails.
+ *
+ * Class for #GcrImportButton.
+ */
+
+struct _GcrImportButtonPrivate {
+	GList *importers;
+	gboolean created;
+	gboolean importing;
+	gchar *imported;
+	GtkWidget *spinner;
+	GtkWidget *arrow;
+	GtkWidget *label;
+	GCancellable *cancellable;
+	GtkMenu *menu;
+};
+
+enum {
+	IMPORTED,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static GQuark QUARK_IMPORTER = 0;
+
+G_DEFINE_TYPE (GcrImportButton, gcr_import_button, GTK_TYPE_BUTTON);
+
+static void
+gcr_import_button_init (GcrImportButton *self)
+{
+	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_IMPORT_BUTTON, GcrImportButtonPrivate);
+	self->pv->cancellable = g_cancellable_new ();
+	self->pv->label = gtk_label_new ("");
+}
+
+static void
+gcr_import_button_constructed (GObject *obj)
+{
+	GcrImportButton *self = GCR_IMPORT_BUTTON (obj);
+	GtkWidget *grid;
+
+	G_OBJECT_CLASS (gcr_import_button_parent_class)->constructed (obj);
+
+	self->pv->spinner = gtk_spinner_new ();
+	self->pv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
+	grid = gtk_grid_new ();
+
+	gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_HORIZONTAL);
+	gtk_container_add (GTK_CONTAINER (grid), self->pv->spinner);
+	gtk_container_add (GTK_CONTAINER (grid), self->pv->label);
+	gtk_container_add (GTK_CONTAINER (grid), self->pv->arrow);
+	gtk_grid_set_row_spacing (GTK_GRID (grid), 3);
+	gtk_widget_set_hexpand (grid, TRUE);
+	gtk_widget_set_halign (grid, GTK_ALIGN_CENTER);
+
+	gtk_widget_show (self->pv->label);
+	gtk_widget_show (grid);
+
+	gtk_container_add (GTK_CONTAINER (self), grid);
+}
+
+static void
+gcr_import_button_set_property (GObject *obj,
+                                guint prop_id,
+                                const GValue *value,
+                                GParamSpec *pspec)
+{
+	GcrImportButton *self = GCR_IMPORT_BUTTON (obj);
+
+	switch (prop_id) {
+	case PROP_LABEL:
+		gtk_label_set_label (GTK_LABEL (self->pv->label), g_value_get_string (value));
+		g_object_notify (obj, "label");
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gcr_import_button_get_property (GObject *obj,
+                                guint prop_id,
+                                GValue *value,
+                                GParamSpec *pspec)
+{
+	GcrImportButton *self = GCR_IMPORT_BUTTON (obj);
+
+	switch (prop_id) {
+	case PROP_LABEL:
+		g_value_set_string (value, gtk_label_get_label (GTK_LABEL (self->pv->label)));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gcr_import_button_dispose (GObject *obj)
+{
+	GcrImportButton *self = GCR_IMPORT_BUTTON (obj);
+
+	gck_list_unref_free (self->pv->importers);
+	self->pv->importers = NULL;
+	g_cancellable_cancel (self->pv->cancellable);
+	g_clear_object (&self->pv->menu);
+
+	G_OBJECT_CLASS (gcr_import_button_parent_class)->dispose (obj);
+}
+
+static void
+gcr_import_button_finalize (GObject *obj)
+{
+	GcrImportButton *self = GCR_IMPORT_BUTTON (obj);
+
+	g_object_unref (self->pv->cancellable);
+
+	G_OBJECT_CLASS (gcr_import_button_parent_class)->finalize (obj);
+}
+
+static void
+update_import_button (GcrImportButton *self)
+{
+	gchar *message;
+	gchar *label;
+
+	/* Importing, set a spinner */
+	if (self->pv->importing) {
+		gtk_widget_show (self->pv->spinner);
+		gtk_widget_hide (self->pv->arrow);
+		gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
+		gtk_widget_set_tooltip_text (GTK_WIDGET (self), _("Import is in progress..."));
+
+	} else if (self->pv->imported) {
+		gtk_widget_hide (self->pv->spinner);
+		gtk_widget_hide (self->pv->arrow);
+		gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
+		message = g_strdup_printf (_("Imported to: %s"), self->pv->imported);
+		gtk_widget_set_tooltip_text (GTK_WIDGET (self), message);
+		g_free (message);
+
+	/* Not importing, but have importers */
+	} else if (self->pv->importers) {
+		gtk_widget_hide (self->pv->spinner);
+		gtk_widget_set_sensitive (GTK_WIDGET (self), TRUE);
+
+		/* More than one importer */
+		if (self->pv->importers->next) {
+			gtk_widget_show (self->pv->arrow);
+			gtk_widget_set_tooltip_text (GTK_WIDGET (self), NULL);
+
+		/* Only one importer */
+		} else {
+			gtk_widget_hide (self->pv->arrow);
+			g_object_get (self->pv->importers->data, "label", &label, NULL);
+			message = g_strdup_printf (_("Import to: %s"), label);
+			gtk_widget_set_tooltip_text (GTK_WIDGET (self), message);
+			g_free (message);
+			g_free (label);
+		}
+
+	/* No importers, none compatible */
+	} else if (self->pv->created) {
+		gtk_widget_hide (self->pv->spinner);
+		gtk_widget_hide (self->pv->arrow);
+
+		gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
+		gtk_widget_set_tooltip_text (GTK_WIDGET (self), _("Cannot import because there are no compatible importers"));
+
+	/* No importers yet added */
+	} else {
+		gtk_widget_hide (self->pv->spinner);
+		gtk_widget_hide (self->pv->arrow);
+
+		gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
+		gtk_widget_set_tooltip_text (GTK_WIDGET (self), _("No data to import"));
+	}
+}
+
+static void
+on_import_complete (GObject *importer,
+                    GAsyncResult *result,
+                    gpointer user_data)
+{
+	GcrImportButton *self = GCR_IMPORT_BUTTON (user_data);
+	GError *error = NULL;
+
+	g_return_if_fail (self->pv->imported == NULL);
+
+	self->pv->importing = FALSE;
+
+	gcr_importer_import_finish (GCR_IMPORTER (importer), result, &error);
+	if (error == NULL) {
+		g_object_get (importer, "label", &self->pv->imported, NULL);
+		gck_list_unref_free (self->pv->importers);
+		self->pv->importers = NULL;
+	}
+
+	g_signal_emit (self, signals[IMPORTED], 0, importer, error);
+	g_clear_error (&error);
+
+	update_import_button (self);
+}
+
+static void
+begin_import (GcrImportButton *self,
+              GcrImporter *importer)
+{
+	g_return_if_fail (self->pv->importing == FALSE);
+
+	self->pv->importing = TRUE;
+	g_free (self->pv->imported);
+	self->pv->imported = NULL;
+
+	gcr_importer_import_async (importer,
+	                           self->pv->cancellable,
+	                           on_import_complete,
+	                           g_object_ref (self));
+}
+
+static void
+on_importer_menu_activated (GtkMenuItem *menu_item,
+                            gpointer user_data)
+{
+	GcrImportButton *self = GCR_IMPORT_BUTTON (user_data);
+	GcrImporter *importer;
+
+	importer = g_object_get_qdata (G_OBJECT (menu_item), QUARK_IMPORTER);
+	g_return_if_fail (GCR_IMPORTER (importer));
+	g_return_if_fail (self->pv->importing == FALSE);
+
+	begin_import (self, importer);
+	update_import_button (self);
+}
+
+static void
+update_importer_menu (GcrImportButton *self)
+{
+	GtkWidget *menu_item;
+	GtkWidget *image;
+	GList *children, *l;
+	GIcon *icon;
+	gchar *label;
+
+	if (!self->pv->menu) {
+		self->pv->menu = GTK_MENU (gtk_menu_new ());
+		g_object_ref_sink (self->pv->menu);
+	}
+
+	children = gtk_container_get_children (GTK_CONTAINER (self->pv->menu));
+	for (l = children; l != NULL; l = g_list_next (l))
+		gtk_container_remove (GTK_CONTAINER (self->pv->menu), l->data);
+	g_list_free (children);
+
+	for (l = self->pv->importers; l != NULL; l = g_list_next (l)) {
+		g_object_get (l->data, "label", &label, "icon", &icon, NULL);
+		menu_item = gtk_image_menu_item_new_with_label (label);
+		g_signal_connect (menu_item, "activate", G_CALLBACK (on_importer_menu_activated), self);
+		g_object_set_qdata (G_OBJECT (menu_item), QUARK_IMPORTER, l->data);
+		image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_MENU);
+		gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), image);
+		gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (menu_item), TRUE);
+		gtk_widget_show (image);
+		gtk_widget_show (menu_item);
+		gtk_container_add (GTK_CONTAINER (self->pv->menu), menu_item);
+		g_object_unref (icon);
+		g_free (label);
+	}
+}
+
+static void
+on_menu_position (GtkMenu *menu,
+                  gint *x,
+                  gint *y,
+                  gboolean *push_in,
+                  gpointer user_data)
+{
+	GcrImportButton *self = GCR_IMPORT_BUTTON (user_data);
+	GtkWidget *widget = GTK_WIDGET (self);
+	GtkAllocation allocation;
+	GtkRequisition menu_req;
+	GdkRectangle monitor;
+	GdkWindow *window;
+	GtkWidget *toplevel;
+	GdkScreen *screen;
+	gint monitor_num;
+	gint sx = 0;
+	gint sy = 0;
+
+	g_return_if_fail (x != NULL);
+	g_return_if_fail (y != NULL);
+	g_return_if_fail (push_in != NULL);
+
+	gtk_widget_get_allocation (widget, &allocation);
+
+	if (!gtk_widget_get_has_window (widget)) {
+		sx += allocation.x;
+		sy += allocation.y;
+	}
+
+	window = gtk_widget_get_window (widget);
+	gdk_window_get_root_coords (window, sx, sy, &sx, &sy);
+
+	gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &menu_req);
+	if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
+		*x = sx;
+	else
+		*x = sx + allocation.width - menu_req.width;
+	*y = sy;
+
+	screen = gtk_widget_get_screen (widget);
+	monitor_num = gdk_screen_get_monitor_at_window (screen, window);
+	if (monitor_num < 0)
+		monitor_num = 0;
+	gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+
+	if (*x < monitor.x)
+		*x = monitor.x;
+	else if (*x + menu_req.width > monitor.x + monitor.width)
+		*x = monitor.x + monitor.width - menu_req.width;
+
+	if (monitor.y + monitor.height - *y - allocation.height >= menu_req.height)
+		*y += allocation.height;
+	else if (*y - monitor.y >= menu_req.height)
+		*y -= menu_req.height;
+	else if (monitor.y + monitor.height - *y - allocation.height > *y - monitor.y)
+		*y += allocation.height;
+	else
+		*y -= menu_req.height;
+
+	gtk_menu_set_monitor (menu, monitor_num);
+
+	toplevel = gtk_widget_get_parent (GTK_WIDGET (menu));
+	if (GTK_IS_WINDOW (toplevel) && gtk_widget_get_visible (toplevel))
+		gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU);
+
+	*push_in = FALSE;
+}
+
+static void
+gcr_import_button_clicked (GtkButton *button)
+{
+	GcrImportButton *self = GCR_IMPORT_BUTTON (button);
+
+	g_return_if_fail (self->pv->importing == FALSE);
+	g_return_if_fail (self->pv->importers != NULL);
+
+	/* More than one importer, show the menu */
+	if (self->pv->importers->next) {
+		update_importer_menu (self);
+		gtk_menu_popup (self->pv->menu, NULL, NULL, on_menu_position,
+		                self, 1, gtk_get_current_event_time ());
+
+	/* Only one importer, import on click */
+	} else {
+		begin_import (self, self->pv->importers->data);
+	}
+
+	update_import_button (self);
+}
+
+static void
+gcr_import_button_class_init (GcrImportButtonClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GtkButtonClass *button_class = GTK_BUTTON_CLASS (klass);
+
+	gobject_class->constructed = gcr_import_button_constructed;
+	gobject_class->dispose = gcr_import_button_dispose;
+	gobject_class->finalize = gcr_import_button_finalize;
+	gobject_class->get_property = gcr_import_button_get_property;
+	gobject_class->set_property = gcr_import_button_set_property;
+
+	button_class->clicked = gcr_import_button_clicked;
+
+	g_object_class_override_property (gobject_class, PROP_LABEL, "label");
+
+	/**
+	 * GcrImportButton::imported:
+	 * @self: the import button
+	 * @importer: the importer that was imported to
+	 * @error: if import was successful %NULL, or an error
+	 *
+	 * Signal emitted when an import completes or fails.
+	 */
+	signals[IMPORTED] = g_signal_new ("imported", GCR_TYPE_IMPORT_BUTTON, G_SIGNAL_RUN_LAST,
+	                                  G_STRUCT_OFFSET (GcrImportButtonClass, imported),
+	                                  NULL, NULL, _gcr_marshal_VOID__OBJECT_BOXED,
+	                                  G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_ERROR);
+
+	QUARK_IMPORTER = g_quark_from_static_string ("gcr-import-button-importer");
+
+	g_type_class_add_private (klass, sizeof (GcrImportButtonPrivate));
+}
+
+GcrImportButton*
+gcr_import_button_new (const gchar *label)
+{
+	return g_object_new (GCR_TYPE_IMPORT_BUTTON,
+	                     "label", label,
+	                     NULL);
+}
+
+void
+gcr_import_button_add_parsed (GcrImportButton *self,
+                              GcrParser *parser)
+{
+	GList *importers;
+
+	g_return_if_fail (GCR_IS_IMPORT_BUTTON (self));
+	g_return_if_fail (GCR_IS_PARSER (parser));
+
+	g_free (self->pv->imported);
+	self->pv->imported = NULL;
+
+	if (self->pv->created) {
+		importers = gcr_importer_queue_and_filter_for_parsed (self->pv->importers, parser);
+	} else {
+		importers = gcr_importer_create_for_parsed (parser);
+		self->pv->created = TRUE;
+	}
+
+	gck_list_unref_free (self->pv->importers);
+	self->pv->importers = importers;
+
+	update_import_button (self);
+}
diff --git a/gcr/gcr-import-button.h b/gcr/gcr-import-button.h
new file mode 100644
index 0000000..35b116c
--- /dev/null
+++ b/gcr/gcr-import-button.h
@@ -0,0 +1,68 @@
+/*
+ * 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>
+ */
+
+#ifndef __GCR_IMPORT_BUTTON_H__
+#define __GCR_IMPORT_BUTTON_H__
+
+#include "gcr.h"
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GCR_TYPE_IMPORT_BUTTON               (gcr_import_button_get_type ())
+#define GCR_IMPORT_BUTTON(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_IMPORT_BUTTON, GcrImportButton))
+#define GCR_IMPORT_BUTTON_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_IMPORT_BUTTON, GcrImportButtonClass))
+#define GCR_IS_IMPORT_BUTTON(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_IMPORT_BUTTON))
+#define GCR_IS_IMPORT_BUTTON_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_IMPORT_BUTTON))
+#define GCR_IMPORT_BUTTON_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_IMPORT_BUTTON, GcrImportButtonClass))
+
+typedef struct _GcrImportButton GcrImportButton;
+typedef struct _GcrImportButtonClass GcrImportButtonClass;
+typedef struct _GcrImportButtonPrivate GcrImportButtonPrivate;
+
+struct _GcrImportButton {
+	GtkButton parent;
+
+	/*< private >*/
+	GcrImportButtonPrivate *pv;
+};
+
+struct _GcrImportButtonClass {
+	GtkButtonClass parent_class;
+
+	void    (*imported)    (GcrImportButton *self,
+	                        GcrImporter *importer,
+	                        GError *error);
+};
+
+GType               gcr_import_button_get_type               (void) G_GNUC_CONST;
+
+GcrImportButton *   gcr_import_button_new                    (const gchar *label);
+
+void                gcr_import_button_add_parsed             (GcrImportButton *button,
+                                                              GcrParser *parser);
+
+G_END_DECLS
+
+#endif /* __GCR_IMPORT_BUTTON_H__ */
diff --git a/gcr/gcr-list-selector.c b/gcr/gcr-list-selector.c
index b7e6beb..aacde0f 100644
--- a/gcr/gcr-list-selector.c
+++ b/gcr/gcr-list-selector.c
@@ -45,7 +45,6 @@
 
 /**
  * GcrListSelector:
- * @parent: Parent object
  *
  * A list selector widget.
  */
diff --git a/gcr/gcr-marshal.list b/gcr/gcr-marshal.list
index 09f114f..5e36589 100644
--- a/gcr/gcr-marshal.list
+++ b/gcr/gcr-marshal.list
@@ -3,3 +3,5 @@ BOOLEAN:BOXED
 VOID:STRING,BOXED
 VOID:BOXED
 VOID:STRING
+VOID:OBJECT,BOXED
+VOID:OBJECT,OBJECT
diff --git a/gcr/gcr-pkcs11-importer.c b/gcr/gcr-pkcs11-importer.c
index 714e13a..29a2972 100644
--- a/gcr/gcr-pkcs11-importer.c
+++ b/gcr/gcr-pkcs11-importer.c
@@ -332,7 +332,7 @@ calculate_icon (GcrPkcs11Importer *self)
 
 	info = gck_slot_get_token_info (self->pv->slot);
 	if (g_strcmp0 (info->manufacturer_id, "Gnome Keyring") == 0)
-		result = g_themed_icon_new ("home-folder");
+		result = g_themed_icon_new ("user-home");
 	else
 		result = g_themed_icon_new ("media-flash");
 	gck_token_info_free (info);
diff --git a/gcr/gcr-simple-collection.c b/gcr/gcr-simple-collection.c
index 05c17ae..2ac411a 100644
--- a/gcr/gcr-simple-collection.c
+++ b/gcr/gcr-simple-collection.c
@@ -40,7 +40,6 @@
 
 /**
  * GcrSimpleCollection:
- * @parent: The parent object
  *
  * A simple implementation of #GcrCollection.
  */
diff --git a/gcr/gcr-tree-selector.c b/gcr/gcr-tree-selector.c
index 11836b4..5cb2556 100644
--- a/gcr/gcr-tree-selector.c
+++ b/gcr/gcr-tree-selector.c
@@ -40,7 +40,6 @@
 
 /**
  * GcrTreeSelector:
- * @parent: The parent object
  *
  * A tree selector widget.
  */
diff --git a/gcr/gcr-union-collection.c b/gcr/gcr-union-collection.c
index 55e1785..dca7614 100644
--- a/gcr/gcr-union-collection.c
+++ b/gcr/gcr-union-collection.c
@@ -41,7 +41,6 @@
 
 /**
  * GcrUnionCollection:
- * @parent: The parent object
  *
  * A union implementation of #GcrCollection.
  */
diff --git a/gcr/gcr-unlock-renderer.c b/gcr/gcr-unlock-renderer.c
index 9d15678..4615057 100644
--- a/gcr/gcr-unlock-renderer.c
+++ b/gcr/gcr-unlock-renderer.c
@@ -50,6 +50,13 @@ struct _GcrUnlockRendererPrivate {
 	gint no_destroy;
 };
 
+enum {
+	UNLOCK_CLICKED,
+	LAST_SIGNAL,
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
 static void gcr_renderer_iface_init (GcrRendererIface *iface);
 
 G_DEFINE_TYPE_WITH_CODE (GcrUnlockRenderer, _gcr_unlock_renderer, GTK_TYPE_ALIGNMENT,
@@ -65,42 +72,15 @@ calculate_label (GcrUnlockRenderer *self)
 	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)
+void
+_gcr_unlock_renderer_show_warning (GcrUnlockRenderer *self,
+                                   const gchar *message)
 {
 	gchar *text;
 
+	g_return_if_fail (GCR_UNLOCK_RENDERER (self));
+	g_return_if_fail (message != NULL);
+
 	text = g_strdup_printf ("<i>%s</i>", message);
 	gtk_label_set_markup (self->pv->warning, text);
 	g_free (text);
@@ -113,34 +93,7 @@ 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));
+	g_signal_emit (self, signals[UNLOCK_CLICKED], 0);
 }
 
 static void
@@ -265,6 +218,10 @@ _gcr_unlock_renderer_class_init (GcrUnlockRendererClass *klass)
 	g_object_class_install_property (gobject_class, PROP_ATTRIBUTES,
 	           g_param_spec_boxed ("attributes", "Attributes", "Certificate pkcs11 attributes",
 	                               GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE));
+
+	signals[UNLOCK_CLICKED] = g_signal_new ("unlock-clicked", GCR_TYPE_UNLOCK_RENDERER, G_SIGNAL_RUN_LAST,
+	                                        G_STRUCT_OFFSET (GcrUnlockRendererClass, unlock_clicked),
+	                                        NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
 }
 
 static void
@@ -363,7 +320,26 @@ _gcr_unlock_renderer_new_for_parsed (GcrParser *parser)
 	gconstpointer block;
 	gsize n_block;
 
+	g_return_val_if_fail (GCR_IS_PARSER (parser), NULL);
+
 	block = gcr_parser_get_parsed_block (parser, &n_block);
 	return _gcr_unlock_renderer_new (gcr_parser_get_parsed_label (parser),
 	                                 block, n_block);
 }
+
+const gchar *
+_gcr_unlock_renderer_get_password (GcrUnlockRenderer *self)
+{
+	g_return_val_if_fail (GCR_IS_UNLOCK_RENDERER (self), NULL);
+	return gtk_entry_get_text (self->pv->entry);
+}
+
+gconstpointer
+_gcr_unlock_renderer_get_locked_data (GcrUnlockRenderer *self,
+                                      gsize *n_data)
+{
+	g_return_val_if_fail (GCR_IS_UNLOCK_RENDERER (self), NULL);
+	g_return_val_if_fail (n_data != NULL, NULL);
+	*n_data = self->pv->n_locked_data;
+	return self->pv->locked_data;
+}
diff --git a/gcr/gcr-unlock-renderer.h b/gcr/gcr-unlock-renderer.h
index 739133a..bc695b1 100644
--- a/gcr/gcr-unlock-renderer.h
+++ b/gcr/gcr-unlock-renderer.h
@@ -52,8 +52,10 @@ struct _GcrUnlockRenderer {
 };
 
 struct _GcrUnlockRendererClass {
-	/*< private >*/
 	GtkAlignmentClass parent_class;
+
+	/* signals */
+	void       (*unlock_clicked)        (GcrUnlockRenderer *unlock);
 };
 
 GType                  _gcr_unlock_renderer_get_type          (void);
@@ -64,6 +66,14 @@ GcrUnlockRenderer *    _gcr_unlock_renderer_new               (const gchar *labe
 
 GcrUnlockRenderer *    _gcr_unlock_renderer_new_for_parsed    (GcrParser *parser);
 
+const gchar *          _gcr_unlock_renderer_get_password      (GcrUnlockRenderer *self);
+
+void                   _gcr_unlock_renderer_show_warning      (GcrUnlockRenderer *self,
+                                                               const gchar *message);
+
+gconstpointer          _gcr_unlock_renderer_get_locked_data   (GcrUnlockRenderer *self,
+                                                               gsize *n_data);
+
 G_END_DECLS
 
 #endif /* __GCR_UNLOCK_RENDERER_H__ */
diff --git a/gcr/gcr-viewer-tool.c b/gcr/gcr-viewer-tool.c
index 2b0e260..85205ca 100644
--- a/gcr/gcr-viewer-tool.c
+++ b/gcr/gcr-viewer-tool.c
@@ -61,7 +61,7 @@ on_idle_load_files (gpointer user_data)
 	if (remaining_args) {
 		for (i = 0; remaining_args[i] != NULL; ++i) {
 			file = g_file_new_for_commandline_arg (remaining_args[i]);
-			gcr_viewer_window_load (window, file);
+			_gcr_viewer_window_load (window, file);
 			g_object_unref (file);
 		}
 
@@ -85,7 +85,7 @@ main (int argc, char *argv[])
 {
 	GOptionContext *context;
 	GError *error = NULL;
-	GcrViewerWindow *window;
+	GtkWindow *window;
 
 	g_type_init ();
 	g_thread_init (NULL);
@@ -119,7 +119,7 @@ main (int argc, char *argv[])
 
 	gtk_init (&argc, &argv);
 
-	window = gcr_viewer_window_new ();
+	window = _gcr_viewer_window_new ();
 	gtk_widget_show (GTK_WIDGET (window));
 
 	g_idle_add (on_idle_load_files, window);
diff --git a/gcr/gcr-viewer-widget.c b/gcr/gcr-viewer-widget.c
new file mode 100644
index 0000000..a4bf8c6
--- /dev/null
+++ b/gcr/gcr-viewer-widget.c
@@ -0,0 +1,436 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gcr-viewer-widget: Widget for viewer
+
+   Copyright (C) 2011 Collabora Ltd.
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  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-display-scrolled.h"
+#include "gcr-failure-renderer.h"
+#include "gcr-importer.h"
+#include "gcr-marshal.h"
+#include "gcr-parser.h"
+#include "gcr-renderer.h"
+#include "gcr-unlock-renderer.h"
+#include "gcr-viewer-widget.h"
+#include "gcr-viewer.h"
+
+#include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+
+#include <locale.h>
+#include <string.h>
+
+/**
+ * SECTION:gcr-viewer-widget
+ * @title: GcrViewerWidget
+ * @short_description: A widget which shows certificates or keys
+ *
+ * A viewer widget which can display certificates and keys that are
+ * located in files.
+ */
+
+/**
+ * GcrViewerWidget:
+ *
+ * A viewer widget object.
+ */
+
+/**
+ * GcrViewerWidgetClass:
+ *
+ * Class for #GcrViewerWidget
+ */
+
+/*
+ * Not yet figured out how to expose these without locking down our
+ * implementation, the parent class we derive from.
+ */
+
+struct _GcrViewerWidget {
+	/*< private >*/
+	GcrDisplayScrolled parent;
+	GcrViewerWidgetPrivate *pv;
+};
+
+struct _GcrViewerWidgetClass {
+	GcrDisplayScrolledClass parent_class;
+
+	void       (*added)        (GcrViewerWidget *widget,
+	                            GcrRenderer *renderer,
+	                            GcrParser *parser);
+};
+
+struct _GcrViewerWidgetPrivate {
+	GQueue *files_to_load;
+	GcrParser *parser;
+	GCancellable *cancellable;
+	GList *unlocks;
+	gboolean loading;
+	gchar *display_name;
+};
+
+enum {
+	ADDED,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+static void viewer_load_next_file (GcrViewerWidget *self);
+static void viewer_stop_loading_files (GcrViewerWidget *self);
+
+G_DEFINE_TYPE (GcrViewerWidget, gcr_viewer_widget, GCR_TYPE_DISPLAY_SCROLLED);
+
+static const gchar *
+get_parsed_label_or_display_name (GcrViewerWidget *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)
+{
+	GcrViewerWidget *self = GCR_VIEWER_WIDGET (user_data);
+	GckAttributes *attrs;
+	GcrRenderer *renderer;
+	const gchar *label;
+	gboolean actual = TRUE;
+
+	label = get_parsed_label_or_display_name (self, parser);
+	attrs = gcr_parser_get_parsed_attributes (parser);
+
+	renderer = gcr_renderer_create (label, attrs);
+
+	if (renderer == NULL) {
+		renderer = gcr_failure_renderer_new_unsupported (label);
+		actual = FALSE;
+	}
+
+	/* And show the data */
+	gcr_viewer_add_renderer (GCR_VIEWER (self), renderer);
+
+	/* Let callers know we're rendering data */
+	if (actual == TRUE)
+		g_signal_emit (self, signals[ADDED], 0, renderer, parser);
+
+	g_object_unref (renderer);
+}
+
+static gboolean
+on_parser_authenticate_for_unlock (GcrParser *parser,
+                                   guint count,
+                                   gpointer user_data)
+{
+	GcrUnlockRenderer *unlock = GCR_UNLOCK_RENDERER (user_data);
+	const gchar *password;
+
+	if (count == 0) {
+		password = _gcr_unlock_renderer_get_password (unlock);
+		gcr_parser_add_password (parser, password);
+	}
+
+	return TRUE;
+}
+
+static void
+on_unlock_renderer_clicked (GcrUnlockRenderer *unlock,
+                            gpointer user_data)
+{
+	GcrViewerWidget *self = GCR_VIEWER_WIDGET (user_data);
+	GError *error = NULL;
+	gconstpointer data;
+	gsize n_data;
+	gulong sig;
+
+	/* Override our main authenticate signal handler */
+	sig = g_signal_connect (self->pv->parser, "authenticate",
+	                        G_CALLBACK (on_parser_authenticate_for_unlock), unlock);
+
+	data = _gcr_unlock_renderer_get_locked_data (unlock, &n_data);
+	if (gcr_parser_parse_data (self->pv->parser, data, n_data, &error)) {
+
+		/* Done with this unlock renderer */
+		gcr_viewer_remove_renderer (GCR_VIEWER (self), GCR_RENDERER (unlock));
+		self->pv->unlocks = g_list_remove (self->pv->unlocks, unlock);
+		g_object_unref (unlock);
+
+	} else if (g_error_matches (error, GCR_DATA_ERROR, GCR_ERROR_LOCKED)){
+		_gcr_unlock_renderer_show_warning (unlock,  _("The password was incorrect"));
+		g_error_free (error);
+
+	} else {
+		_gcr_unlock_renderer_show_warning (unlock, error->message);
+		g_error_free (error);
+	}
+
+	g_signal_handler_disconnect (self->pv->parser, sig);
+}
+
+static gboolean
+on_parser_authenticate_for_data (GcrParser *parser,
+                                 guint count,
+                                 gpointer user_data)
+{
+	GcrViewerWidget *self = GCR_VIEWER_WIDGET (user_data);
+	GcrUnlockRenderer *unlock;
+
+	unlock = _gcr_unlock_renderer_new_for_parsed (parser);
+	if (unlock != NULL) {
+		g_object_set (unlock, "label", get_parsed_label_or_display_name (self, parser), NULL);
+		gcr_viewer_add_renderer (GCR_VIEWER (self), GCR_RENDERER (unlock));
+		g_signal_connect (unlock, "unlock-clicked", G_CALLBACK (on_unlock_renderer_clicked), self);
+		self->pv->unlocks = g_list_prepend (self->pv->unlocks, unlock);
+	}
+
+	return TRUE;
+}
+
+static void
+gcr_viewer_widget_init (GcrViewerWidget *self)
+{
+	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_VIEWER_WIDGET,
+	                                        GcrViewerWidgetPrivate);
+
+	self->pv->files_to_load = g_queue_new ();
+	self->pv->parser = gcr_parser_new ();
+	self->pv->cancellable = g_cancellable_new ();
+	self->pv->unlocks = NULL;
+
+	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_for_data), self);
+}
+
+static void
+gcr_viewer_widget_dispose (GObject *obj)
+{
+	GcrViewerWidget *self = GCR_VIEWER_WIDGET (obj);
+	GList *l;
+
+	g_signal_handlers_disconnect_by_func (self->pv->parser, on_parser_parsed, self);
+
+	for (l = self->pv->unlocks; l != NULL; l = g_list_next (l)) {
+		g_signal_handlers_disconnect_by_func (l->data, on_unlock_renderer_clicked, self);
+		g_object_unref (l->data);
+	}
+	g_list_free (self->pv->unlocks);
+	self->pv->unlocks = NULL;
+
+	while (!g_queue_is_empty (self->pv->files_to_load))
+		g_object_unref (g_queue_pop_head (self->pv->files_to_load));
+
+	g_cancellable_cancel (self->pv->cancellable);
+
+	G_OBJECT_CLASS (gcr_viewer_widget_parent_class)->dispose (obj);
+}
+
+static void
+gcr_viewer_widget_finalize (GObject *obj)
+{
+	GcrViewerWidget *self = GCR_VIEWER_WIDGET (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);
+
+	G_OBJECT_CLASS (gcr_viewer_widget_parent_class)->finalize (obj);
+}
+
+static void
+gcr_viewer_widget_class_init (GcrViewerWidgetClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+	gobject_class->dispose = gcr_viewer_widget_dispose;
+	gobject_class->finalize = gcr_viewer_widget_finalize;
+
+	g_type_class_add_private (klass, sizeof (GcrViewerWidget));
+
+	signals[ADDED] = g_signal_new ("added", GCR_TYPE_VIEWER_WIDGET, G_SIGNAL_RUN_LAST,
+	                               G_STRUCT_OFFSET (GcrViewerWidgetClass, added),
+	                               NULL, NULL, _gcr_marshal_VOID__OBJECT_OBJECT,
+	                               G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_OBJECT);
+}
+
+static void
+on_parser_parse_stream_returned (GObject *source,
+                                 GAsyncResult *result,
+                                 gpointer user_data)
+{
+	GcrViewerWidget *self = GCR_VIEWER_WIDGET (user_data);
+	GError *error = NULL;
+	GcrRenderer *renderer;
+
+	gcr_parser_parse_stream_finish (self->pv->parser, result, &error);
+
+	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
+	    g_error_matches (error, GCR_DATA_ERROR, GCR_ERROR_CANCELLED)) {
+		viewer_stop_loading_files (self);
+
+	} else if (g_error_matches (error, GCR_DATA_ERROR, GCR_ERROR_LOCKED)) {
+		/* Just skip this one, an unlock renderer was added */
+
+	} else if (error) {
+		renderer = gcr_failure_renderer_new (self->pv->display_name, error);
+		gcr_viewer_add_renderer (GCR_VIEWER (self), renderer);
+		g_object_unref (renderer);
+		g_error_free (error);
+	}
+
+	viewer_load_next_file (self);
+}
+
+static void
+update_display_name (GcrViewerWidget *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
+on_file_read_returned (GObject *source,
+                       GAsyncResult *result,
+                       gpointer user_data)
+{
+	GcrViewerWidget *self = GCR_VIEWER_WIDGET (user_data);
+	GFile *file = G_FILE (source);
+	GError *error = NULL;
+	GFileInputStream *fis;
+	GcrRenderer *renderer;
+
+	fis = g_file_read_finish (file, result, &error);
+	update_display_name (self, file);
+
+	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+		viewer_stop_loading_files (self);
+
+	} else if (error) {
+		renderer = gcr_failure_renderer_new (self->pv->display_name, error);
+		gcr_viewer_add_renderer (GCR_VIEWER (self), renderer);
+		g_object_unref (renderer);
+		g_error_free (error);
+
+		viewer_load_next_file (self);
+
+	} else {
+		gcr_parser_parse_stream_async (self->pv->parser, G_INPUT_STREAM (fis),
+		                               self->pv->cancellable, on_parser_parse_stream_returned,
+		                               self);
+		g_object_unref (fis);
+	}
+}
+
+static void
+viewer_stop_loading_files (GcrViewerWidget *self)
+{
+	self->pv->loading = FALSE;
+}
+
+static void
+viewer_load_next_file (GcrViewerWidget *self)
+{
+	GFile* file;
+
+	file = g_queue_pop_head (self->pv->files_to_load);
+	if (file == NULL) {
+		viewer_stop_loading_files (self);
+		return;
+	}
+
+	g_file_read_async (file, G_PRIORITY_DEFAULT, self->pv->cancellable,
+	                   on_file_read_returned, self);
+
+	g_object_unref (file);
+}
+
+/**
+ * gcr_viewer_widget_new:
+ *
+ * Create a new viewer widget.
+ *
+ * Returns: (transfer full): A new #GcrViewerWidget object
+ */
+GcrViewerWidget *
+gcr_viewer_widget_new (void)
+{
+	return g_object_new (GCR_TYPE_VIEWER_WIDGET, NULL);
+}
+
+/**
+ * gcr_viewer_widget_load_file:
+ * @self: a viewer widget
+ * @file: a file to load
+ *
+ * Display contents of a file in the viewer widget. Multiple files can
+ * be loaded.
+ */
+void
+gcr_viewer_widget_load_file (GcrViewerWidget *self,
+                             GFile *file)
+{
+	g_return_if_fail (GCR_IS_VIEWER_WIDGET (self));
+	g_return_if_fail (G_IS_FILE (file));
+
+	g_queue_push_tail (self->pv->files_to_load, g_object_ref (file));
+
+	if (!self->pv->loading)
+		viewer_load_next_file (self);
+}
+
+void
+gcr_viewer_widget_load_data (GcrViewerWidget *self,
+                             const gchar *display_name,
+                             gconstpointer *data,
+                             gsize n_data)
+{
+	GError *error = NULL;
+	GcrRenderer *renderer;
+
+	g_return_if_fail (GCR_IS_VIEWER_WIDGET (self));
+
+	g_free (self->pv->display_name);
+	self->pv->display_name = g_strdup (display_name);
+
+	if (!gcr_parser_parse_data (self->pv->parser, data, n_data, &error)) {
+		renderer = gcr_failure_renderer_new (display_name, error);
+		gcr_viewer_add_renderer (GCR_VIEWER (self), renderer);
+		g_object_unref (renderer);
+		g_error_free (error);
+	}
+}
diff --git a/gcr/gcr-viewer-widget.h b/gcr/gcr-viewer-widget.h
new file mode 100644
index 0000000..a4dbbb1
--- /dev/null
+++ b/gcr/gcr-viewer-widget.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gcr-viewer-widget.h: Widget for viewer
+
+   Copyright (C) 2011 Collabora Ltd.
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  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>
+*/
+
+#ifndef GCR_VIEWER_WIDGET_H
+#define GCR_VIEWER_WIDGET_H
+
+#include <gtk/gtk.h>
+
+#define GCR_TYPE_VIEWER_WIDGET               (gcr_viewer_widget_get_type ())
+#define GCR_VIEWER_WIDGET(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_VIEWER_WIDGET, GcrViewerWidget))
+#define GCR_VIEWER_WIDGET_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_VIEWER_WIDGET, GcrViewerWidgetClass))
+#define GCR_IS_VIEWER_WIDGET(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_VIEWER_WIDGET))
+#define GCR_IS_VIEWER_WIDGET_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_VIEWER_WIDGET))
+#define GCR_VIEWER_WIDGET_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_VIEWER_WIDGET, GcrViewerWidgetClass))
+
+typedef struct _GcrViewerWidget GcrViewerWidget;
+typedef struct _GcrViewerWidgetClass GcrViewerWidgetClass;
+typedef struct _GcrViewerWidgetPrivate GcrViewerWidgetPrivate;
+
+
+GType              gcr_viewer_widget_get_type         (void);
+
+GcrViewerWidget *  gcr_viewer_widget_new              (void);
+
+void               gcr_viewer_widget_load_file        (GcrViewerWidget *self,
+                                                       GFile *file);
+
+void               gcr_viewer_widget_load_data        (GcrViewerWidget *self,
+                                                       const gchar *display_name,
+                                                       gconstpointer *data,
+                                                       gsize n_data);
+
+#endif /* GCR_VIEWER_WIDGET_H */
diff --git a/gcr/gcr-viewer-window.c b/gcr/gcr-viewer-window.c
index 44e2f30..6301917 100644
--- a/gcr/gcr-viewer-window.c
+++ b/gcr/gcr-viewer-window.c
@@ -23,12 +23,7 @@
 
 #include "config.h"
 
-#include "gcr-failure-renderer.h"
-#include "gcr-parser.h"
-#include "gcr-renderer.h"
-#include "gcr-unlock-renderer.h"
 #include "gcr-viewer-window.h"
-#include "gcr-viewer.h"
 
 #include <glib/gi18n-lib.h>
 #include <gtk/gtk.h>
@@ -36,342 +31,134 @@
 #include <locale.h>
 #include <string.h>
 
-/**
- * SECTION:gcr-viewer-window
- * @title: GcrViewerWindow
- * @short_description: A window which shows certificates or keys
- *
- * A viewer window which can display certificates and keys that are
- * located in files.
- */
-
-/**
- * GcrViewerWindow:
- *
- * A viewer window object.
- */
-
-/**
- * GcrViewerWindowClass:
- *
- * Class for #GcrViewerWindow
- */
-
 struct _GcrViewerWindowPrivate {
-	GQueue *files_to_load;
-	GcrParser *parser;
-	GCancellable *cancellable;
-	GcrViewer *viewer;
-	gboolean loading;
-	gchar *display_name;
+	GcrViewerWidget *viewer;
+	GcrImportButton *import;
 };
 
-static void viewer_load_next_file (GcrViewerWindow *self);
-static void viewer_stop_loading_files (GcrViewerWindow *self);
-
-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;
-}
+G_DEFINE_TYPE (GcrViewerWindow, _gcr_viewer_window, GTK_TYPE_WINDOW);
 
 static void
-on_parser_parsed (GcrParser *parser, gpointer user_data)
+on_viewer_renderer_added (GcrViewerWidget *viewer,
+                          GcrRenderer *renderer,
+                          GcrParser *parser,
+                          gpointer user_data)
 {
 	GcrViewerWindow *self = GCR_VIEWER_WINDOW (user_data);
-	GcrRenderer *renderer;
-
-	renderer = gcr_renderer_create (get_parsed_label_or_display_name (self, parser),
-	                                gcr_parser_get_parsed_attributes (parser));
-
-	if (renderer == NULL)
-		renderer = _gcr_failure_renderer_new_unsupported (get_parsed_label_or_display_name (self, parser));
-
-	gcr_viewer_add_renderer (self->pv->viewer, renderer);
-	g_object_unref (renderer);
-}
-
-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;
+	gcr_import_button_add_parsed (self->pv->import, parser);
 }
 
 static void
-gcr_viewer_window_init (GcrViewerWindow *self)
+_gcr_viewer_window_init (GcrViewerWindow *self)
 {
 	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_VIEWER_WINDOW,
 	                                        GcrViewerWindowPrivate);
-
-	self->pv->files_to_load = g_queue_new ();
-	self->pv->parser = gcr_parser_new ();
-	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
-gcr_viewer_window_constructed (GObject *obj)
-{
-	GcrViewerWindow *self = GCR_VIEWER_WINDOW (obj);
-
-	if (G_OBJECT_CLASS (gcr_viewer_window_parent_class)->constructed)
-		G_OBJECT_CLASS (gcr_viewer_window_parent_class)->constructed (obj);
-
-	self->pv->viewer = gcr_viewer_new_scrolled ();
-
-	gtk_widget_show (GTK_WIDGET (self->pv->viewer));
-	gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->pv->viewer));
-
-	gtk_window_set_default_size (GTK_WINDOW (self), 250, 400);
-}
-
-static void
-gcr_viewer_window_dispose (GObject *obj)
-{
-	GcrViewerWindow *self = GCR_VIEWER_WINDOW (obj);
-
-	g_signal_handlers_disconnect_by_func (self->pv->parser, on_parser_parsed, self);
-
-	while (!g_queue_is_empty (self->pv->files_to_load))
-		g_object_unref (g_queue_pop_head (self->pv->files_to_load));
-
-	g_cancellable_cancel (self->pv->cancellable);
-
-	G_OBJECT_CLASS (gcr_viewer_window_parent_class)->dispose (obj);
-}
-
-static void
-gcr_viewer_window_finalize (GObject *obj)
-{
-	GcrViewerWindow *self = GCR_VIEWER_WINDOW (obj);
-
-	/* self->pv->viewer is owned by container */
-
-	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);
-
-	G_OBJECT_CLASS (gcr_viewer_window_parent_class)->finalize (obj);
-}
-
-static void
-gcr_viewer_window_class_init (GcrViewerWindowClass *klass)
-{
-	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
-	gcr_viewer_window_parent_class = g_type_class_peek_parent (klass);
-
-	gobject_class->dispose = gcr_viewer_window_dispose;
-	gobject_class->finalize = gcr_viewer_window_finalize;
-	gobject_class->constructed = gcr_viewer_window_constructed;
-
-	g_type_class_add_private (klass, sizeof (GcrViewerWindow));
-}
-
-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)
+on_import_button_imported (GcrImportButton *button,
+                           GcrImporter *importer,
+                           GError *error,
+                           gpointer user_data)
 {
 	GcrViewerWindow *self = GCR_VIEWER_WINDOW (user_data);
-	GError *error = NULL;
 	GcrRenderer *renderer;
 
-	gcr_parser_parse_stream_finish (self->pv->parser, result, &error);
-
-	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
-	    g_error_matches (error, GCR_DATA_ERROR, GCR_ERROR_CANCELLED)) {
-		viewer_stop_loading_files (self);
+	if (error == NULL) {
+		g_object_set (button, "label", _("Imported"), NULL);
 
-	} else if (g_error_matches (error, GCR_DATA_ERROR, GCR_ERROR_LOCKED)) {
-		/* Just skip this one, an unlock renderer was added */
-
-	} else if (error) {
-		renderer = _gcr_failure_renderer_new (self->pv->display_name, error);
-		gcr_viewer_add_renderer (self->pv->viewer, renderer);
-		g_object_unref (renderer);
-		g_error_free (error);
+	} else {
+		if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+			renderer = gcr_failure_renderer_new (_("Import failed"), error);
+			gcr_viewer_add_renderer (GCR_VIEWER (self->pv->viewer), renderer);
+			g_object_unref (renderer);
+		}
 	}
-
-	viewer_load_next_file (self);
 }
 
 static void
-update_display_name (GcrViewerWindow *self,
-                     GFile *file)
+on_close_clicked (GtkButton *button,
+                  gpointer user_data)
 {
-	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);
+	GcrViewerWindow *self = GCR_VIEWER_WINDOW (user_data);
+	gtk_widget_destroy (GTK_WIDGET (self));
 }
 
 static void
-on_file_read_returned (GObject *source, GAsyncResult *result, gpointer user_data)
+_gcr_viewer_window_constructed (GObject *obj)
 {
-	GcrViewerWindow *self = GCR_VIEWER_WINDOW (user_data);
-	GFile *file = G_FILE (source);
-	GError *error = NULL;
-	GFileInputStream *fis;
-	GcrRenderer *renderer;
-
-	fis = g_file_read_finish (file, result, &error);
-	update_display_name (self, file);
-
-	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-		viewer_stop_loading_files (self);
+	GcrViewerWindow *self = GCR_VIEWER_WINDOW (obj);
+	GtkWidget *bbox;
+	GtkWidget *box;
+	GtkWidget *button;
+	GtkWidget *align;
+
+	G_OBJECT_CLASS (_gcr_viewer_window_parent_class)->constructed (obj);
+
+	bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
+	gtk_box_set_spacing (GTK_BOX (bbox), 12);
+	gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
+	gtk_widget_show (bbox);
+
+	self->pv->import = gcr_import_button_new (_("Import"));
+	g_signal_connect_object (self->pv->import, "imported",
+	                         G_CALLBACK (on_import_button_imported),
+	                         self, 0);
+	gtk_widget_show (GTK_WIDGET (self->pv->import));
+
+	button = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
+	g_signal_connect_object  (button, "clicked",
+	                          G_CALLBACK (on_close_clicked),
+	                          self, 0);
+	gtk_widget_show (button);
+
+	gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, TRUE, 0);
+	gtk_box_pack_start (GTK_BOX (bbox), GTK_WIDGET (self->pv->import), FALSE, TRUE, 0);
+
+	align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+	gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, 12);
+	gtk_widget_show (align);
+	gtk_container_add (GTK_CONTAINER (align), bbox);
+
+	self->pv->viewer = gcr_viewer_widget_new ();
+	g_signal_connect_object (self->pv->viewer, "added",
+	                         G_CALLBACK (on_viewer_renderer_added),
+	                         self, 0);
+	gtk_widget_show (GTK_WIDGET (self->pv->viewer));
 
-	} else if (error) {
-		renderer = _gcr_failure_renderer_new (self->pv->display_name, error);
-		gcr_viewer_add_renderer (self->pv->viewer, renderer);
-		g_object_unref (renderer);
-		g_error_free (error);
+	box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+	gtk_widget_show (box);
 
-		viewer_load_next_file (self);
+	gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (self->pv->viewer), TRUE, TRUE, 0);
+	gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 6);
 
-	} else {
-		gcr_parser_parse_stream_async (self->pv->parser, G_INPUT_STREAM (fis),
-		                               self->pv->cancellable, on_parser_parse_stream_returned,
-		                               self);
-		g_object_unref (fis);
-	}
-}
+	gtk_container_add (GTK_CONTAINER (self), box);
 
-static void
-viewer_stop_loading_files (GcrViewerWindow *self)
-{
-	self->pv->loading = FALSE;
+	gtk_window_set_default_size (GTK_WINDOW (self), 250, 400);
 }
 
 static void
-viewer_load_next_file (GcrViewerWindow *self)
+_gcr_viewer_window_class_init (GcrViewerWindowClass *klass)
 {
-	GFile* file;
-
-	file = g_queue_pop_head (self->pv->files_to_load);
-	if (file == NULL) {
-		viewer_stop_loading_files (self);
-		return;
-	}
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
-	g_file_read_async (file, G_PRIORITY_DEFAULT, self->pv->cancellable,
-	                   on_file_read_returned, self);
+	gobject_class->constructed = _gcr_viewer_window_constructed;
 
-	g_object_unref (file);
+	g_type_class_add_private (klass, sizeof (GcrViewerWindow));
 }
 
-/**
- * gcr_viewer_window_new:
- *
- * Create a new viewer window.
- *
- * Returns: (transfer full): A new #GcrViewerWindow object
- */
-GcrViewerWindow *
-gcr_viewer_window_new (void)
+GtkWindow *
+_gcr_viewer_window_new (void)
 {
 	return g_object_new (GCR_TYPE_VIEWER_WINDOW, NULL);
 }
 
-/**
- * gcr_viewer_window_load:
- * @self: a viewer window
- * @file: a file to load
- *
- * Display contents of a file in the viewer window. Multiple files can
- * be loaded.
- */
 void
-gcr_viewer_window_load (GcrViewerWindow *self, GFile *file)
+_gcr_viewer_window_load (GcrViewerWindow *self,
+                         GFile *file)
 {
 	g_return_if_fail (GCR_IS_VIEWER_WINDOW (self));
 	g_return_if_fail (G_IS_FILE (file));
 
-	g_queue_push_tail (self->pv->files_to_load, g_object_ref (file));
-
-	if (!self->pv->loading)
-		viewer_load_next_file (self);
+	return gcr_viewer_widget_load_file (self->pv->viewer, file);
 }
diff --git a/gcr/gcr-viewer-window.h b/gcr/gcr-viewer-window.h
index d5ac88d..90b0744 100644
--- a/gcr/gcr-viewer-window.h
+++ b/gcr/gcr-viewer-window.h
@@ -26,7 +26,9 @@
 
 #include <gtk/gtk.h>
 
-#define GCR_TYPE_VIEWER_WINDOW               (gcr_viewer_window_get_type ())
+#include "gcr/gcr.h"
+
+#define GCR_TYPE_VIEWER_WINDOW               (_gcr_viewer_window_get_type ())
 #define GCR_VIEWER_WINDOW(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_VIEWER_WINDOW, GcrViewerWindow))
 #define GCR_VIEWER_WINDOW_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_VIEWER_WINDOW, GcrViewerWindowClass))
 #define GCR_IS_VIEWER_WINDOW(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_VIEWER_WINDOW))
@@ -48,11 +50,11 @@ struct _GcrViewerWindowClass {
 	GtkWindowClass parent_class;
 };
 
-GType              gcr_viewer_window_get_type         (void);
+GType              _gcr_viewer_window_get_type         (void);
 
-GcrViewerWindow *  gcr_viewer_window_new              (void);
+GtkWindow *        _gcr_viewer_window_new              (void);
 
-void               gcr_viewer_window_load             (GcrViewerWindow *self,
-                                                       GFile *file);
+void               _gcr_viewer_window_load             (GcrViewerWindow *self,
+                                                        GFile *file);
 
 #endif /* GCR_VIEWER_WINDOW_H */
diff --git a/gcr/gcr-viewer.c b/gcr/gcr-viewer.c
index 26b65df..b210c61 100644
--- a/gcr/gcr-viewer.c
+++ b/gcr/gcr-viewer.c
@@ -57,31 +57,14 @@
  * The interface for #GcrViewer
  */
 
-static void
-gcr_viewer_base_init (gpointer gobject_iface)
-{
-	static gboolean initialized = FALSE;
-	if (!initialized) {
+typedef GcrViewerIface GcrViewerInterface;
 
-		initialized = TRUE;
-	}
-}
+G_DEFINE_INTERFACE (GcrViewer, gcr_viewer, GTK_TYPE_WIDGET);
 
-GType
-gcr_viewer_get_type (void)
+static void
+gcr_viewer_default_init (GcrViewerIface *iface)
 {
-	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;
+
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/gcr/gcr.h b/gcr/gcr.h
index b3078ee..ec150a9 100644
--- a/gcr/gcr.h
+++ b/gcr/gcr.h
@@ -42,14 +42,18 @@
 #include "gcr-deprecated.h"
 #include "gcr-key-renderer.h"
 #include "gcr-key-widget.h"
-#include "gcr-importer.h"
+#include "gcr-enum-types.h"
+#include "gcr-failure-renderer.h"
+#include "gcr-key-renderer.h"
+#include "gcr-key-widget.h"
+#include "gcr-import-button.h"
 #include "gcr-list-selector.h"
 #include "gcr-renderer.h"
 #include "gcr-tree-selector.h"
 #include "gcr-union-collection.h"
 #include "gcr-unlock-options-widget.h"
 #include "gcr-viewer.h"
-#include "gcr-viewer-window.h"
+#include "gcr-viewer-widget.h"
 
 #undef __GCR_INSIDE_HEADER__
 
diff --git a/gcr/tests/Makefile.am b/gcr/tests/Makefile.am
index 15c0cb8..018f0bb 100644
--- a/gcr/tests/Makefile.am
+++ b/gcr/tests/Makefile.am
@@ -61,3 +61,7 @@ noinst_PROGRAMS = \
 	frob-parser \
 	frob-unlock \
 	frob-unlock-options
+
+frob_unlock_SOURCES = \
+	frob-unlock.c \
+	../gcr-viewer-window.c
diff --git a/gcr/tests/frob-unlock.c b/gcr/tests/frob-unlock.c
index 3a7f511..ac9c608 100644
--- a/gcr/tests/frob-unlock.c
+++ b/gcr/tests/frob-unlock.c
@@ -25,6 +25,7 @@
 
 #include "gcr/gcr.h"
 #include "gcr/gcr-unlock-renderer.h"
+#include "gcr/gcr-viewer-window.h"
 
 #include <gtk/gtk.h>
 
@@ -55,7 +56,7 @@ on_parser_authenticate (GcrParser *parser,
 	GcrUnlockRenderer *renderer;
 	GtkWindow *window;
 
-	window = GTK_WINDOW (gcr_viewer_window_new ());
+	window = GTK_WINDOW (_gcr_viewer_window_new ());
 	g_object_ref_sink (window);
 
 	renderer = _gcr_unlock_renderer_new_for_parsed (parser);



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