Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 693870 Details for
Bug 907156
gnome-keyring-daemon fails to unlock/spawn popup in shell when auto-loggedin
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
WIP backport deadlock fix, Start with all possible patches
0001-WIP-backport-deadlock-fix.-Start-with-all-possible-p.patch (text/plain), 45.91 KB, created by
Stef Walter
on 2013-02-06 10:37:38 UTC
(
hide
)
Description:
WIP backport deadlock fix, Start with all possible patches
Filename:
MIME Type:
Creator:
Stef Walter
Created:
2013-02-06 10:37:38 UTC
Size:
45.91 KB
patch
obsolete
>From 288c34ad0eb1ef725ccf38f8a999e5d9e0704b76 Mon Sep 17 00:00:00 2001 >From: Stef Walter <stefw@gnome.org> >Date: Fri, 21 Sep 2012 09:20:34 +0200 >Subject: [PATCH] WIP backport deadlock fix. Start with all possible patches > >gcr: Always specify the context for 'running' prompts > > * Don't automatically use the thread context, unless that's what > was passed to run_closure_begin(). > >https://bugzilla.gnome.org/show_bug.cgi?id=678611 > >gcr: Remove the waiting field in the system prompt CallClosure > > * This field wasn't being used for anything. > >https://bugzilla.gnome.org/show_bug.cgi?id=678611 > >gcr: Add prompt-close action signal to GcrPrompt > > * This signal is fired when the prompt is closed, regardless of > whether that closure was initiated by the user, or by the the > application. > * Add a gcr_prompt_close() method to fire this signal. > * After closing a prompt the prompt should not display any further > password or confirm prompts to the user. > >https://bugzilla.gnome.org/show_bug.cgi?id=678611 > >gcr: Implement prompt-close in GcrPromptDialog > > * When the dialog is closed, fire the prompt-close signal and > close the dialog. > >https://bugzilla.gnome.org/show_bug.cgi?id=678611 > >gcr: Implement prompt-close in GcrSystemPrompt and GcrSystemPrompter > > * Properly relay the prompt-close signal from GcrSystemPrompter > back to GcrSystemPrompt by firing the PromptDone callback method > on the caller's DBus interface. > * Make sure GcrSystemPrompt emits prompt-close appropriately for > all the various paths that can close the prompt. > * Add testing of the above, and changes in the mock prompter for this. > >https://bugzilla.gnome.org/show_bug.cgi?id=678611 > >gcr: Cancel the prompt when prompter goes away > > * If the prompter quits, cancel any prompting that's going on. > >https://bugzilla.gnome.org/show_bug.cgi?id=684478 > >gcr: Allow cancellation between ops in the GcrPromptDialog > > * Keep the cancel button enabled when in 'password checking' mode. >--- > docs/reference/gcr/gcr-sections.txt | 2 + > gcr/gcr-base.symbols | 3 + > gcr/gcr-mock-prompter.c | 80 +++++++++- > gcr/gcr-mock-prompter.h | 4 + > gcr/gcr-prompt-dialog.c | 65 ++++++-- > gcr/gcr-prompt.c | 43 ++++- > gcr/gcr-prompt.h | 4 + > gcr/gcr-system-prompt.c | 309 +++++++++++++++++++++++++----------- > gcr/gcr-system-prompter.c | 58 +++++-- > gcr/tests/frob-system-prompt.c | 3 + > gcr/tests/test-system-prompt.c | 183 +++++++++++++++++++++ > 11 files changed, 629 insertions(+), 125 deletions(-) > >diff --git a/docs/reference/gcr/gcr-sections.txt b/docs/reference/gcr/gcr-sections.txt >index be85461..b39923e 100644 >--- a/docs/reference/gcr/gcr-sections.txt >+++ b/docs/reference/gcr/gcr-sections.txt >@@ -743,6 +743,7 @@ gcr_prompt_confirm_async > gcr_prompt_confirm_finish > gcr_prompt_confirm_run > gcr_prompt_reset >+gcr_prompt_close > gcr_prompt_get_title > gcr_prompt_set_title > gcr_prompt_get_message >@@ -850,6 +851,7 @@ gcr_mock_prompter_expect_confirm_cancel > gcr_mock_prompter_expect_confirm_ok > gcr_mock_prompter_expect_password_cancel > gcr_mock_prompter_expect_password_ok >+gcr_mock_prompter_expect_close > gcr_mock_prompter_get_delay_msec > gcr_mock_prompter_set_delay_msec > gcr_mock_prompter_is_expecting >diff --git a/gcr/gcr-base.symbols b/gcr/gcr-base.symbols >index 5bc2708..35a74a1 100644 >--- a/gcr/gcr-base.symbols >+++ b/gcr/gcr-base.symbols >@@ -100,6 +100,7 @@ gcr_import_interaction_supplement > gcr_import_interaction_supplement_async > gcr_import_interaction_supplement_finish > gcr_import_interaction_supplement_prep >+gcr_mock_prompter_expect_close > gcr_mock_prompter_expect_confirm_cancel > gcr_mock_prompter_expect_confirm_ok > gcr_mock_prompter_expect_password_cancel >@@ -110,6 +111,7 @@ gcr_mock_prompter_is_prompting > gcr_mock_prompter_set_delay_msec > gcr_mock_prompter_start > gcr_mock_prompter_stop >+gcr_mock_prompter_disconnect > gcr_parsed_get_attributes > gcr_parsed_get_data > gcr_parsed_get_description >@@ -152,6 +154,7 @@ gcr_pkcs11_initialize_finish > gcr_pkcs11_set_modules > gcr_pkcs11_set_trust_lookup_uris > gcr_pkcs11_set_trust_store_uri >+gcr_prompt_close > gcr_prompt_confirm > gcr_prompt_confirm_async > gcr_prompt_confirm_finish >diff --git a/gcr/gcr-mock-prompter.c b/gcr/gcr-mock-prompter.c >index 3e14403..d2af10e 100644 >--- a/gcr/gcr-mock-prompter.c >+++ b/gcr/gcr-mock-prompter.c >@@ -88,6 +88,7 @@ struct _GcrMockPromptClass { > }; > > typedef struct { >+ gboolean close; > gboolean proceed; > gchar *password; > GList *properties; >@@ -104,7 +105,7 @@ typedef struct { > > /* Owned by the prompter thread*/ > GcrSystemPrompter *prompter; >- const gchar *bus_name; >+ GDBusConnection *connection; > GMainLoop *loop; > } ThreadData; > >@@ -403,6 +404,17 @@ on_timeout_complete_response (gpointer data) > return FALSE; > } > >+static gboolean >+on_timeout_complete_and_close (gpointer data) >+{ >+ GSimpleAsyncResult *res = data; >+ GcrPrompt *prompt = GCR_PROMPT (g_async_result_get_source_object (data)); >+ g_simple_async_result_complete (res); >+ gcr_prompt_close (prompt); >+ g_object_unref (prompt); >+ return FALSE; >+} >+ > static void > gcr_mock_prompt_confirm_async (GcrPrompt *prompt, > GCancellable *cancellable, >@@ -426,6 +438,10 @@ gcr_mock_prompt_confirm_async (GcrPrompt *prompt, > g_critical ("password prompt requested, but not expected"); > g_simple_async_result_set_op_res_gboolean (res, FALSE); > >+ } else if (response->close) { >+ complete_func = on_timeout_complete_and_close; >+ g_simple_async_result_set_op_res_gboolean (res, FALSE); >+ > } else if (response->password) { > g_critical ("confirmation prompt requested, but password prompt expected"); > g_simple_async_result_set_op_res_gboolean (res, FALSE); >@@ -500,6 +516,10 @@ gcr_mock_prompt_password_async (GcrPrompt *prompt, > g_critical ("password prompt requested, but not expected"); > g_simple_async_result_set_op_res_gpointer (res, NULL, NULL); > >+ } else if (response->close) { >+ g_simple_async_result_set_op_res_gpointer (res, NULL, NULL); >+ complete_func = on_timeout_complete_and_close; >+ > } else if (!response->password) { > g_critical ("password prompt requested, but confirmation prompt expected"); > g_simple_async_result_set_op_res_gpointer (res, NULL, NULL); >@@ -793,6 +813,30 @@ gcr_mock_prompter_expect_password_cancel (void) > } > > /** >+ * gcr_mock_prompter_expect_close: >+ * >+ * Queue an expected response on the mock prompter. >+ * >+ * Expects any prompt, and closes the prompt when it gets it. >+ */ >+void >+gcr_mock_prompter_expect_close (void) >+{ >+ MockResponse *response; >+ >+ g_assert (running != NULL); >+ >+ g_mutex_lock (running->mutex); >+ >+ response = g_new0 (MockResponse, 1); >+ response->close = TRUE; >+ >+ g_queue_push_tail (&running->responses, response); >+ >+ g_mutex_unlock (running->mutex); >+} >+ >+/** > * gcr_mock_prompter_is_expecting: > * > * Check if the mock prompter is expecting a response. This will be %TRUE >@@ -894,9 +938,9 @@ mock_prompter_thread (gpointer data) > G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION, > NULL, NULL, &error); > if (error == NULL) { >+ thread_data->connection = connection; > gcr_system_prompter_register (GCR_SYSTEM_PROMPTER (thread_data->prompter), > connection); >- thread_data->bus_name = g_dbus_connection_get_unique_name (connection); > } else { > g_critical ("couldn't create connection: %s", error->message); > g_error_free (error); >@@ -929,10 +973,19 @@ mock_prompter_thread (gpointer data) > thread_data->prompter = NULL; > > if (connection) { >- if (!g_dbus_connection_flush_sync (connection, NULL, &error)) { >- g_critical ("connection flush failed: %s", error->message); >- g_error_free (error); >+ thread_data->connection = NULL; >+ >+ if (!g_dbus_connection_is_closed (connection)) { >+ if (!g_dbus_connection_flush_sync (connection, NULL, &error)) { >+ g_critical ("connection flush failed: %s", error->message); >+ g_error_free (error); >+ } >+ if (!g_dbus_connection_close_sync (connection, NULL, &error)) { >+ g_critical ("connection close failed: %s", error->message); >+ g_error_free (error); >+ } > } >+ > g_object_unref (connection); > } > >@@ -981,7 +1034,22 @@ gcr_mock_prompter_start (void) > g_assert (running->prompter); > g_mutex_unlock (running->mutex); > >- return running->bus_name; >+ return g_dbus_connection_get_unique_name (running->connection); >+} >+ >+void >+gcr_mock_prompter_disconnect (void) >+{ >+ GError *error = NULL; >+ >+ g_assert (running != NULL); >+ g_assert (running->connection); >+ >+ g_dbus_connection_close_sync (running->connection, NULL, &error); >+ if (error != NULL) { >+ g_critical ("disconnect connection close failed: %s", error->message); >+ g_error_free (error); >+ } > } > > /** >diff --git a/gcr/gcr-mock-prompter.h b/gcr/gcr-mock-prompter.h >index 43c53cb..f89f762 100644 >--- a/gcr/gcr-mock-prompter.h >+++ b/gcr/gcr-mock-prompter.h >@@ -36,6 +36,8 @@ G_BEGIN_DECLS > > const gchar * gcr_mock_prompter_start (void); > >+void gcr_mock_prompter_disconnect (void); >+ > void gcr_mock_prompter_stop (void); > > gboolean gcr_mock_prompter_is_prompting (void); >@@ -55,6 +57,8 @@ void gcr_mock_prompter_expect_password_ok (const gchar *p > > void gcr_mock_prompter_expect_password_cancel (void); > >+void gcr_mock_prompter_expect_close (void); >+ > gboolean gcr_mock_prompter_is_expecting (void); > > G_END_DECLS >diff --git a/gcr/gcr-prompt-dialog.c b/gcr/gcr-prompt-dialog.c >index 48d324e..1fb7363 100644 >--- a/gcr/gcr-prompt-dialog.c >+++ b/gcr/gcr-prompt-dialog.c >@@ -39,8 +39,8 @@ > * @short_description: a GTK+ dialog prompt > * > * A #GcrPrompt implementation which shows a GTK+ dialog. The dialog will >- * remain visible (but insensitive) between prompts. Use gtk_widget_hide() to >- * hide the dialog when appropriate. >+ * remain visible (but insensitive) between prompts. If the user cancels the >+ * dialog between prompts, then the dialog will be hidden. > */ > > /** >@@ -102,6 +102,8 @@ struct _GcrPromptDialogPrivate { > > GSimpleAsyncResult *async_result; > GcrPromptReply last_reply; >+ GtkWidget *widget_grid; >+ GtkWidget *continue_button; > GtkWidget *spinner; > GtkWidget *image; > GtkWidget *password_entry; >@@ -111,6 +113,7 @@ struct _GcrPromptDialogPrivate { > GdkDevice *grabbed_device; > gulong grab_broken_id; > gboolean grab_disabled; >+ gboolean was_closed; > }; > > static void gcr_prompt_dialog_prompt_iface (GcrPromptIface *iface); >@@ -501,6 +504,7 @@ gcr_prompt_dialog_constructed (GObject *obj) > g_object_bind_property (self, "cancel-label", button, "label", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); > button = gtk_dialog_add_button (dialog, GTK_STOCK_OK, GTK_RESPONSE_OK); > g_object_bind_property (self, "continue-label", button, "label", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); >+ self->pv->continue_button = button; > > gtk_window_set_type_hint (GTK_WINDOW (dialog), GDK_WINDOW_TYPE_HINT_NORMAL); > gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); >@@ -617,6 +621,7 @@ gcr_prompt_dialog_constructed (GObject *obj) > > gtk_container_add (GTK_CONTAINER (content), GTK_WIDGET (grid)); > gtk_widget_show (GTK_WIDGET (grid)); >+ self->pv->widget_grid = GTK_WIDGET (grid); > > g_signal_connect (self, "map-event", G_CALLBACK (grab_keyboard), self); > g_signal_connect (self, "unmap-event", G_CALLBACK (ungrab_keyboard), self); >@@ -669,12 +674,19 @@ gcr_prompt_dialog_response (GtkDialog *dialog, > GcrPromptDialog *self = GCR_PROMPT_DIALOG (dialog); > GSimpleAsyncResult *res; > >- g_return_if_fail (self->pv->mode != PROMPT_NONE); >- g_return_if_fail (self->pv->async_result != NULL); >+ /* >+ * If this is called while no prompting is going on, then the dialog >+ * is waiting for the caller to perform some action. Close the dialog. >+ */ >+ >+ if (self->pv->mode == PROMPT_NONE) { >+ g_return_if_fail (response_id != GTK_RESPONSE_OK); >+ gcr_prompt_close (GCR_PROMPT (self)); >+ return; >+ } > > switch (response_id) { > case GTK_RESPONSE_OK: >- > switch (self->pv->mode) { > case PROMPT_PASSWORDING: > if (!handle_password_response (self)) >@@ -691,7 +703,8 @@ gcr_prompt_dialog_response (GtkDialog *dialog, > break; > } > >- gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE); >+ gtk_widget_set_sensitive (self->pv->continue_button, FALSE); >+ gtk_widget_set_sensitive (self->pv->widget_grid, FALSE); > gtk_widget_show (self->pv->spinner); > gtk_spinner_start (GTK_SPINNER (self->pv->spinner)); > self->pv->mode = PROMPT_NONE; >@@ -708,10 +721,11 @@ gcr_prompt_dialog_dispose (GObject *obj) > { > GcrPromptDialog *self = GCR_PROMPT_DIALOG (obj); > >- if (self->pv->async_result) >- gcr_prompt_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_DELETE_EVENT); >+ gcr_prompt_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_DELETE_EVENT); > g_assert (self->pv->async_result == NULL); > >+ gcr_prompt_close (GCR_PROMPT (self)); >+ > ungrab_keyboard (GTK_WIDGET (self), NULL, self); > g_assert (self->pv->grabbed_device == NULL); > >@@ -827,16 +841,23 @@ gcr_prompt_dialog_password_async (GcrPrompt *prompt, > self->pv->async_result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, > gcr_prompt_dialog_password_async); > >+ gtk_entry_buffer_set_text (self->pv->password_buffer, "", 0); >+ gtk_entry_buffer_set_text (self->pv->confirm_buffer, "", 0); >+ >+ if (self->pv->was_closed) { >+ self->pv->last_reply = GCR_PROMPT_REPLY_CANCEL; >+ g_simple_async_result_complete_in_idle (self->pv->async_result); >+ return; >+ } >+ > gtk_image_set_from_stock (GTK_IMAGE (self->pv->image), > GTK_STOCK_DIALOG_AUTHENTICATION, > GTK_ICON_SIZE_DIALOG); >- gtk_widget_set_sensitive (GTK_WIDGET (self), TRUE); >+ gtk_widget_set_sensitive (self->pv->continue_button, TRUE); >+ gtk_widget_set_sensitive (self->pv->widget_grid, TRUE); > gtk_widget_hide (self->pv->spinner); > gtk_spinner_stop (GTK_SPINNER (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"); >@@ -884,10 +905,17 @@ gcr_prompt_dialog_confirm_async (GcrPrompt *prompt, > self->pv->async_result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, > gcr_prompt_dialog_confirm_async); > >+ if (self->pv->was_closed) { >+ self->pv->last_reply = GCR_PROMPT_REPLY_CANCEL; >+ g_simple_async_result_complete_in_idle (self->pv->async_result); >+ return; >+ } >+ > gtk_image_set_from_stock (GTK_IMAGE (self->pv->image), > GTK_STOCK_DIALOG_QUESTION, > GTK_ICON_SIZE_DIALOG); >- gtk_widget_set_sensitive (GTK_WIDGET (self), TRUE); >+ gtk_widget_set_sensitive (self->pv->continue_button, TRUE); >+ gtk_widget_set_sensitive (self->pv->widget_grid, TRUE); > gtk_widget_hide (self->pv->spinner); > gtk_spinner_stop (GTK_SPINNER (self->pv->spinner)); > >@@ -920,10 +948,21 @@ gcr_prompt_dialog_confirm_finish (GcrPrompt *prompt, > } > > static void >+gcr_prompt_dialog_close (GcrPrompt *prompt) >+{ >+ GcrPromptDialog *self = GCR_PROMPT_DIALOG (prompt); >+ if (!self->pv->was_closed) { >+ self->pv->was_closed = TRUE; >+ gtk_widget_hide (GTK_WIDGET (self)); >+ } >+} >+ >+static void > gcr_prompt_dialog_prompt_iface (GcrPromptIface *iface) > { > iface->prompt_password_async = gcr_prompt_dialog_password_async; > iface->prompt_password_finish = gcr_prompt_dialog_password_finish; > iface->prompt_confirm_async = gcr_prompt_dialog_confirm_async; > iface->prompt_confirm_finish = gcr_prompt_dialog_confirm_finish; >+ iface->prompt_close = gcr_prompt_dialog_close; > } >diff --git a/gcr/gcr-prompt.c b/gcr/gcr-prompt.c >index b80c899..033d536 100644 >--- a/gcr/gcr-prompt.c >+++ b/gcr/gcr-prompt.c >@@ -64,6 +64,7 @@ > * @prompt_password_finish: complete a password prompt > * @prompt_confirm_async: begin a confirm prompt > * @prompt_confirm_finish: complete a confirm prompt >+ * @prompt_close: close a prompt > * > * The interface for implementing #GcrPrompt. > */ >@@ -75,6 +76,14 @@ > * > * Various replies returned by gcr_prompt_confirm() and friends. > */ >+ >+enum { >+ PROMPT_CLOSE, >+ NUM_SIGNALS >+}; >+ >+static guint signals[NUM_SIGNALS]; >+ > typedef struct { > GAsyncResult *result; > GMainLoop *loop; >@@ -226,6 +235,20 @@ gcr_prompt_default_init (GcrPromptIface *iface) > g_param_spec_string ("cancel-label", "Cancel label", "Cancel button label", > _("Cancel"), G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); > >+ /** >+ * GcrPrompt::prompt-close: >+ * >+ * Action signal fired when the prompt is to be closed. After the default >+ * handler has run, the prompt is closed. The various prompting methods >+ * will return results as if the user dismissed the prompt. >+ * >+ * You can use the gcr_prompt_close() method to emit this signal. >+ */ >+ signals[PROMPT_CLOSE] = g_signal_new ("prompt-close", GCR_TYPE_PROMPT, G_SIGNAL_RUN_FIRST, >+ G_STRUCT_OFFSET (GcrPromptIface, prompt_close), >+ NULL, NULL, g_cclosure_marshal_generic, >+ G_TYPE_NONE, 0); >+ > g_once_init_leave (&initialized, 1); > } > } >@@ -247,7 +270,7 @@ static RunClosure * > run_closure_begin (GMainContext *context) > { > RunClosure *closure = g_new0 (RunClosure, 1); >- closure->loop = g_main_loop_new (context ? context : g_main_context_get_thread_default (), FALSE); >+ closure->loop = g_main_loop_new (context, FALSE); > closure->result = NULL; > > /* We assume ownership of context reference */ >@@ -1027,3 +1050,21 @@ gcr_prompt_confirm_run (GcrPrompt *prompt, > > return reply; > } >+ >+/** >+ * gcr_prompt_close: >+ * @prompt: a prompt >+ * >+ * Closes the prompt so that in can no longer be used to prompt. The various >+ * prompt methods will return results as if the user dismissed the prompt. >+ * >+ * The prompt may also be closed by the implementor of the #GcrPrompt object. >+ * >+ * This emits the GcrPrompt::prompt-close signal on the prompt object. >+ */ >+void >+gcr_prompt_close (GcrPrompt *prompt) >+{ >+ g_return_if_fail (GCR_IS_PROMPT (prompt)); >+ g_signal_emit (prompt, signals[PROMPT_CLOSE], 0); >+} >diff --git a/gcr/gcr-prompt.h b/gcr/gcr-prompt.h >index 00ff8a6..67735c3 100644 >--- a/gcr/gcr-prompt.h >+++ b/gcr/gcr-prompt.h >@@ -67,6 +67,8 @@ struct _GcrPromptIface { > GcrPromptReply (* prompt_confirm_finish) (GcrPrompt *prompt, > GAsyncResult *result, > GError **error); >+ >+ void (* prompt_close) (GcrPrompt *prompt); > }; > > GType gcr_prompt_get_type (void); >@@ -159,6 +161,8 @@ GcrPromptReply gcr_prompt_confirm_run (GcrPrompt *prompt, > GCancellable *cancellable, > GError **error); > >+void gcr_prompt_close (GcrPrompt *prompt); >+ > G_END_DECLS > > #endif /* __GCR_PROMPT_H__ */ >diff --git a/gcr/gcr-system-prompt.c b/gcr/gcr-system-prompt.c >index 36c4500..b370b1c 100644 >--- a/gcr/gcr-system-prompt.c >+++ b/gcr/gcr-system-prompt.c >@@ -143,9 +143,10 @@ static gint unique_prompt_id = 0; > > typedef struct { > GSource *timeout; >+ GSource *waiting; > GMainContext *context; > GCancellable *cancellable; >- gboolean waiting; >+ guint watch_id; > } CallClosure; > > static void >@@ -154,11 +155,45 @@ call_closure_free (gpointer data) > CallClosure *closure = data; > if (closure->timeout) > g_source_destroy (closure->timeout); >- g_clear_object (&closure->cancellable); >+ if (closure->waiting) >+ g_source_destroy (closure->waiting); >+ if (closure->watch_id) >+ g_bus_unwatch_name (closure->watch_id); >+ g_object_unref (closure->cancellable); > g_free (data); > } > > static void >+on_propagate_cancelled (GCancellable *cancellable, >+ gpointer user_data) >+{ >+ /* Propagate the cancelled signal */ >+ GCancellable *cancel = G_CANCELLABLE (user_data); >+ g_cancellable_cancel (cancel); >+} >+ >+static CallClosure * >+call_closure_new (GCancellable *cancellable) >+{ >+ CallClosure *call; >+ >+ /* >+ * We use our own cancellable object, since we cancel it it in >+ * situations other than when the caller cancels. >+ */ >+ >+ call = g_new0 (CallClosure, 1); >+ call->cancellable = g_cancellable_new (); >+ >+ if (cancellable) { >+ g_cancellable_connect (cancellable, G_CALLBACK (on_propagate_cancelled), >+ g_object_ref (call->cancellable), g_object_unref); >+ } >+ >+ return call; >+} >+ >+static void > gcr_system_prompt_init (GcrSystemPrompt *self) > { > self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_SYSTEM_PROMPT, >@@ -391,15 +426,100 @@ gcr_system_prompt_constructed (GObject *obj) > } > > static void >+on_prompter_stop_prompting (GObject *source, >+ GAsyncResult *result, >+ gpointer user_data) >+{ >+ GSimpleAsyncResult *async = NULL; >+ GError *error = NULL; >+ GVariant *retval; >+ >+ retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); >+ if (error != NULL) { >+ _gcr_debug ("failed to stop prompting: %s", egg_error_message (error)); >+ g_clear_error (&error); >+ } >+ >+ if (retval) >+ g_variant_unref (retval); >+ >+ if (user_data) { >+ async = G_SIMPLE_ASYNC_RESULT (user_data); >+ g_simple_async_result_complete (async); >+ g_object_unref (async); >+ } >+} >+ >+static void >+perform_close (GcrSystemPrompt *self, >+ GSimpleAsyncResult *async, >+ GCancellable *cancellable) >+{ >+ GSimpleAsyncResult *res; >+ CallClosure *closure; >+ gboolean called = FALSE; >+ gboolean closed; >+ >+ closed = self->pv->closed; >+ self->pv->closed = TRUE; >+ >+ if (!closed) >+ _gcr_debug ("closing prompt"); >+ >+ if (self->pv->pending) { >+ res = g_object_ref (self->pv->pending); >+ g_clear_object (&self->pv->pending); >+ closure = g_simple_async_result_get_op_res_gpointer (res); >+ g_cancellable_cancel (closure->cancellable); >+ g_simple_async_result_complete_in_idle (res); >+ g_object_unref (res); >+ } >+ >+ if (self->pv->prompt_registered) { >+ g_dbus_connection_unregister_object (self->pv->connection, >+ self->pv->prompt_registered); >+ self->pv->prompt_registered = 0; >+ } >+ >+ if (self->pv->begun_prompting) { >+ if (self->pv->connection && self->pv->prompt_path) { >+ _gcr_debug ("Calling the prompter %s method", GCR_DBUS_PROMPTER_METHOD_STOP); >+ g_dbus_connection_call (self->pv->connection, >+ self->pv->prompter_bus_name, >+ GCR_DBUS_PROMPTER_OBJECT_PATH, >+ GCR_DBUS_PROMPTER_INTERFACE, >+ GCR_DBUS_PROMPTER_METHOD_STOP, >+ g_variant_new ("(o)", self->pv->prompt_path), >+ G_VARIANT_TYPE ("()"), >+ G_DBUS_CALL_FLAGS_NO_AUTO_START, >+ -1, cancellable, >+ on_prompter_stop_prompting, >+ async ? g_object_ref (async) : NULL); >+ called = TRUE; >+ } >+ self->pv->begun_prompting = FALSE; >+ } >+ >+ g_free (self->pv->prompt_path); >+ self->pv->prompt_path = NULL; >+ >+ g_clear_object (&self->pv->connection); >+ >+ if (!called && async) >+ g_simple_async_result_complete_in_idle (async); >+ >+ /* Emit the signal if necessary, after closed */ >+ if (!closed) >+ gcr_prompt_close (GCR_PROMPT (self)); >+} >+ >+static void > gcr_system_prompt_dispose (GObject *obj) > { > GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (obj); > > g_clear_object (&self->pv->exchange); >- >- _gcr_debug ("closing prompt asynchronously: %s", self->pv->prompt_path); >- if (self->pv->connection) >- gcr_system_prompt_close_async (self, NULL, NULL, NULL); >+ perform_close (self, NULL, NULL); > > g_hash_table_remove_all (self->pv->properties); > g_hash_table_remove_all (self->pv->dirty_properties); >@@ -560,17 +680,15 @@ prompt_method_done (GcrSystemPrompt *self, > GDBusMethodInvocation *invocation, > GVariant *parameters) > { >- GSimpleAsyncResult *res; >- >- g_return_if_fail (G_IS_SIMPLE_ASYNC_RESULT (self->pv->pending)); >- > g_dbus_method_invocation_return_value (invocation, g_variant_new ("()")); > >- res = g_object_ref (self->pv->pending); >- g_clear_object (&self->pv->pending); >- g_simple_async_result_set_op_res_gpointer (res, NULL, NULL); >- g_simple_async_result_complete (res); >- g_object_unref (res); >+ /* >+ * At this point we're done prompting, and calling StopPrompting >+ * on the prompter is no longer necessary. It may have already been >+ * called, or the prompter may have stopped on its own accord. >+ */ >+ self->pv->begun_prompting = FALSE; >+ perform_close (self, NULL, NULL); > } > > static void >@@ -660,6 +778,16 @@ register_prompt_object (GcrSystemPrompt *self, > } > > static void >+on_prompter_vanished (GDBusConnection *connection, >+ const gchar *name, >+ gpointer user_data) >+{ >+ GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data); >+ CallClosure *call = g_simple_async_result_get_op_res_gpointer (async); >+ g_cancellable_cancel (call->cancellable); >+} >+ >+static void > on_bus_connected (GObject *source, > GAsyncResult *result, > gpointer user_data) >@@ -681,6 +809,12 @@ on_bus_connected (GObject *source, > > g_main_context_push_thread_default (closure->context); > >+ closure->watch_id = g_bus_watch_name_on_connection (self->pv->connection, >+ self->pv->prompter_bus_name, >+ G_BUS_NAME_WATCHER_FLAGS_NONE, >+ NULL, on_prompter_vanished, >+ res, NULL); >+ > register_prompt_object (self, &error); > > g_main_context_pop_thread_default (closure->context); >@@ -753,6 +887,27 @@ on_call_timeout (gpointer user_data) > return FALSE; /* Don't call this function again */ > } > >+static gboolean >+on_call_cancelled (GCancellable *cancellable, >+ gpointer user_data) >+{ >+ GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data); >+ CallClosure *call = g_simple_async_result_get_op_res_gpointer (async); >+ GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data)); >+ >+ g_source_destroy (call->waiting); >+ call->waiting = NULL; >+ >+ g_simple_async_result_set_error (async, G_IO_ERROR, G_IO_ERROR_CANCELLED, >+ _("The operation was cancelled")); >+ >+ /* Tell the prompter we're no longer interested */ >+ gcr_system_prompt_close_async (self, NULL, NULL, NULL); >+ >+ g_object_unref (self); >+ return FALSE; /* Don't call this function again */ >+} >+ > void > perform_init_async (GcrSystemPrompt *self, > GSimpleAsyncResult *res) >@@ -814,7 +969,7 @@ gcr_system_prompt_real_init_async (GAsyncInitable *initable, > > res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, > gcr_system_prompt_real_init_async); >- closure = g_new0 (CallClosure, 1); >+ closure = call_closure_new (cancellable); > closure->context = g_main_context_get_thread_default (); > if (closure->context) > g_main_context_ref (closure->context); >@@ -947,16 +1102,20 @@ on_perform_prompt_complete (GObject *source, > { > GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); > GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data)); >- CallClosure *closure = g_simple_async_result_get_op_res_gpointer (res); >+ CallClosure *call = g_simple_async_result_get_op_res_gpointer (res); > GError *error = NULL; > GVariant *retval; > > retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); > if (error != NULL) { >+ self->pv->pending = NULL; > g_simple_async_result_take_error (res, error); >- g_simple_async_result_complete_in_idle (res); >+ g_simple_async_result_complete (res); > } else { >- closure->waiting = TRUE; >+ g_assert (call->waiting == NULL); >+ call->waiting = g_cancellable_source_new (call->cancellable); >+ g_source_set_callback (call->waiting, (GSourceFunc)on_call_cancelled, res, NULL); >+ g_source_attach (call->waiting, call->context); > } > > if (retval) >@@ -988,19 +1147,31 @@ perform_prompt_async (GcrSystemPrompt *self, > return; > } > >- _gcr_debug ("prompting for password"); >- > res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, source_tag); >- closure = g_new0 (CallClosure, 1); >- closure->cancellable = cancellable ? g_object_ref (cancellable) : cancellable; >+ closure = call_closure_new (cancellable); > g_simple_async_result_set_op_res_gpointer (res, closure, call_closure_free); > >+ if (self->pv->closed) { >+ self->pv->last_response = g_strdup (GCR_DBUS_PROMPT_REPLY_NONE); >+ g_simple_async_result_complete_in_idle (res); >+ g_object_unref (res); >+ return; >+ } >+ >+ _gcr_debug ("prompting for password"); >+ > exchange = gcr_system_prompt_get_secret_exchange (self); > if (self->pv->received) > sent = gcr_secret_exchange_send (exchange, NULL, 0); > else > sent = gcr_secret_exchange_begin (exchange); > >+ closure->watch_id = g_bus_watch_name_on_connection (self->pv->connection, >+ self->pv->prompter_bus_name, >+ G_BUS_NAME_WATCHER_FLAGS_NONE, >+ NULL, on_prompter_vanished, >+ res, NULL); >+ > builder = build_dirty_properties (self); > > /* Reregister the prompt object in the current GMainContext */ >@@ -1111,12 +1282,29 @@ gcr_system_prompt_confirm_finish (GcrPrompt *prompt, > } > > static void >+gcr_system_prompt_real_close (GcrPrompt *prompt) >+{ >+ GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (prompt); >+ >+ /* >+ * Setting this before calling close_async allows us to prevent firing >+ * this signal again in a loop. >+ */ >+ >+ if (!self->pv->closed) { >+ self->pv->closed = TRUE; >+ perform_close (self, NULL, NULL); >+ } >+} >+ >+static void > gcr_system_prompt_prompt_iface (GcrPromptIface *iface) > { > iface->prompt_password_async = gcr_system_prompt_password_async; > iface->prompt_password_finish = gcr_system_prompt_password_finish; > iface->prompt_confirm_async = gcr_system_prompt_confirm_async; > iface->prompt_confirm_finish = gcr_system_prompt_confirm_finish; >+ iface->prompt_close = gcr_system_prompt_real_close; > } > > /** >@@ -1303,8 +1491,8 @@ gcr_system_prompt_open_for_prompter (const gchar *prompter_name, > * @cancellable: an optional cancellation object > * @error: location to place an error on failure > * >- * Close this prompt. After calling this function, no further methods may be >- * called on this object. The prompt object is not unreferenced by this >+ * Close this prompt. After calling this function, no further prompts will >+ * succeed on this object. The prompt object is not unreferenced by this > * function, and you must unreference it once done. > * > * This call may block, use the gcr_system_prompt_close_async() to perform >@@ -1339,28 +1527,6 @@ gcr_system_prompt_close (GcrSystemPrompt *self, > return result; > } > >-static void >-on_prompter_stop_prompting (GObject *source, >- GAsyncResult *result, >- gpointer user_data) >-{ >- GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); >- GError *error = NULL; >- GVariant *retval; >- >- retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); >- if (error != NULL) { >- _gcr_debug ("failed to stop prompting: %s", egg_error_message (error)); >- g_clear_error (&error); >- } >- >- if (retval) >- g_variant_unref (retval); >- >- g_simple_async_result_complete (res); >- g_object_unref (res); >-} >- > /** > * gcr_system_prompt_close_async: > * @self: the prompt >@@ -1382,65 +1548,20 @@ gcr_system_prompt_close_async (GcrSystemPrompt *self, > { > GSimpleAsyncResult *res; > CallClosure *closure; >- gboolean called = FALSE; > > g_return_if_fail (GCR_SYSTEM_PROMPT (self)); > g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); >- g_return_if_fail (self->pv->connection != NULL); >- g_return_if_fail (self->pv->prompt_path != NULL); >- g_return_if_fail (self->pv->closed == FALSE); >- >- _gcr_debug ("closing prompt"); >- self->pv->closed = TRUE; >- >- if (self->pv->pending) { >- res = g_object_ref (self->pv->pending); >- g_clear_object (&self->pv->pending); >- closure = g_simple_async_result_get_op_res_gpointer (res); >- g_cancellable_cancel (closure->cancellable); >- g_simple_async_result_complete_in_idle (res); >- g_object_unref (res); >- } > > res = g_simple_async_result_new (NULL, callback, user_data, > gcr_system_prompt_close_async); >- closure = g_new0 (CallClosure, 1); >- closure->cancellable = cancellable ? g_object_ref (cancellable) : g_cancellable_new (); >+ closure = call_closure_new (cancellable); > closure->context = g_main_context_get_thread_default (); > if (closure->context != NULL) > g_main_context_ref (closure->context); > g_simple_async_result_set_op_res_gpointer (res, closure, call_closure_free); > >- if (self->pv->prompt_registered) { >- g_dbus_connection_unregister_object (self->pv->connection, >- self->pv->prompt_registered); >- self->pv->prompt_registered = 0; >- } >- >- if (self->pv->begun_prompting) { >- if (self->pv->connection) { >- g_dbus_connection_call (self->pv->connection, >- self->pv->prompter_bus_name, >- GCR_DBUS_PROMPTER_OBJECT_PATH, >- GCR_DBUS_PROMPTER_INTERFACE, >- GCR_DBUS_PROMPTER_METHOD_STOP, >- g_variant_new ("(o)", self->pv->prompt_path), >- G_VARIANT_TYPE ("()"), >- G_DBUS_CALL_FLAGS_NO_AUTO_START, >- -1, closure->cancellable, >- on_prompter_stop_prompting, >- g_object_ref (res)); >- called = TRUE; >- } >- } >- >- g_free (self->pv->prompt_path); >- self->pv->prompt_path = NULL; >- >- g_clear_object (&self->pv->connection); >+ perform_close (self, res, closure->cancellable); > >- if (!called) >- g_simple_async_result_complete_in_idle (res); > g_object_unref (res); > } > >diff --git a/gcr/gcr-system-prompter.c b/gcr/gcr-system-prompter.c >index fb03ec8..ba16dcc 100644 >--- a/gcr/gcr-system-prompter.c >+++ b/gcr/gcr-system-prompter.c >@@ -121,6 +121,8 @@ typedef struct { > GHashTable *changed; > GcrSecretExchange *exchange; > gboolean received; >+ gboolean closed; >+ guint close_sig; > } ActivePrompt; > > static void prompt_send_ready (ActivePrompt *active, >@@ -151,6 +153,14 @@ on_prompt_notify (GObject *object, > g_hash_table_replace (active->changed, key, key); > } > >+static void >+on_prompt_close (GcrPrompt *prompt, >+ gpointer user_data) >+{ >+ ActivePrompt *active = user_data; >+ prompt_stop_prompting (active->prompter, active->callback, TRUE, FALSE); >+} >+ > static Callback * > callback_dup (Callback *original) > { >@@ -195,9 +205,13 @@ active_prompt_unref (gpointer data) > ActivePrompt *active = data; > > if (g_atomic_int_dec_and_test (&active->refs)) { >+ callback_free (active->callback); > g_object_unref (active->prompter); > g_object_unref (active->cancellable); >- g_signal_handlers_disconnect_by_func (active->prompt, on_prompt_notify, active); >+ if (g_signal_handler_is_connected (active->prompt, active->notify_sig)) >+ g_signal_handler_disconnect (active->prompt, active->notify_sig); >+ if (g_signal_handler_is_connected (active->prompt, active->close_sig)) >+ g_signal_handler_disconnect (active->prompt, active->close_sig); > g_object_unref (active->prompt); > g_hash_table_destroy (active->changed); > if (active->exchange) >@@ -221,17 +235,15 @@ active_prompt_create (GcrSystemPrompter *self, > ActivePrompt *active; > > active = g_slice_new0 (ActivePrompt); >- if (!g_hash_table_lookup_extended (self->pv->callbacks, lookup, >- (gpointer *)&active->callback, NULL)) >- g_return_val_if_reached (NULL); >- > active->refs = 1; >+ active->callback = callback_dup (lookup); > active->prompter = g_object_ref (self); > active->cancellable = g_cancellable_new (); > g_signal_emit (self, signals[NEW_PROMPT], 0, &active->prompt); > g_return_val_if_fail (active->prompt != NULL, NULL); > > active->notify_sig = g_signal_connect (active->prompt, "notify", G_CALLBACK (on_prompt_notify), active); >+ active->close_sig = g_signal_connect (active->prompt, "prompt-close", G_CALLBACK (on_prompt_close), active); > active->changed = g_hash_table_new (g_direct_hash, g_direct_equal); > > /* Insert us into the active hash table */ >@@ -481,11 +493,26 @@ prompt_stop_prompting (GcrSystemPrompter *self, > { > ActivePrompt *active; > GVariant *retval; >+ gpointer watch; >+ >+ _gcr_debug ("stopping prompting for operation %s@%s", >+ callback->path, callback->name); > > /* Get a pointer to our actual callback */ > if (!g_hash_table_lookup_extended (self->pv->callbacks, callback, >- (gpointer *)&callback, NULL)) >+ (gpointer *)&callback, &watch)) { >+ _gcr_debug ("couldn't find the callback for prompting operation %s@%s", >+ callback->path, callback->name); > return; >+ } >+ >+ /* >+ * We remove these from the callbacks hash table so that we don't >+ * do this stuff more than once. However we still need the callback >+ * to be valid. >+ */ >+ if (!g_hash_table_steal (self->pv->callbacks, callback)) >+ g_assert_not_reached (); > > /* Removed from the waiting queue */ > g_queue_remove (&self->pv->waiting, callback); >@@ -493,16 +520,19 @@ prompt_stop_prompting (GcrSystemPrompter *self, > /* Close any active prompt */ > active = g_hash_table_lookup (self->pv->active, callback); > if (active != NULL) { >+ active_prompt_ref (active); >+ g_hash_table_remove (self->pv->active, callback); >+ > if (!active->ready) { > _gcr_debug ("cancelling active prompting operation for %s@%s", > callback->path, callback->name); > g_cancellable_cancel (active->cancellable); > } > >- _gcr_debug ("disposing the prompt"); >- >+ _gcr_debug ("closing the prompt"); >+ gcr_prompt_close (active->prompt); > g_object_run_dispose (G_OBJECT (active->prompt)); >- g_hash_table_remove (self->pv->active, callback); >+ active_prompt_unref (active); > } > > /* Notify the caller */ >@@ -540,8 +570,14 @@ prompt_stop_prompting (GcrSystemPrompter *self, > -1, NULL, NULL, NULL); > } > >- /* And all traces gone, including watch */ >- g_hash_table_remove (self->pv->callbacks, callback); >+ /* >+ * And all traces gone, including watch. We stole these values from >+ * the callbacks hashtable above. Now free them >+ */ >+ >+ callback_free (callback); >+ unwatch_name (watch); >+ > g_object_notify (G_OBJECT (self), "prompting"); > } > >diff --git a/gcr/tests/frob-system-prompt.c b/gcr/tests/frob-system-prompt.c >index 39919b3..b743adf 100644 >--- a/gcr/tests/frob-system-prompt.c >+++ b/gcr/tests/frob-system-prompt.c >@@ -25,6 +25,8 @@ > > #include "gcr/gcr.h" > >+#include "egg/egg-testing.h" >+ > #include <gtk/gtk.h> > #include <gdk/gdkx.h> > >@@ -67,6 +69,7 @@ on_prompt_clicked (GtkToolButton *button, > > g_print ("password: %s\n", password); > g_object_unref (prompt); >+ egg_assert_not_object (prompt); > } > > static gboolean >diff --git a/gcr/tests/test-system-prompt.c b/gcr/tests/test-system-prompt.c >index 944d773..ed78ec0 100644 >--- a/gcr/tests/test-system-prompt.c >+++ b/gcr/tests/test-system-prompt.c >@@ -513,6 +513,15 @@ test_prompt_close (Test *test, > } > > static void >+on_prompt_close (GcrPrompt *prompt, >+ gpointer user_data) >+{ >+ gboolean *prompt_closed = (gboolean *)user_data; >+ g_assert (*prompt_closed == FALSE); >+ *prompt_closed = TRUE; >+} >+ >+static void > test_close_cancels (Test *test, > gconstpointer unused) > { >@@ -520,6 +529,7 @@ test_close_cancels (Test *test, > GError *error = NULL; > const gchar *password = NULL; > GAsyncResult *result = NULL; >+ gboolean prompt_closed; > > gcr_mock_prompter_set_delay_msec (3000); > gcr_mock_prompter_expect_password_ok ("booo", NULL); >@@ -528,11 +538,15 @@ test_close_cancels (Test *test, > g_assert_no_error (error); > g_assert (GCR_IS_SYSTEM_PROMPT (prompt)); > >+ prompt_closed = FALSE; >+ g_signal_connect_after (prompt, "prompt-close", G_CALLBACK (on_prompt_close), &prompt_closed); >+ > gcr_prompt_password_async (prompt, NULL, on_async_result, &result); > > gcr_system_prompt_close (GCR_SYSTEM_PROMPT (prompt), NULL, &error); > g_assert_no_error (error); > >+ g_assert (prompt_closed == TRUE); > egg_test_wait (); > > password = gcr_prompt_password_finish (prompt, result, &error); >@@ -544,6 +558,172 @@ test_close_cancels (Test *test, > egg_assert_not_object (prompt); > } > >+static void >+test_close_from_prompter (Test *test, >+ gconstpointer unused) >+{ >+ GcrPrompt *prompt; >+ GError *error = NULL; >+ gboolean ret; >+ const gchar *password; >+ gboolean prompt_closed; >+ >+ gcr_mock_prompter_expect_close (); >+ >+ prompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 1, NULL, &error); >+ g_assert_no_error (error); >+ g_assert (GCR_IS_SYSTEM_PROMPT (prompt)); >+ >+ prompt_closed = FALSE; >+ g_signal_connect_after (prompt, "prompt-close", G_CALLBACK (on_prompt_close), &prompt_closed); >+ >+ ret = gcr_prompt_confirm_run (prompt, NULL, &error); >+ g_assert_no_error (error); >+ g_assert (ret == GCR_PROMPT_REPLY_CANCEL); >+ >+ /* The prompt should be closed now, these shouldn't reach the mock prompter */ >+ >+ while (!prompt_closed) >+ g_main_context_iteration (NULL, TRUE); >+ >+ ret = gcr_prompt_confirm_run (prompt, NULL, &error); >+ g_assert_no_error (error); >+ g_assert (ret == GCR_PROMPT_REPLY_CANCEL); >+ >+ password = gcr_prompt_password_run (prompt, NULL, &error); >+ g_assert_no_error (error); >+ g_assert (password == NULL); >+ >+ g_object_unref (prompt); >+ egg_assert_not_object (prompt); >+} >+ >+static void >+test_after_close_dismisses (Test *test, >+ gconstpointer unused) >+{ >+ GcrPrompt *prompt; >+ GError *error = NULL; >+ gboolean ret; >+ const gchar *password; >+ gboolean prompt_closed; >+ >+ gcr_mock_prompter_expect_confirm_ok (NULL); >+ >+ prompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 1, NULL, &error); >+ g_assert_no_error (error); >+ g_assert (GCR_IS_SYSTEM_PROMPT (prompt)); >+ >+ prompt_closed = FALSE; >+ g_signal_connect_after (prompt, "prompt-close", G_CALLBACK (on_prompt_close), &prompt_closed); >+ >+ >+ ret = gcr_prompt_confirm_run (prompt, NULL, &error); >+ g_assert_no_error (error); >+ g_assert (ret == GCR_PROMPT_REPLY_CONTINUE); >+ >+ gcr_prompt_close (prompt); >+ g_assert (prompt_closed); >+ >+ /* These should never even reach the mock prompter */ >+ >+ ret = gcr_prompt_confirm_run (prompt, NULL, &error); >+ g_assert_no_error (error); >+ g_assert (ret == GCR_PROMPT_REPLY_CANCEL); >+ >+ password = gcr_prompt_password_run (prompt, NULL, &error); >+ g_assert_no_error (error); >+ g_assert (password == NULL); >+ >+ while (g_main_context_iteration (NULL, FALSE)); >+ >+ g_object_unref (prompt); >+ egg_assert_not_object (prompt); >+} >+ >+typedef struct { >+ GAsyncResult *result1; >+ GAsyncResult *result2; >+} ResultPair; >+ >+static void >+on_result_pair_one (GObject *source, >+ GAsyncResult *result, >+ gpointer user_data) >+{ >+ ResultPair *pair = user_data; >+ g_assert (pair->result1 == NULL); >+ pair->result1 = g_object_ref (result); >+ if (pair->result1 && pair->result2) >+ egg_test_wait_stop (); >+} >+ >+static void >+on_result_pair_two (GObject *source, >+ GAsyncResult *result, >+ gpointer user_data) >+{ >+ ResultPair *pair = user_data; >+ g_assert (pair->result2 == NULL); >+ pair->result2 = g_object_ref (result); >+ if (pair->result1 && pair->result2) >+ egg_test_wait_stop (); >+} >+ >+static void >+test_watch_cancels (Test *test, >+ gconstpointer unused) >+{ >+ GDBusConnection *connection; >+ GcrPrompt *prompt; >+ GcrPrompt *prompt2; >+ GError *error = NULL; >+ const gchar *password; >+ ResultPair pair = { NULL, NULL }; >+ >+ gcr_mock_prompter_set_delay_msec (3000); >+ gcr_mock_prompter_expect_password_ok ("booo", NULL); >+ >+ connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); >+ g_assert_no_error (error); >+ >+ /* This should happen immediately */ >+ prompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error); >+ g_assert_no_error (error); >+ g_assert (GCR_IS_SYSTEM_PROMPT (prompt)); >+ >+ /* Show a password prompt */ >+ gcr_prompt_password_async (prompt, NULL, on_result_pair_one, &pair); >+ >+ /* This prompt should wait, block */ >+ gcr_system_prompt_open_for_prompter_async (test->prompter_name, 0, NULL, >+ on_result_pair_two, &pair); >+ >+ /* Wait a bit before stopping, so outgoing request is done */ >+ g_usleep (G_TIME_SPAN_SECOND / 4); >+ >+ /* Kill the mock prompter */ >+ gcr_mock_prompter_disconnect (); >+ >+ /* Both the above operations should cancel */ >+ egg_test_wait (); >+ >+ prompt2 = gcr_system_prompt_open_finish (pair.result2, &error); >+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); >+ g_clear_error (&error); >+ g_assert (prompt2 == NULL); >+ >+ password = gcr_prompt_password_finish (prompt, pair.result1, &error); >+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); >+ g_clear_error (&error); >+ g_assert (password == NULL); >+ >+ g_object_unref (prompt); >+ g_object_unref (pair.result1); >+ g_object_unref (pair.result2); >+ g_object_unref (connection); >+} >+ > int > main (int argc, char **argv) > { >@@ -566,6 +746,9 @@ main (int argc, char **argv) > g_test_add ("/gcr/system-prompt/properties-reset", Test, NULL, setup, test_prompt_properties_reset, teardown); > g_test_add ("/gcr/system-prompt/close", Test, NULL, setup, test_prompt_close, teardown); > g_test_add ("/gcr/system-prompt/close-cancels", Test, NULL, setup, test_close_cancels, teardown); >+ g_test_add ("/gcr/system-prompt/after-close-dismisses", Test, NULL, setup, test_after_close_dismisses, teardown); >+ g_test_add ("/gcr/system-prompt/close-from-prompter", Test, NULL, setup, test_close_from_prompter, teardown); >+ g_test_add ("/gcr/system-prompt/watch-cancels", Test, NULL, setup, test_watch_cancels, teardown); > > return egg_tests_run_with_loop (); > } >-- >1.8.1 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 907156
:
692799
|
692894
|
692895
|
693003
|
693042
|
693043
|
693870
|
693943