[gcr] gcr: Add frob-prompt tool and fix bugs



commit 3d8fd1a2f4ed07f049784e8f5f7ec17b1893d26f
Author: Stef Walter <stefw collabora co uk>
Date:   Sun Dec 18 18:22:47 2011 +0100

    gcr: Add frob-prompt tool and fix bugs
    
     * Add frob-prompt tool for playing around with prompts
     * Fix tons of bugs and refactor where necessary

 gcr/Makefile.am                                    |    4 +-
 gcr/gcr-dbus-constants.h                           |    4 +-
 gcr/gcr-prompt-dialog.c                            |   61 +++--
 gcr/gcr-prompter-tool.c                            |   62 ++++-
 gcr/gcr-system-prompt.c                            |   20 +-
 gcr/gcr-system-prompt.h                            |    6 +-
 gcr/gcr-system-prompter.c                          |  296 +++++++++++---------
 ...> org.gnome.keyring.PrivatePrompter.service.in} |    0
 ...=> org.gnome.keyring.SystemPrompter.service.in} |    0
 gcr/tests/Makefile.am                              |    1 +
 gcr/tests/files/prompt-tests/simple.prompt         |   28 ++
 gcr/tests/frob-prompt.c                            |  202 +++++++++++++
 gcr/tests/frob-system-prompt.c                     |    2 +-
 gcr/tests/test-system-prompt.c                     |   67 ++---
 14 files changed, 541 insertions(+), 212 deletions(-)
---
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index be40c75..8e3b63b 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -309,7 +309,9 @@ desktop_in_files = $(desktop_in_in_files:.desktop.in.in=.desktop.in)
 desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
 @INTLTOOL_DESKTOP_RULE@
 
-service_in_files = org.gnome.keyring.Prompter.service.in
+service_in_files = \
+	org.gnome.keyring.SystemPrompter.service.in \
+	org.gnome.keyring.PrivatePrompter.service.in
 servicedir       = $(DBUS_SERVICES_DIR)
 service_DATA     = $(service_in_files:.service.in=.service)
 
diff --git a/gcr/gcr-dbus-constants.h b/gcr/gcr-dbus-constants.h
index aead8ab..2d7468f 100644
--- a/gcr/gcr-dbus-constants.h
+++ b/gcr/gcr-dbus-constants.h
@@ -29,11 +29,11 @@
 G_BEGIN_DECLS
 
 #define GCR_DBUS_PROMPTER_SYSTEM_BUS_NAME            "org.gnome.keyring.SystemPrompter"
-#define GCR_DBUS_PROMPTER_BUS_NAME                   "org.gnome.keyring.Prompter"
+#define GCR_DBUS_PROMPTER_PRIVATE_BUS_NAME           "org.gnome.keyring.PrivatePrompter"
 #define GCR_DBUS_PROMPTER_MOCK_BUS_NAME              "org.gnome.keyring.MockPrompter"
 
 #define GCR_DBUS_PROMPTER_OBJECT_PATH                "/org/gnome/keyring/Prompter"
-#define GCR_DBUS_PROMPT_OBJECT_PREFIX                "/org/gnome/keyring/internal/Prompt"
+#define GCR_DBUS_PROMPT_OBJECT_PREFIX                "/org/gnome/keyring/Prompt"
 
 #define GCR_DBUS_PROMPTER_INTERFACE                  "org.gnome.keyring.internal.Prompter"
 
diff --git a/gcr/gcr-prompt-dialog.c b/gcr/gcr-prompt-dialog.c
index 2169929..fc4efdb 100644
--- a/gcr/gcr-prompt-dialog.c
+++ b/gcr/gcr-prompt-dialog.c
@@ -56,8 +56,7 @@
  * The class for #GcrPromptDialog.
  */
 
