Reviewed & pushed with a few typo corrections.

On Tue, Feb 19, 2013 at 09:37:29 +0100, Jakub Filak wrote:
> - closes rhbz#901467
> 
> Signed-off-by: Jakub Filak <[email protected]>
> ---
>  src/gtk-helpers/secrets.c | 132 
> +++++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 118 insertions(+), 14 deletions(-)
> 
> diff --git a/src/gtk-helpers/secrets.c b/src/gtk-helpers/secrets.c
> index 9de2284..c3c1f68 100644
> --- a/src/gtk-helpers/secrets.c
> +++ b/src/gtk-helpers/secrets.c
> @@ -34,6 +34,9 @@
>  /* 5s timeout*/
>  #define SECRETS_CALL_DEFAULT_TIMEOUT 5000
>  
> +/* 15s until the timeout dialog will appear  */
> +#define PROMPT_TIMEOUT_SECONDS 15
> +
>  /* Well known errors for which we have workarounds */
>  #define NOT_IMPLEMENTED_READ_ALIAS_ERROR 
> "org.freedesktop.DBus.Error.UnknownMethod"
>  #define INVALID_PROPERTIES_ARGUMENTS_ERROR 
> "org.freedesktop.DBus.Error.InvalidArgs"
> @@ -377,24 +380,41 @@ static void secrets_service_set_unavailable(void)
>  /* http://standards.freedesktop.org/secret-service/re05.html                 
>   */
>  
> /*******************************************************************************/
>  
> +/*
> + * Holds all data necessary for management of the glib main loop with the
> + * timeout dialog.
> + */
> +struct secrets_loop_env
> +{
> +    GMainContext* gcontext;
> +    GMainLoop *gloop;
> +    GtkWidget *timeout_dialog;
> +};
> +
>  struct prompt_source
>  {
>      GSource source;
>      GDBusProxy *prompt_proxy;
> -    GMainLoop *loop;
> +    struct secrets_loop_env *env;
>  };
>  
>  struct prompt_call_back_args
>  {
>      gboolean dismissed;
>      GVariant *result;
> -    GMainLoop *loop;
> +    struct secrets_loop_env *env;
>  };
>  
> -static void prompt_quit_loop(GMainLoop *loop)
> +static void prompt_quit_loop(struct secrets_loop_env *env)
>  {
> -    if (g_main_loop_is_running(loop))
> -        g_main_loop_quit(loop);
> +    if (NULL != env->timeout_dialog)
> +    {
> +        gtk_widget_destroy(env->timeout_dialog);
> +        env->timeout_dialog = NULL;
> +    }
> +
> +    if (g_main_loop_is_running(env->gloop))
> +        g_main_loop_quit(env->gloop);
>  }
>  
>  static gboolean prompt_g_idle_prepare(GSource *source_data, gint *timeout)
> @@ -425,7 +445,7 @@ static gboolean prompt_g_idle_dispatch(GSource *source,
>      if (!resp)
>          /* We have to kill the loop because a dbus call failed and the 
> signal */
>          /* which stops the loop won't be received */
> -        prompt_quit_loop(prompt_source->loop);
> +        prompt_quit_loop(prompt_source->env);
>      else
>          g_variant_unref(resp);
>  
> @@ -454,7 +474,7 @@ static void prompt_call_back(GDBusConnection *connection, 
> const gchar *sender_na
>          /* if the prompt or operation were dismissed we don't care about 
> result */
>          g_variant_unref(result);
>  
> -    prompt_quit_loop(args->loop);
> +    prompt_quit_loop(args->env);
>  }
>  
>  /*
> @@ -467,6 +487,83 @@ static bool is_prompt_required(const char *prompt_path)
>  }
>  
>  /*
> + * Sets the timeout dialog to be displayed after PROMPT_TIMEOUT_SECONDS.
> + *
> + * @param env Crate holding necessary values.
> + */
> +static void prompt_timeout_start(struct secrets_loop_env *env);
> +
> +/*
> + * A response callback which stops main loop execution or starts a new 
> timeout.
> + *
> + * The main loop is stopped if user replied with "YES"; otherwise a new 
> timeout
> + * is started.
> + */
> +static void timeout_dialog_response_cb(GtkDialog *dialog, gint response_id, 
> gpointer user_data)
> +{
> +    struct secrets_loop_env *env = (struct secrets_loop_env *)user_data;
> +
> +    gtk_widget_hide(env->timeout_dialog);
> +
> +    /* YES means 'Yes I want to stop wainting for Secret Service' */
> +    /* for other responses we have to start a new timeout */
> +    if (GTK_RESPONSE_YES == response_id)
> +        prompt_quit_loop(env);
> +    else
> +        prompt_timeout_start(env);
> +}
> +
> +/*
> + * Shows the timeout dialog which should allow user to break infinite 
> wainting
> + * for Completed signal emitted by the Secret Service
> + *
> + * @param user_data Should hold an pointer to struct secrets_loop_env
> + */
> +static gboolean prompt_timeout_cb(gpointer user_data)
> +{
> +    VERB3 log("A timeout was reached while waiting for the DBus Secret 
> Service to get prompt result.");
> +    struct secrets_loop_env *env = (struct secrets_loop_env *)user_data;
> +
> +    if (env->timeout_dialog == NULL)
> +    {
> +        GtkWidget *dialog = gtk_message_dialog_new(/*parent widget*/NULL,
> +                                                   GTK_DIALOG_MODAL,
> +                                                   GTK_MESSAGE_WARNING,
> +                                                   GTK_BUTTONS_YES_NO,
> +                _("A timeout was reached while waiting for a prompt result 
> from the DBus Secret Service."));
> +
> +        gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
> +                _("Do you want to stop waiting and continue in reporting 
> without properly loaded configuration?"));
> +
> +        g_signal_connect(dialog, "response", 
> G_CALLBACK(timeout_dialog_response_cb), user_data);
> +
> +        env->timeout_dialog = dialog;
> +    }
> +
> +    gtk_widget_show_all(env->timeout_dialog);
> +
> +    return FALSE; /* remove this source */
> +}
> +
> +/*
> + * Sets the timeout dialog to be displayed after PROMPT_TIMEOUT_SECONDS.
> + *
> + * @param env Crate holding necessary values.
> + */
> +static void prompt_timeout_start(struct secrets_loop_env *env)
> +{
> +    GSource *timeout_source= 
> g_timeout_source_new_seconds(PROMPT_TIMEOUT_SECONDS);
> +
> +    g_source_set_callback(timeout_source, prompt_timeout_cb, /*callback 
> arg*/env, /*arg destroyer*/NULL);
> +    g_source_attach(timeout_source, env->gcontext);
> +
> +    /* remove local reference, the source will be destroyed by the 
> GMainContext
> +     * over taken from glib2/gmain.c: g_timeout_add_full()
> +     */
> +    g_source_unref(timeout_source);
> +}
> +
> +/*
>   * Perform a prompt
>   *
>   * @param prompt_path An object path pointing to a prompt
> @@ -496,12 +593,16 @@ static GVariant *secrets_prompt(const char *prompt_path,
>      /* We have to use the thread default main context because a dbus signal 
> callback */
>      /* will be invoked in the thread default main loop */
>      GMainContext *context = g_main_context_get_thread_default();
> -    GMainLoop *loop = g_main_loop_new(context, FALSE);
> +    struct secrets_loop_env env = {
> +        .gcontext=context,
> +        .gloop=g_main_loop_new(context, FALSE),
> +        .timeout_dialog=NULL,
> +    };
>  
>      struct prompt_call_back_args args = {
>          .result=NULL,
>          .dismissed=FALSE,
> -        .loop=loop
> +        .env=&env
>      };
>  
>      /* g_dbus_connection_signal_subscribe() doesn't report any error */
> @@ -517,22 +618,25 @@ static GVariant *secrets_prompt(const char *prompt_path,
>      /* Idle source simply performs a prompt after the loop is stared. */
>      struct prompt_source *const prompt_source =
>          (struct prompt_source*)g_source_new(&idle_funcs, 
> sizeof(*prompt_source));
> -
>      prompt_source->prompt_proxy = prompt_proxy;
> +    prompt_source->env = &env;
>  
>      g_source_attach((GSource*)prompt_source, context);
>  
> -    /* the loop is exited when the Completed signal is received */
>      /* the loop may sucks in infinite loop if the signal is never received */
> -    /* TODO : if timeout is required use g_timeout_source_new() and 
> g_source_attach() */
> -    g_main_loop_run(loop);
> +    /* thus in order to prevent it we use this timeout */
> +    prompt_timeout_start(&env);
> +
> +    /* the loop is exited when the Completed signal is received */
> +    g_main_loop_run(env.gloop);
>  
>      /* destroy prompt source */
>      g_object_unref(prompt_proxy);
>      g_source_destroy((GSource*)prompt_source);
> +    g_source_unref((GSource*)prompt_source);
>  
>      g_dbus_connection_signal_unsubscribe(g_connection, signal_ret);
> -    g_main_loop_unref(loop);
> +    g_main_loop_unref(env.gloop);
>  
>      *dismissed = args.dismissed;
>      return args.result;
> -- 
> 1.8.1.2
> 

Reply via email to