-#define LOG_ERRORS 1
-#define GRAB_KEYBOARD 1
+#define GRAB_KEYBOARD 0
 
 typedef enum {
 	PROMPT_NONE,
@@ -67,7 +66,6 @@ typedef enum {
 
 enum {
 	PROP_0,
-	PROP_TITLE,
 	PROP_MESSAGE,
 	PROP_DESCRIPTION,
 	PROP_WARNING,
@@ -157,6 +155,12 @@ gcr_prompt_dialog_init (GcrPromptDialog *self)
 {
 	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_PROMPT_DIALOG,
 	                                        GcrPromptDialogPrivate);
+
+	/*
+	 * This is a stupid hack to work around to help the window act like
+	 * a normal object with regards to reference counting and unref.
+	 */
+	gtk_window_set_has_user_ref_count (GTK_WINDOW (self), FALSE);
 }
 
 static void
@@ -168,11 +172,6 @@ gcr_prompt_dialog_set_property (GObject *obj,
 	GcrPromptDialog *self = GCR_PROMPT_DIALOG (obj);
 
 	switch (prop_id) {
-	case PROP_TITLE:
-		g_free (self->pv->title);
-		self->pv->title = g_value_dup_string (value);
-		g_object_notify (obj, "title");
-		break;
 	case PROP_MESSAGE:
 		g_free (self->pv->message);
 		self->pv->message = g_value_dup_string (value);
@@ -191,6 +190,7 @@ gcr_prompt_dialog_set_property (GObject *obj,
 			self->pv->warning = NULL;
 		}
 		g_object_notify (obj, "warning");
+		g_object_notify (obj, "warning-visible");
 		break;
 	case PROP_CHOICE_LABEL:
 		g_free (self->pv->choice_label);
@@ -200,9 +200,16 @@ gcr_prompt_dialog_set_property (GObject *obj,
 			self->pv->choice_label = NULL;
 		}
 		g_object_notify (obj, "choice-label");
+		g_object_notify (obj, "choice-visible");
+		break;
+	case PROP_CHOICE_CHOSEN:
+		self->pv->choice_chosen = g_value_get_boolean (value);
+		g_object_notify (obj, "choice-chosen");
 		break;
 	case PROP_PASSWORD_NEW:
 		self->pv->password_new = g_value_get_boolean (value);
+		g_object_notify (obj, "password-new");
+		g_object_notify (obj, "confirm-visible");
 		break;
 	case PROP_CALLER_WINDOW:
 		g_free (self->pv->caller_window);
@@ -229,9 +236,6 @@ gcr_prompt_dialog_get_property (GObject *obj,
 	GcrPromptDialog *self = GCR_PROMPT_DIALOG (obj);
 
 	switch (prop_id) {
-	case PROP_TITLE:
-		g_value_set_string (value, self->pv->title);
-		break;
 	case PROP_MESSAGE:
 		g_value_set_string (value, self->pv->message);
 		break;
@@ -251,7 +255,7 @@ gcr_prompt_dialog_get_property (GObject *obj,
 		g_value_set_boolean (value, self->pv->password_new);
 		break;
 	case PROP_PASSWORD_STRENGTH:
-		g_value_set_uint (value, self->pv->password_strength);
+		g_value_set_int (value, self->pv->password_strength);
 		break;
 	case PROP_CALLER_WINDOW:
 		g_value_set_string (value, self->pv->caller_window);
@@ -357,9 +361,10 @@ grab_status_message (GdkGrabStatus status)
 
 static gboolean
 on_grab_broken (GtkWidget *widget,
-                GdkEventGrabBroken * event)
+                GdkEventGrabBroken * event,
+                gpointer user_data)
 {
-	ungrab_keyboard (widget, (GdkEvent *)event, NULL);
+	ungrab_keyboard (widget, (GdkEvent *)event, user_data);
 	return TRUE;
 }
 
@@ -400,7 +405,7 @@ grab_keyboard (GtkWidget *widget,
 	                          GDK_KEY_PRESS | GDK_KEY_RELEASE, NULL, at);
 	if (status == GDK_GRAB_SUCCESS) {
 		self->pv->grab_broken_id = g_signal_connect (widget, "grab-broken-event",
-		                                             G_CALLBACK (on_grab_broken), NULL);
+		                                             G_CALLBACK (on_grab_broken), self);
 		gtk_device_grab_add (widget, device, TRUE);
 		self->pv->grabbed_device = device;
 	} else {
@@ -466,11 +471,16 @@ gcr_prompt_dialog_constructed (GObject *obj)
 	                        _("Continue"), GTK_RESPONSE_OK,
 	                        NULL);
 
+	gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+	gtk_window_set_keep_above (GTK_WINDOW (dialog), TRUE);
+	gtk_dialog_set_default_response (dialog, GTK_RESPONSE_OK);
+
 	content = gtk_dialog_get_content_area (dialog);
 
 	grid = GTK_GRID (gtk_grid_new ());
 	gtk_container_set_border_width (GTK_CONTAINER (grid), 6);
 	gtk_widget_set_hexpand (GTK_WIDGET (grid), TRUE);
+	gtk_grid_set_column_homogeneous (grid, FALSE);
 	gtk_grid_set_column_spacing (grid, 12);
 	gtk_grid_set_row_spacing (grid, 6);
 
@@ -513,6 +523,7 @@ gcr_prompt_dialog_constructed (GObject *obj)
 	/* The password label */
 	widget = gtk_label_new (_("Password:"));
 	gtk_widget_set_halign (widget, GTK_ALIGN_START);
+	gtk_widget_set_hexpand (widget, FALSE);
 	g_object_bind_property (self, "password-visible", widget, "visible", G_BINDING_DEFAULT);
 	gtk_grid_attach (grid, widget, 0, 2, 1, 1);
 
@@ -520,21 +531,24 @@ gcr_prompt_dialog_constructed (GObject *obj)
 	self->pv->password_buffer = gcr_secure_entry_buffer_new ();
 	entry = gtk_entry_new_with_buffer (self->pv->password_buffer);
 	gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
-	gtk_widget_set_hexpand (widget, TRUE);
+	gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
+	gtk_widget_set_hexpand (entry, TRUE);
 	g_object_bind_property (self, "password-visible", entry, "visible", G_BINDING_DEFAULT);
 	gtk_grid_attach (grid, entry, 1, 2, 1, 1);
 
 	/* The confirm label */
 	widget = gtk_label_new (_("Confirm:"));
 	gtk_widget_set_halign (widget, GTK_ALIGN_START);
+	gtk_widget_set_hexpand (widget, FALSE);
 	g_object_bind_property (self, "confirm-visible", widget, "visible", G_BINDING_DEFAULT);
 	gtk_grid_attach (grid, widget, 0, 3, 1, 1);
 
 	/* The confirm entry */
 	self->pv->confirm_buffer = gcr_secure_entry_buffer_new ();
-	widget = gtk_entry_new_with_buffer (self->pv->password_buffer);
+	widget = gtk_entry_new_with_buffer (self->pv->confirm_buffer);
 	gtk_widget_set_hexpand (widget, TRUE);
 	gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE);
+	gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);
 	g_object_bind_property (self, "confirm-visible", widget, "visible", G_BINDING_DEFAULT);
 	gtk_grid_attach (grid, widget, 1, 3, 1, 1);
 
@@ -551,6 +565,7 @@ gcr_prompt_dialog_constructed (GObject *obj)
 	pango_attr_list_insert (attrs, pango_attr_style_new (PANGO_STYLE_ITALIC));
 	gtk_label_set_attributes (GTK_LABEL (widget), attrs);
 	pango_attr_list_unref (attrs);
+	gtk_widget_set_hexpand (widget, FALSE);
 	g_object_bind_property (self, "warning", widget, "label", G_BINDING_DEFAULT);
 	g_object_bind_property (self, "warning-visible", widget, "visible", G_BINDING_DEFAULT);
 	gtk_grid_attach (grid, widget, 0, 5, 2, 1);
@@ -561,6 +576,7 @@ gcr_prompt_dialog_constructed (GObject *obj)
 	g_object_bind_property (self, "choice-label", widget, "label", G_BINDING_DEFAULT);
 	g_object_bind_property (self, "choice-visible", widget, "visible", G_BINDING_DEFAULT);
 	g_object_bind_property (self, "choice-chosen", widget, "active", G_BINDING_BIDIRECTIONAL);
+	gtk_widget_set_hexpand (widget, FALSE);
 	gtk_grid_attach (grid, widget, 0, 6, 2, 1);
 
 	gtk_container_add (GTK_CONTAINER (content), GTK_WIDGET (grid));
@@ -700,8 +716,6 @@ gcr_prompt_dialog_class_init (GcrPromptDialogClass *klass)
 
 	g_type_class_add_private (gobject_class, sizeof (GcrPromptDialogPrivate));
 
-	g_object_class_override_property (gobject_class, PROP_TITLE, "title");
-
 	g_object_class_override_property (gobject_class, PROP_MESSAGE, "message");
 
 	g_object_class_override_property (gobject_class, PROP_DESCRIPTION, "description");
@@ -780,11 +794,16 @@ gcr_prompt_dialog_password_async (GcrPrompt *prompt,
 	gtk_widget_show (self->pv->image);
 	gtk_widget_hide (self->pv->spinner);
 
+	gtk_entry_buffer_set_text (self->pv->password_buffer, "", 0);
+	gtk_entry_buffer_set_text (self->pv->confirm_buffer, "", 0);
+
 	obj = G_OBJECT (self);
 	g_object_notify (obj, "password-visible");
 	g_object_notify (obj, "confirm-visible");
 	g_object_notify (obj, "warning-visible");
 	g_object_notify (obj, "choice-visible");
+
+	gtk_widget_show (GTK_WIDGET (self));
 }
 
 static const gchar *
@@ -821,7 +840,7 @@ gcr_prompt_dialog_confirm_async (GcrPrompt *prompt,
 
 	self->pv->mode = PROMPT_CONFIRMING;
 	self->pv->async_result = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
-	                                                    gcr_prompt_dialog_password_async);
+	                                                    gcr_prompt_dialog_confirm_async);
 
 	gtk_image_set_from_stock (GTK_IMAGE (self->pv->image),
 	                          GTK_STOCK_DIALOG_QUESTION,
@@ -835,6 +854,8 @@ gcr_prompt_dialog_confirm_async (GcrPrompt *prompt,
 	g_object_notify (obj, "confirm-visible");
 	g_object_notify (obj, "warning-visible");
 	g_object_notify (obj, "choice-visible");
+
+	gtk_widget_show (GTK_WIDGET (self));
 }
 
 static GcrPromptReply
diff --git a/gcr/gcr-prompter-tool.c b/gcr/gcr-prompter-tool.c
index 3a06d4e..b897a0c 100644
--- a/gcr/gcr-prompter-tool.c
+++ b/gcr/gcr-prompter-tool.c
@@ -41,6 +41,9 @@
 #define QUIT_TIMEOUT 10
 
 static GcrSystemPrompter *the_prompter = NULL;
+static gboolean registered_prompter = FALSE;
+static gboolean acquired_system_prompter = FALSE;
+static gboolean acquired_private_prompter = FALSE;
 
 #if 0
 static gboolean
@@ -74,6 +77,9 @@ on_bus_acquired (GDBusConnection *connection,
                  const gchar *name,
                  gpointer user_data)
 {
+	if (!registered_prompter)
+		gcr_system_prompter_register (the_prompter, connection);
+	registered_prompter = TRUE;
 }
 
 static void
@@ -81,7 +87,11 @@ on_name_acquired (GDBusConnection *connection,
                   const gchar *name,
                   gpointer user_data)
 {
-	gcr_system_prompter_register (the_prompter, connection);
+	if (g_strcmp0 (name, GCR_DBUS_PROMPTER_SYSTEM_BUS_NAME) == 0)
+		acquired_system_prompter = TRUE;
+
+	else if (g_strcmp0 (name, GCR_DBUS_PROMPTER_PRIVATE_BUS_NAME) == 0)
+		acquired_private_prompter = TRUE;
 }
 
 static void
@@ -89,14 +99,25 @@ on_name_lost (GDBusConnection *connection,
               const gchar *name,
               gpointer user_data)
 {
-	gcr_system_prompter_unregister (the_prompter, FALSE);
-	gtk_main_quit ();
+	/* Called like so when no connection can be made */
+	if (connection == NULL) {
+		g_warning ("couldn't connect to session bus");
+		gtk_main_quit ();
+
+	} else if (g_strcmp0 (name, GCR_DBUS_PROMPTER_SYSTEM_BUS_NAME) == 0) {
+		acquired_system_prompter = TRUE;
+
+	} else if (g_strcmp0 (name, GCR_DBUS_PROMPTER_PRIVATE_BUS_NAME) == 0) {
+		acquired_private_prompter = TRUE;
+
+	}
 }
 
 int
 main (int argc, char *argv[])
 {
-	guint owner_id;
+	guint system_owner_id;
+	guint private_owner_id;
 
 	g_type_init ();
 	gtk_init (&argc, &argv);
@@ -114,18 +135,33 @@ main (int argc, char *argv[])
 
 	the_prompter = gcr_system_prompter_new (GCR_SYSTEM_PROMPTER_SINGLE,
 	                                        GCR_TYPE_PROMPT_DIALOG);
-	owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
-	                           GCR_DBUS_PROMPTER_SYSTEM_BUS_NAME,
-	                           G_BUS_NAME_OWNER_FLAGS_NONE,
-	                           on_bus_acquired,
-	                           on_name_acquired,
-	                           on_name_lost,
-	                           NULL,
-	                           NULL);
+
+	system_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
+	                                  GCR_DBUS_PROMPTER_SYSTEM_BUS_NAME,
+	                                  G_BUS_NAME_OWNER_FLAGS_NONE,
+	                                  on_bus_acquired,
+	                                  on_name_acquired,
+	                                  on_name_lost,
+	                                  NULL,
+	                                  NULL);
+
+	private_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
+	                                   GCR_DBUS_PROMPTER_PRIVATE_BUS_NAME,
+	                                   G_BUS_NAME_OWNER_FLAGS_NONE,
+	                                   on_bus_acquired,
+	                                   on_name_acquired,
+	                                   on_name_lost,
+	                                   NULL,
+	                                   NULL);
 
 	gtk_main ();
 
-	g_bus_unown_name (owner_id);
+	if (registered_prompter)
+		gcr_system_prompter_unregister (the_prompter, TRUE);
+
+	g_bus_unown_name (system_owner_id);
+	g_bus_unown_name (private_owner_id);
+
 	g_object_unref (the_prompter);
 
 	return 0;
diff --git a/gcr/gcr-system-prompt.c b/gcr/gcr-system-prompt.c
index 25ef5f0..b500fed 100644
--- a/gcr/gcr-system-prompt.c
+++ b/gcr/gcr-system-prompt.c
@@ -1186,10 +1186,10 @@ gcr_system_prompt_open_for_prompter_async (const gchar *prompter_name,
  *
  * Complete an operation to asynchronously open a system prompt.
  *
- * Returns: (transfer full): the prompt, or %NULL if prompt could not
- *          be opened
+ * Returns: (transfer full) (type Gcr.SystemPrompt): the prompt, or %NULL if
+ *          prompt could not be opened
  */
-GcrSystemPrompt *
+GcrPrompt *
 gcr_system_prompt_open_finish (GAsyncResult *result,
                                GError **error)
 {
@@ -1207,7 +1207,7 @@ gcr_system_prompt_open_finish (GAsyncResult *result,
 	g_object_unref (source_object);
 
 	if (object != NULL)
-		return GCR_SYSTEM_PROMPT (object);
+		return GCR_PROMPT (object);
 	else
 		return NULL;
 }
@@ -1227,10 +1227,10 @@ gcr_system_prompt_open_finish (GAsyncResult *result,
  * expires, then this function will fail with a %GCR_SYSTEM_PROMPT_IN_PROGRESS
  * error.
  *
- * Returns: (transfer full): the prompt, or %NULL if prompt could not
- *          be opened
+ * Returns: (transfer full) (type Gcr.SystemPrompt): the prompt, or %NULL if
+ *          prompt could not be opened
  */
-GcrSystemPrompt *
+GcrPrompt *
 gcr_system_prompt_open (gint timeout_seconds,
                         GCancellable *cancellable,
                         GError **error)
@@ -1260,10 +1260,10 @@ gcr_system_prompt_open (gint timeout_seconds,
  * expires, then this function will fail with a %GCR_SYSTEM_PROMPT_IN_PROGRESS
  * error.
  *
- * Returns: (transfer full): the prompt, or %NULL if prompt could not
- *          be opened
+ * Returns: (transfer full) (type Gcr.SystemPrompt): the prompt, or %NULL if
+ *          prompt could not be opened
  */
-GcrSystemPrompt *
+GcrPrompt *
 gcr_system_prompt_open_for_prompter (const gchar *prompter_name,
                                      gint timeout_seconds,
                                      GCancellable *cancellable,
diff --git a/gcr/gcr-system-prompt.h b/gcr/gcr-system-prompt.h
index b7c4e7b..275c0ea 100644
--- a/gcr/gcr-system-prompt.h
+++ b/gcr/gcr-system-prompt.h
@@ -81,15 +81,15 @@ void                 gcr_system_prompt_open_for_prompter_async   (const gchar *p
                                                                   gpointer user_data);
 
 
-GcrSystemPrompt *    gcr_system_prompt_open_finish               (GAsyncResult *result,
+GcrPrompt *          gcr_system_prompt_open_finish               (GAsyncResult *result,
                                                                   GError **error);
 
-GcrSystemPrompt *    gcr_system_prompt_open_for_prompter         (const gchar *prompter_name,
+GcrPrompt *          gcr_system_prompt_open_for_prompter         (const gchar *prompter_name,
                                                                   gint timeout_seconds,
                                                                   GCancellable *cancellable,
                                                                   GError **error);
 
-GcrSystemPrompt *    gcr_system_prompt_open                      (gint timeout_seconds,
+GcrPrompt *          gcr_system_prompt_open                      (gint timeout_seconds,
                                                                   GCancellable *cancellable,
                                                                   GError **error);
 
diff --git a/gcr/gcr-system-prompter.c b/gcr/gcr-system-prompter.c
index 0441ed3..60b96c6 100644
--- a/gcr/gcr-system-prompter.c
+++ b/gcr/gcr-system-prompter.c
@@ -88,16 +88,21 @@ struct _GcrSystemPrompterPrivate {
 	guint prompter_registered;
 	GDBusConnection *connection;
 
-	GHashTable *pending;          /* callback path (string) -> sender (string) */
-	GHashTable *active;           /* callback path (string) -> active (ActivePrompt) */
+	GHashTable *callbacks;       /* Callback -> guint watch_id */
+	GHashTable *active;          /* Callback -> active (ActivePrompt) */
+	GQueue waiting;
 };
 
 G_DEFINE_TYPE (GcrSystemPrompter, gcr_system_prompter, G_TYPE_OBJECT);
 
 typedef struct {
+	const gchar *path;
+	const gchar *name;
+} Callback;
+
+typedef struct {
 	gint refs;
-	gchar *callback_path;
-	gchar *callback_name;
+	Callback *callback;
 	GcrSystemPrompter *prompter;
 	GCancellable *cancellable;
 	GcrPrompt *prompt;
@@ -112,10 +117,10 @@ static void    prompt_send_ready               (ActivePrompt *active,
                                                 const gchar *response,
                                                 const gchar *secret);
 
-static void    prompt_possibly_ready           (GcrSystemPrompter *self,
-                                                const gchar *callback);
+static void    prompt_next_ready               (GcrSystemPrompter *self);
 
-static void    prompt_stop_prompting           (ActivePrompt *active,
+static void    prompt_stop_prompting           (GcrSystemPrompter *self,
+                                                Callback *callback,
                                                 gboolean send_done_message,
                                                 gboolean wait_for_reply);
 
@@ -136,14 +141,50 @@ on_prompt_notify (GObject *object,
 	g_hash_table_replace (active->changed, key, key);
 }
 
+static Callback *
+callback_dup (Callback *original)
+{
+	Callback *callback = g_slice_new0 (Callback);
+	g_assert (original != NULL);
+	g_assert (original->path != NULL);
+	g_assert (original->name != NULL);
+	callback->path = g_strdup (original->path);
+	callback->name = g_strdup (original->name);
+	return callback;
+}
+
+static void
+callback_free (gpointer data)
+{
+	Callback *callback = data;
+	g_free ((gchar *)callback->path);
+	g_free ((gchar *)callback->name);
+	g_slice_free (Callback, callback);
+}
+
+static guint
+callback_hash (gconstpointer data)
+{
+	const Callback *callback = data;
+	return g_str_hash (callback->name) ^ g_str_hash (callback->path);
+}
+
+static gboolean
+callback_equal (gconstpointer one,
+                gconstpointer two)
+{
+	const Callback *cone = one;
+	const Callback *ctwo = two;
+	return g_str_equal (cone->name, ctwo->name) &&
+	       g_str_equal (cone->path, ctwo->path);
+}
+
 static void
 active_prompt_unref (gpointer data)
 {
 	ActivePrompt *active = data;
 
 	if (g_atomic_int_dec_and_test (&active->refs)) {
-		g_free (active->callback_path);
-		g_free (active->callback_name);
 		g_object_unref (active->prompter);
 		g_object_unref (active->cancellable);
 		g_signal_handlers_disconnect_by_func (active->prompt, on_prompt_notify, active);
@@ -165,16 +206,13 @@ active_prompt_get_secret_exchange (ActivePrompt *active)
 
 static ActivePrompt *
 active_prompt_create (GcrSystemPrompter *self,
-                      const gchar *callback)
+                      Callback *lookup)
 {
 	ActivePrompt *active;
 
 	active = g_slice_new0 (ActivePrompt);
-	if (!g_hash_table_lookup_extended (self->pv->pending, callback,
-	                                   (gpointer *)&active->callback_path,
-	                                   (gpointer *)&active->callback_name))
-		g_return_val_if_reached (NULL);
-	if (!g_hash_table_steal (self->pv->pending, callback))
+	if (!g_hash_table_lookup_extended (self->pv->callbacks, lookup,
+	                                   (gpointer *)&active->callback, NULL))
 		g_return_val_if_reached (NULL);
 
 	active->refs = 1;
@@ -185,17 +223,23 @@ active_prompt_create (GcrSystemPrompter *self,
 	active->changed = g_hash_table_new (g_direct_hash, g_direct_equal);
 
 	/* Insert us into the active hash table */
-	g_hash_table_replace (self->pv->active, active->callback_path, active);
+	g_hash_table_replace (self->pv->active, active->callback, active);
 	return active;
 }
 
 static void
+unwatch_name (gpointer data)
+{
+	g_bus_unwatch_name (GPOINTER_TO_UINT (data));
+}
+
+static void
 gcr_system_prompter_init (GcrSystemPrompter *self)
 {
 	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_SYSTEM_PROMPTER,
 	                                        GcrSystemPrompterPrivate);
-	self->pv->pending = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-	self->pv->active = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, active_prompt_unref);
+	self->pv->callbacks = g_hash_table_new_full (callback_hash, callback_equal, callback_free, unwatch_name);
+	self->pv->active = g_hash_table_new_full (callback_hash, callback_equal, NULL, active_prompt_unref);
 }
 
 static void
@@ -250,8 +294,8 @@ gcr_system_prompter_dispose (GObject *obj)
 	if (self->pv->prompter_registered)
 		gcr_system_prompter_unregister (self, FALSE);
 
+	g_hash_table_remove_all (self->pv->callbacks);
 	g_hash_table_remove_all (self->pv->active);
-	g_hash_table_remove_all (self->pv->pending);
 
 	G_OBJECT_CLASS (gcr_system_prompter_parent_class)->dispose (obj);
 }
@@ -266,8 +310,8 @@ gcr_system_prompter_finalize (GObject *obj)
 	g_assert (self->pv->connection == NULL);
 	g_assert (self->pv->prompter_registered == 0);
 
+	g_hash_table_destroy (self->pv->callbacks);
 	g_hash_table_destroy (self->pv->active);
-	g_hash_table_destroy (self->pv->pending);
 
 	G_OBJECT_CLASS (gcr_system_prompter_parent_class)->finalize (obj);
 }
@@ -363,20 +407,36 @@ prompt_build_properties (GcrPrompt *prompt,
 }
 
 static void
-prompt_stop_prompting (ActivePrompt *active,
+prompt_stop_prompting (GcrSystemPrompter *self,
+                       Callback *callback,
                        gboolean send_done_message,
                        gboolean wait_for_reply)
 {
-	GcrSystemPrompter *self = g_object_ref (active->prompter);
+	ActivePrompt *active;
 	GVariant *retval;
 
-	if (!active->ready)
-		g_cancellable_cancel (active->cancellable);
+	/* Get a pointer to our actual callback */
+	if (!g_hash_table_lookup_extended (self->pv->callbacks, callback,
+	                                   (gpointer *)&callback, NULL))
+		return;
+
+	/* Removed from the waiting queue */
+	g_queue_remove (&self->pv->waiting, callback);
 
+	/* Close any active prompt */
+	active = g_hash_table_lookup (self->pv->active, callback);
+	if (active != NULL) {
+		if (!active->ready)
+			g_cancellable_cancel (active->cancellable);
+		g_object_run_dispose (G_OBJECT (active->prompt));
+		g_hash_table_remove (self->pv->active, callback);
+	}
+
+	/* Notify the caller */
 	if (send_done_message && wait_for_reply) {
 		retval = g_dbus_connection_call_sync (self->pv->connection,
-		                                      active->callback_name,
-		                                      active->callback_path,
+		                                      callback->name,
+		                                      callback->path,
 		                                      GCR_DBUS_CALLBACK_INTERFACE,
 		                                      GCR_DBUS_CALLBACK_METHOD_DONE,
 		                                      g_variant_new ("()"),
@@ -387,8 +447,8 @@ prompt_stop_prompting (ActivePrompt *active,
 			g_variant_unref (retval);
 	} else if (send_done_message) {
 		g_dbus_connection_call (self->pv->connection,
-		                        active->callback_name,
-		                        active->callback_path,
+		                        callback->name,
+		                        callback->path,
 		                        GCR_DBUS_CALLBACK_INTERFACE,
 		                        GCR_DBUS_CALLBACK_METHOD_DONE,
 		                        g_variant_new ("()"),
@@ -397,11 +457,8 @@ prompt_stop_prompting (ActivePrompt *active,
 		                        -1, NULL, NULL, NULL);
 	}
 
-	g_object_run_dispose (G_OBJECT (active->prompt));
-	if (!g_hash_table_remove (self->pv->active, active->callback_path))
-		g_assert_not_reached ();
-
-	g_object_unref (self);
+	/* And all traces gone, including watch */
+	g_hash_table_remove (self->pv->callbacks, callback);
 }
 
 static void
@@ -414,21 +471,29 @@ on_prompt_ready_complete (GObject *source,
 	GError *error = NULL;
 	GVariant *retval;
 
+	g_assert (active->ready == FALSE);
+
 	active->ready = TRUE;
 	retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
 
+	/* Was cancelled, prompter probably unregistered */
+	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
+	    g_cancellable_is_cancelled (active->cancellable)) {
+		g_error_free (error);
+
 	/* The ready call failed,  */
-	if (error != NULL) {
+	} else if (error != NULL) {
 		if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD))
 			_gcr_debug ("prompt disappeared or does not exist: %s: %s",
-			            active->callback_name, active->callback_path);
+			            active->callback->name, active->callback->path);
 		else
 			g_message ("received an error from the prompt callback: %s", error->message);
 		g_error_free (error);
-		prompt_stop_prompting (active, FALSE, FALSE);
+		prompt_stop_prompting (self, active->callback, FALSE, FALSE);
+		g_hash_table_remove (self->pv->callbacks, active->callback);
 
 		/* Another new prompt may be ready to go active? */
-		prompt_possibly_ready (self, NULL);
+		prompt_next_ready (self);
 	}
 
 	if (retval != NULL)
@@ -448,6 +513,8 @@ prompt_send_ready (ActivePrompt *active,
 	GcrSecretExchange *exchange;
 	gchar *sent;
 
+	g_assert (active->ready == FALSE);
+
 	exchange = active_prompt_get_secret_exchange (active);
 	if (!active->received) {
 		g_return_if_fail (secret == NULL);
@@ -460,8 +527,8 @@ prompt_send_ready (ActivePrompt *active,
 	builder = prompt_build_properties (active->prompt, active->changed);
 
 	g_dbus_connection_call (self->pv->connection,
-	                        active->callback_name,
-	                        active->callback_path,
+	                        active->callback->name,
+	                        active->callback->path,
 	                        GCR_DBUS_CALLBACK_INTERFACE,
 	                        GCR_DBUS_CALLBACK_METHOD_READY,
 	                        g_variant_new ("(sa{sv}s)", response, builder, sent),
@@ -476,30 +543,23 @@ prompt_send_ready (ActivePrompt *active,
 }
 
 static void
-prompt_possibly_ready (GcrSystemPrompter *self,
-                       const gchar *callback)
+prompt_next_ready (GcrSystemPrompter *self)
 {
 	ActivePrompt *active;
-	GHashTableIter iter;
+	Callback *callback;
 
-	if (callback == NULL) {
-		g_hash_table_iter_init (&iter, self->pv->pending);
-		if (!g_hash_table_iter_next (&iter, (gpointer *)&callback, NULL))
-			return;
-		g_assert (callback != NULL);
-	}
-
-	active = g_hash_table_lookup (self->pv->active, callback);
+	if (self->pv->mode == GCR_SYSTEM_PROMPTER_SINGLE &&
+	    g_hash_table_size (self->pv->active) > 0)
+		return;
 
-	/* Only one prompt at a time, and only one active */
-	if (active == NULL) {
-		if (self->pv->mode == GCR_SYSTEM_PROMPTER_SINGLE &&
-		    g_hash_table_size (self->pv->active) > 0)
-			return;
+	callback = g_queue_pop_head (&self->pv->waiting);
+	if (callback == NULL)
+		return;
 
-		active = active_prompt_create (self, callback);
-	}
+	active = g_hash_table_lookup (self->pv->active, callback);
+	g_assert (active == NULL);
 
+	active = active_prompt_create (self, callback);
 	prompt_send_ready (active, GCR_DBUS_PROMPT_REPLY_YES, NULL);
 }
 
@@ -548,28 +608,55 @@ prompter_set_property (GDBusConnection *connection,
 }
 
 static void
+on_caller_vanished (GDBusConnection *connection,
+                    const gchar *name,
+                    gpointer user_data)
+{
+	GcrSystemPrompter *self = GCR_SYSTEM_PROMPTER (user_data);
+	GQueue queue = G_QUEUE_INIT;
+	Callback *callback;
+	GHashTableIter iter;
+
+	g_hash_table_iter_init (&iter, self->pv->callbacks);
+	while (g_hash_table_iter_next (&iter, (gpointer *)&callback, NULL)) {
+		if (g_strcmp0 (name, callback->name) == 0)
+			g_queue_push_tail (&queue, callback);
+	}
+
+	while ((callback = g_queue_pop_head (&queue)) != NULL)
+		prompt_stop_prompting (self, callback, FALSE, FALSE);
+}
+
+static void
 prompter_method_begin_prompting (GcrSystemPrompter *self,
                                  GDBusMethodInvocation *invocation,
                                  GVariant *parameters)
 {
-	gchar *callback;
-	const gchar *sender;
+	Callback lookup;
+	Callback *callback;
+	const gchar *caller;
+	guint watch_id;
 
-	g_variant_get (parameters, "(o)", &callback);
+	lookup.name = caller = g_dbus_method_invocation_get_sender (invocation);
+	g_variant_get (parameters, "(&o)", &lookup.path);
 
-	if (g_hash_table_lookup (self->pv->pending, callback) ||
-	    g_hash_table_lookup (self->pv->active, callback)) {
+	if (g_hash_table_lookup (self->pv->callbacks, &lookup)) {
 		g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
 		                                               "Already begun prompting for this prompt callback");
 		return;
 	}
 
-	sender = g_dbus_method_invocation_get_sender (invocation);
-	g_hash_table_insert (self->pv->pending, g_strdup (callback), g_strdup (sender));
+	callback = callback_dup (&lookup);
+	watch_id = g_bus_watch_name_on_connection (self->pv->connection, caller,
+	                                           G_BUS_NAME_WATCHER_FLAGS_NONE,
+	                                           NULL, on_caller_vanished,
+	                                           self, NULL);
+	g_hash_table_insert (self->pv->callbacks, callback, GUINT_TO_POINTER (watch_id));
 
 	g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
-	prompt_possibly_ready (self, callback);
-	g_free (callback);
+
+	g_queue_push_tail (&self->pv->waiting, callback);
+	prompt_next_ready (self);
 }
 
 static void
@@ -640,23 +727,20 @@ prompter_method_perform_prompt (GcrSystemPrompter *self,
 	GcrSecretExchange *exchange;
 	GError *error = NULL;
 	ActivePrompt *active;
-	const gchar *callback;
+	Callback lookup;
 	const gchar *type;
 	GVariantIter *iter;
 	const gchar *received;
 
+	lookup.name = g_dbus_method_invocation_get_sender (invocation);
 	g_variant_get (parameters, "(&o&sa{sv}&s)",
-	               &callback, &type, &iter, &received);
+	               &lookup.path, &type, &iter, &received);
 
-	active = g_hash_table_lookup (self->pv->active, callback);
+	active = g_hash_table_lookup (self->pv->active, &lookup);
 	if (active == NULL) {
 		error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
 		                     "Not begun prompting for this prompt callback");
 
-	} else if (!g_str_equal (active->callback_name, g_dbus_method_invocation_get_sender (invocation))) {
-		error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED,
-		                     "This prompt is not owned by this application");
-
 	} else if (!active->ready) {
 		error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
 		                     "Already performing a prompt for this prompt callback");
@@ -705,17 +789,14 @@ prompter_method_stop_prompting (GcrSystemPrompter *self,
                                 GDBusMethodInvocation *invocation,
                                 GVariant *parameters)
 {
-	const gchar *callback;
-	ActivePrompt *active;
+	Callback lookup;
 
-	g_variant_get (parameters, "(&o)", &callback);
-
-	active = g_hash_table_lookup (self->pv->active, callback);
-	if (active != NULL)
-		prompt_stop_prompting (active, TRUE, FALSE);
+	lookup.name = g_dbus_method_invocation_get_sender (invocation);
+	g_variant_get (parameters, "(&o)", &lookup.path);
+	prompt_stop_prompting (self, &lookup, TRUE, FALSE);
 
 	g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
-	prompt_possibly_ready (self, NULL);
+	prompt_next_ready (self);
 }
 
 static void
@@ -805,11 +886,7 @@ void
 gcr_system_prompter_unregister (GcrSystemPrompter *self,
                                 gboolean wait)
 {
-	ActivePrompt *active;
-	GVariantBuilder builder;
-	const gchar *sender;
-	GVariant *retval;
-	GList *paths;
+	GList *callbacks;
 	GList *l;
 
 	g_return_if_fail (GCR_IS_SYSTEM_PROMPTER (self));
@@ -817,47 +894,14 @@ gcr_system_prompter_unregister (GcrSystemPrompter *self,
 
 	_gcr_debug ("unregistering prompter");
 
-	paths = g_hash_table_get_keys (self->pv->active);
-	for (l = paths; l != NULL; l = g_list_next (l)) {
-		active = g_hash_table_lookup (self->pv->active, l->data);
-		prompt_stop_prompting (active, TRUE, wait);
-	}
-	g_assert (g_hash_table_size (self->pv->active) == 0);
-	g_list_free (paths);
-
-	paths = g_hash_table_get_keys (self->pv->pending);
-	for (l = paths; l != NULL; l = g_list_next (l)) {
-		sender = g_hash_table_lookup (self->pv->pending, l->data);
-		g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
-
-		if (wait) {
-			retval = g_dbus_connection_call_sync (self->pv->connection,
-			                                      sender, l->data,
-			                                      GCR_DBUS_CALLBACK_INTERFACE,
-			                                      GCR_DBUS_CALLBACK_METHOD_DONE,
-			                                      g_variant_new ("()"),
-			                                      G_VARIANT_TYPE ("()"),
-			                                      G_DBUS_CALL_FLAGS_NO_AUTO_START,
-			                                      -1, NULL, NULL);
-			if (retval)
-				g_variant_unref (retval);
-
-		} else {
-			g_dbus_connection_call (self->pv->connection,
-			                        sender, l->data,
-			                        GCR_DBUS_CALLBACK_INTERFACE,
-			                        GCR_DBUS_CALLBACK_METHOD_DONE,
-			                        g_variant_new ("()"),
-			                        G_VARIANT_TYPE ("()"),
-			                        G_DBUS_CALL_FLAGS_NO_AUTO_START,
-			                        -1, NULL, NULL, NULL);
-		}
+	callbacks = g_hash_table_get_keys (self->pv->callbacks);
+	for (l = callbacks; l != NULL; l = g_list_next (l))
+		prompt_stop_prompting (self, l->data, TRUE, wait);
+	g_list_free (callbacks);
 
-		if (!g_hash_table_remove (self->pv->pending, l->data))
-			g_assert_not_reached ();
-	}
-	g_assert (g_hash_table_size (self->pv->pending) == 0);
-	g_list_free (paths);
+	g_assert (g_hash_table_size (self->pv->active) == 0);
+	g_assert (g_hash_table_size (self->pv->callbacks) == 0);
+	g_assert (g_queue_is_empty (&self->pv->waiting));
 
 	if (!g_dbus_connection_unregister_object (self->pv->connection, self->pv->prompter_registered))
 		g_assert_not_reached ();
diff --git a/gcr/org.gnome.keyring.Prompter.service.in b/gcr/org.gnome.keyring.PrivatePrompter.service.in
similarity index 100%
copy from gcr/org.gnome.keyring.Prompter.service.in
copy to gcr/org.gnome.keyring.PrivatePrompter.service.in
diff --git a/gcr/org.gnome.keyring.Prompter.service.in b/gcr/org.gnome.keyring.SystemPrompter.service.in
similarity index 100%
rename from gcr/org.gnome.keyring.Prompter.service.in
rename to gcr/org.gnome.keyring.SystemPrompter.service.in
diff --git a/gcr/tests/Makefile.am b/gcr/tests/Makefile.am
index f4a945c..1a8d6cd 100644
--- a/gcr/tests/Makefile.am
+++ b/gcr/tests/Makefile.am
@@ -66,6 +66,7 @@ noinst_PROGRAMS = \
 	frob-tree-selector \
 	frob-openpgp \
 	frob-parser \
+	frob-prompt \
 	frob-request \
 	frob-system-prompt \
 	frob-unlock \
diff --git a/gcr/tests/files/prompt-tests/simple.prompt b/gcr/tests/files/prompt-tests/simple.prompt
new file mode 100644
index 0000000..870a547
--- /dev/null
+++ b/gcr/tests/files/prompt-tests/simple.prompt
@@ -0,0 +1,28 @@
+[three]
+type = password
+title = Unlock Keyring
+message = Enter password for keyring 'sean' to unlock
+description = An application wants access to the keyring 'sean', but it is locked
+choice-label = Always unlock this keyring whenever I'm logged in.
+password-new = false
+
+[one]
+type = password
+title = The title
+message = The message
+description = Description
+
+[two]
+type = password
+title = New Password
+message = Enter a new password here
+description = This is a test of the new password prompt
+password-new = true
+
+[four]
+type = confirm
+title = Question
+message = A nice question here
+description = This is why you really should be asking this question
+warning =
+
diff --git a/gcr/tests/frob-prompt.c b/gcr/tests/frob-prompt.c
new file mode 100644
index 0000000..98785db
--- /dev/null
+++ b/gcr/tests/frob-prompt.c
@@ -0,0 +1,202 @@
+/*
+ * 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-base.h"
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+
+#include <err.h>
+
+static const gchar *file_name = NULL;
+static gchar *prompt_type = NULL;
+static gint prompt_delay = 0;
+
+static void
+on_prompt_clicked (GtkToolButton *button,
+                   gpointer user_data)
+{
+	GtkWidget *parent = user_data;
+	GKeyFile *file;
+	GError *error = NULL;
+	gchar **groups, **keys;
+	GValue value = { 0, };
+	GParamSpec *spec;
+	GcrPrompt *prompt;
+	const gchar *key;
+	const gchar *password;
+	GcrPromptReply reply;
+	gchar *type;
+	gchar *choice;
+	gchar *caller_id;
+	guint i, j;
+
+
+	file = g_key_file_new ();
+	if (!g_key_file_load_from_file (file, file_name, G_KEY_FILE_NONE, &error))
+		errx (1, "couldn't load prompt info: %s", error->message);
+
+	if (!prompt_type || g_str_equal (prompt_type, "dialog"))
+		prompt = g_object_new (GCR_TYPE_PROMPT_DIALOG, NULL);
+	else if (g_str_equal (prompt_type, "system"))
+		prompt = gcr_system_prompt_open_for_prompter ("org.gnome.keyring.SystemPrompter", 5, NULL, &error);
+	else if (g_str_equal (prompt_type, "private"))
+		prompt = gcr_system_prompt_open_for_prompter ("org.gnome.keyring.PrivatePrompter", 5, NULL, &error);
+	else
+		errx (2, "invalid type: %s", prompt_type);
+
+	if (error != NULL)
+		errx (1, "couldn't create prompt: %s", error->message);
+
+	caller_id = g_strdup_printf ("%lu", (gulong)GDK_WINDOW_XID (gtk_widget_get_window (parent)));
+	gcr_prompt_set_caller_window (GCR_PROMPT (prompt), caller_id);
+	g_free (caller_id);
+
+	groups = g_key_file_get_groups (file, NULL);
+	for (i = 0; groups[i] != NULL; i++) {
+		keys = g_key_file_get_keys (file, groups[i], NULL, NULL);
+		for (j = 0; keys[j] != NULL; j++) {
+			key = keys[j];
+			if (g_str_equal (key, "type"))
+				continue;
+			spec = g_object_class_find_property (G_OBJECT_GET_CLASS (prompt), key);
+			if (spec == NULL)
+				errx (1, "couldn't find property %s on prompt %s",
+				      key, G_OBJECT_TYPE_NAME (prompt));
+			g_value_init (&value, spec->value_type);
+			switch (spec->value_type) {
+			case G_TYPE_STRING:
+				g_value_take_string (&value, g_key_file_get_string (file, groups[i], key, NULL));
+				break;
+			case G_TYPE_INT:
+				g_value_set_int (&value, g_key_file_get_integer (file, groups[i], key, NULL));
+				break;
+			case G_TYPE_BOOLEAN:
+				g_value_set_boolean (&value, g_key_file_get_boolean (file, groups[i], key, NULL));
+				break;
+			default:
+				errx (1, "unsupported type %s for property %s",
+				      g_type_name (spec->value_type), key);
+				break;
+			}
+
+			g_object_set_property (G_OBJECT (prompt), key, &value);
+			g_value_unset (&value);
+		}
+
+		g_strfreev (keys);
+
+		type = g_key_file_get_value (file, groups[i], "type", NULL);
+		if (g_strcmp0 (type, "password") == 0) {
+			password = gcr_prompt_password_run (prompt, NULL, &error);
+			if (error != NULL)
+				errx (1, "couldn't prompt for password: %s", error->message);
+			g_print ("prompt password: %s\n", password);
+			g_print ("password strength: %d\n", gcr_prompt_get_password_strength (prompt));
+		} else if (g_strcmp0 (type, "confirm") == 0) {
+			reply = gcr_prompt_confirm_run (prompt, NULL, &error);
+			if (error != NULL)
+				errx (1, "couldn't prompt for confirm: %s", error->message);
+			g_print ("prompt confirm: %d\n", reply);
+		} else {
+			errx (1, "unsupported prompt type: %s", type);
+		}
+		g_free (type);
+
+		choice = gcr_prompt_get_choice_label (prompt);
+		if (choice)
+			g_print ("choice chosen: %s", gcr_prompt_get_choice_chosen (prompt) ? "true" : "false");
+		g_free (choice);
+		g_print ("\n");
+
+
+	}
+
+	g_object_unref (prompt);
+	g_strfreev (groups);
+	g_key_file_free (file);
+}
+
+
+static gboolean
+on_window_delete (GtkWidget *widget,
+                  GdkEvent *event,
+                  gpointer user_data)
+{
+	gtk_main_quit ();
+	return FALSE;
+}
+
+static GOptionEntry option_entries[] = {
+	{ "type", 'c', 0, G_OPTION_ARG_STRING, &prompt_type,
+	  "'system', 'private' or 'dialog'", "type" },
+	{ "delay", 'd', 0, G_OPTION_ARG_INT, &prompt_delay,
+	  "delay in seconds between prompts", "delay" },
+	{ NULL }
+};
+
+int
+main (int argc, char *argv[])
+{
+	GOptionContext *context;
+	GtkWidget *window;
+	GtkToolbar *toolbar;
+	GtkToolItem *item;
+	GError *error = NULL;
+
+	g_set_prgname ("frob-prompt");
+
+	context = g_option_context_new ("");
+	g_option_context_add_main_entries (context, option_entries, GETTEXT_PACKAGE);
+	g_option_context_add_group (context, gtk_get_option_group (TRUE));
+
+	if (!g_option_context_parse (context, &argc, &argv, &error))
+		errx (2, "%s", error->message);
+
+	g_option_context_free (context);
+
+	if (argc < 1)
+		errx (2, "specify file");
+	file_name = argv[1];
+
+	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+	g_signal_connect (window, "delete-event", G_CALLBACK (on_window_delete), NULL);
+
+	toolbar = GTK_TOOLBAR (gtk_toolbar_new ());
+	gtk_toolbar_set_style (toolbar, GTK_TOOLBAR_TEXT);
+	item = gtk_tool_button_new (NULL, "Prompt");
+	g_signal_connect (item, "clicked", G_CALLBACK (on_prompt_clicked), window);
+	gtk_toolbar_insert (toolbar, item, 0);
+	gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (toolbar));
+
+	gtk_window_set_default_size (GTK_WINDOW (window), 400, 80);
+	gtk_widget_show_all (window);
+
+	gtk_main ();
+
+	g_free (prompt_type);
+	return 0;
+}
diff --git a/gcr/tests/frob-system-prompt.c b/gcr/tests/frob-system-prompt.c
index 6834c56..39919b3 100644
--- a/gcr/tests/frob-system-prompt.c
+++ b/gcr/tests/frob-system-prompt.c
@@ -36,7 +36,7 @@ static void
 on_prompt_clicked (GtkToolButton *button,
                    gpointer user_data)
 {
-	GcrSystemPrompt *prompt;
+	GcrPrompt *prompt;
 	GError *error = NULL;
 	const gchar *password;
 	GtkWidget *parent = user_data;
diff --git a/gcr/tests/test-system-prompt.c b/gcr/tests/test-system-prompt.c
index bb6d841..99344bf 100644
--- a/gcr/tests/test-system-prompt.c
+++ b/gcr/tests/test-system-prompt.c
@@ -51,7 +51,7 @@ static void
 test_open_prompt (Test *test,
                   gconstpointer unused)
 {
-	GcrSystemPrompt *prompt;
+	GcrPrompt *prompt;
 	GError *error = NULL;
 	gboolean ret;
 	gchar *bus_name;
@@ -63,7 +63,7 @@ test_open_prompt (Test *test,
 	g_object_get (prompt, "bus-name", &bus_name, NULL);
 	g_assert_cmpstr (bus_name, ==, test->prompter_name);
 
-	ret = gcr_system_prompt_close (prompt, NULL, &error);
+	ret = gcr_system_prompt_close (GCR_SYSTEM_PROMPT (prompt), NULL, &error);
 	g_assert_no_error (error);
 	g_assert (ret == TRUE);
 
@@ -75,7 +75,7 @@ static void
 test_open_failure (Test *test,
                    gconstpointer unused)
 {
-	GcrSystemPrompt *prompt;
+	GcrPrompt *prompt;
 	GDBusConnection *connection;
 	GError *error = NULL;
 
@@ -96,7 +96,7 @@ static void
 test_prompt_password (Test *test,
                       gconstpointer unused)
 {
-	GcrSystemPrompt *prompt;
+	GcrPrompt *prompt;
 	GError *error = NULL;
 	const gchar *password;
 
@@ -106,7 +106,7 @@ test_prompt_password (Test *test,
 	g_assert_no_error (error);
 	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
 
-	password = gcr_prompt_password_run (GCR_PROMPT (prompt), NULL, &error);
+	password = gcr_prompt_password_run (prompt, NULL, &error);
 	g_assert_no_error (error);
 	g_assert_cmpstr (password, ==, "booo");
 
@@ -118,7 +118,7 @@ static void
 test_password_in_exchange (Test *test,
                            gconstpointer unused)
 {
-	GcrSystemPrompt *prompt;
+	GcrPrompt *prompt;
 	GError *error = NULL;
 	GcrSecretExchange *exchange;
 
@@ -128,7 +128,7 @@ test_password_in_exchange (Test *test,
 	g_assert_no_error (error);
 	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
 
-	gcr_prompt_password_run (GCR_PROMPT (prompt), NULL, &error);
+	gcr_prompt_password_run (prompt, NULL, &error);
 	g_assert_no_error (error);
 
 	g_object_get (prompt, "secret-exchange", &exchange, NULL);
@@ -187,7 +187,7 @@ test_async_password (Test *test,
                      gconstpointer unused)
 {
 	GAsyncResult *result = NULL;
-	GcrSystemPrompt *prompt;
+	GcrPrompt *prompt;
 	GError *error = NULL;
 	const gchar *password;
 
@@ -204,12 +204,12 @@ test_async_password (Test *test,
 	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
 	g_clear_object (&result);
 
-	gcr_prompt_password_async (GCR_PROMPT (prompt), NULL,
+	gcr_prompt_password_async (prompt, NULL,
 	                           on_async_result, &result);
 	g_assert (result == NULL);
 	egg_test_wait ();
 
-	password = gcr_prompt_password_finish (GCR_PROMPT (prompt), result, &error);
+	password = gcr_prompt_password_finish (prompt, result, &error);
 	g_assert_no_error (error);
 	g_assert_cmpstr (password, ==, "booo");
 	g_clear_object (&result);
@@ -221,7 +221,7 @@ static void
 test_prompt_confirm (Test *test,
                      gconstpointer unused)
 {
-	GcrSystemPrompt *prompt;
+	GcrPrompt *prompt;
 	GError *error = NULL;
 	gboolean ret;
 
@@ -231,7 +231,7 @@ test_prompt_confirm (Test *test,
 	g_assert_no_error (error);
 	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
 
-	ret = gcr_prompt_confirm_run (GCR_PROMPT (prompt), NULL, &error);
+	ret = gcr_prompt_confirm_run (prompt, NULL, &error);
 	g_assert_no_error (error);
 	g_assert (ret == TRUE);
 
@@ -244,7 +244,7 @@ test_async_confirm (Test *test,
                     gconstpointer unused)
 {
 	GAsyncResult *result = NULL;
-	GcrSystemPrompt *prompt;
+	GcrPrompt *prompt;
 	GError *error = NULL;
 	gboolean confirm;
 
@@ -261,12 +261,11 @@ test_async_confirm (Test *test,
 	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
 	g_clear_object (&result);
 
-	gcr_prompt_confirm_async (GCR_PROMPT (prompt), NULL,
-	                          on_async_result, &result);
+	gcr_prompt_confirm_async (prompt, NULL, on_async_result, &result);
 	g_assert (result == NULL);
 	egg_test_wait ();
 
-	confirm = gcr_prompt_confirm_finish (GCR_PROMPT (prompt), result, &error);
+	confirm = gcr_prompt_confirm_finish (prompt, result, &error);
 	g_assert_no_error (error);
 	g_assert (confirm == TRUE);
 	g_clear_object (&result);
@@ -279,7 +278,7 @@ static void
 test_cancel_password (Test *test,
                       gconstpointer unused)
 {
-	GcrSystemPrompt *prompt;
+	GcrPrompt *prompt;
 	GError *error = NULL;
 	const gchar *password;
 
@@ -289,7 +288,7 @@ test_cancel_password (Test *test,
 	g_assert_no_error (error);
 	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
 
-	password = gcr_prompt_password_run (GCR_PROMPT (prompt), NULL, &error);
+	password = gcr_prompt_password_run (prompt, NULL, &error);
 	g_assert_no_error (error);
 	g_assert_cmpstr (password, ==, NULL);
 
@@ -301,7 +300,7 @@ static void
 test_cancel_confirm (Test *test,
                      gconstpointer unused)
 {
-	GcrSystemPrompt *prompt;
+	GcrPrompt *prompt;
 	GError *error = NULL;
 	gboolean ret;
 
@@ -311,7 +310,7 @@ test_cancel_confirm (Test *test,
 	g_assert_no_error (error);
 	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
 
-	ret = gcr_prompt_confirm_run (GCR_PROMPT (prompt), NULL, &error);
+	ret = gcr_prompt_confirm_run (prompt, NULL, &error);
 	g_assert_no_error (error);
 	g_assert (ret == FALSE);
 
@@ -323,7 +322,6 @@ static void
 test_prompt_properties (Test *test,
                         gconstpointer unused)
 {
-	GcrSystemPrompt *sprompt;
 	GcrPrompt *prompt;
 	GError *error = NULL;
 	gboolean ret;
@@ -339,11 +337,10 @@ test_prompt_properties (Test *test,
 	                                     "password-strength", 0,
 	                                     NULL);
 
-	sprompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+	prompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
 	g_assert_no_error (error);
-	g_assert (GCR_IS_SYSTEM_PROMPT (sprompt));
+	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
 
-	prompt = GCR_PROMPT (sprompt);
 	g_object_set (prompt,
 	              "title", "Other Title",
 	              "choice-label", "Other Choice",
@@ -388,14 +385,12 @@ static void
 test_prompt_properties_unset (Test *test,
                               gconstpointer unused)
 {
-	GcrSystemPrompt *sprompt;
 	GcrPrompt *prompt;
 	GError *error = NULL;
 
-	sprompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+	prompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
 	g_assert_no_error (error);
-	g_assert (GCR_IS_SYSTEM_PROMPT (sprompt));
-	prompt = GCR_PROMPT (sprompt);
+	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
 
 	g_assert_cmpstr (gcr_prompt_get_title (prompt), ==, NULL);
 	g_assert_cmpstr (gcr_prompt_get_choice_label (prompt), ==, NULL);
@@ -415,8 +410,8 @@ static void
 test_prompt_close (Test *test,
                    gconstpointer unused)
 {
-	GcrSystemPrompt *prompt;
-	GcrSystemPrompt *prompt2;
+	GcrPrompt *prompt;
+	GcrPrompt *prompt2;
 	GError *error = NULL;
 	gboolean ret;
 
@@ -431,7 +426,7 @@ test_prompt_close (Test *test,
 	g_clear_error (&error);
 	g_assert (prompt2 == NULL);
 
-	ret = gcr_prompt_confirm_run (GCR_PROMPT (prompt), NULL, &error);
+	ret = gcr_prompt_confirm_run (prompt, NULL, &error);
 	g_assert_no_error (error);
 	g_assert (ret == TRUE);
 
@@ -440,7 +435,7 @@ test_prompt_close (Test *test,
 	g_clear_error (&error);
 	g_assert (prompt2 == NULL);
 
-	gcr_system_prompt_close (prompt, NULL, &error);
+	gcr_system_prompt_close (GCR_SYSTEM_PROMPT (prompt), NULL, &error);
 	g_assert_no_error (error);
 
 	prompt2 = gcr_system_prompt_open_for_prompter (test->prompter_name, 1, NULL, &error);
@@ -458,7 +453,7 @@ static void
 test_close_cancels (Test *test,
                     gconstpointer unused)
 {
-	GcrSystemPrompt *prompt;
+	GcrPrompt *prompt;
 	GError *error = NULL;
 	const gchar *password = NULL;
 	GAsyncResult *result = NULL;
@@ -470,14 +465,14 @@ test_close_cancels (Test *test,
 	g_assert_no_error (error);
 	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
 
-	gcr_prompt_password_async (GCR_PROMPT (prompt), NULL, on_async_result, &result);
+	gcr_prompt_password_async (prompt, NULL, on_async_result, &result);
 
-	gcr_system_prompt_close (prompt, NULL, &error);
+	gcr_system_prompt_close (GCR_SYSTEM_PROMPT (prompt), NULL, &error);
 	g_assert_no_error (error);
 
 	egg_test_wait ();
 
-	password = gcr_prompt_password_finish (GCR_PROMPT (prompt), result, &error);
+	password = gcr_prompt_password_finish (prompt, result, &error);
 	g_assert_no_error (error);
 	g_assert (password == NULL);
 	g_clear_object (&result);



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