[totem] chapters: Refactor async chapters loading



commit da0961f0f5d6221a13e9201436d84c423c811c87
Author: Bastien Nocera <hadess hadess net>
Date:   Wed Mar 6 13:31:48 2013 +0100

    chapters: Refactor async chapters loading
    
    Using GIO-style async functions which can be properly cancelled.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=692731

 src/plugins/chapters/totem-chapters.c    |   86 ++++++++++--------------
 src/plugins/chapters/totem-cmml-parser.c |  105 ++++++++++++++++++------------
 src/plugins/chapters/totem-cmml-parser.h |    9 ++-
 3 files changed, 106 insertions(+), 94 deletions(-)
---
diff --git a/src/plugins/chapters/totem-chapters.c b/src/plugins/chapters/totem-chapters.c
index dfffc89..dec42c7 100644
--- a/src/plugins/chapters/totem-chapters.c
+++ b/src/plugins/chapters/totem-chapters.c
@@ -98,7 +98,7 @@ enum {
 };
 
 static void totem_file_opened_async_cb (TotemObject *totem, const gchar *uri, TotemChaptersPlugin *plugin);
-static void totem_file_opened_result_cb (gpointer data, gpointer user_data);
+static void totem_file_opened_result_cb (GObject *source_object, GAsyncResult *res, gpointer user_data);
 static void totem_file_closed_cb (TotemObject *totem, TotemChaptersPlugin *plugin);
 static void add_chapter_to_the_list (gpointer data, gpointer user_data);
 static void add_chapter_to_the_list_new (TotemChaptersPlugin *plugin, const gchar *title, gint64 time);
@@ -303,48 +303,47 @@ check_available_time (TotemChaptersPlugin *plugin,
 }
 
 static void
-totem_file_opened_result_cb (gpointer  data,
-                            gpointer   user_data)
+totem_file_opened_result_cb (GObject      *source_object,
+                            GAsyncResult *res,
+                            gpointer      user_data)
 {
-       TotemCmmlAsyncData      *adata;
-       TotemChaptersPlugin     *plugin;
-
-       g_return_if_fail (data != NULL);
-
-       adata = (TotemCmmlAsyncData *) data;
-       plugin = TOTEM_CHAPTERS_PLUGIN (adata->user_data);
+       TotemChaptersPlugin *plugin = TOTEM_CHAPTERS_PLUGIN (user_data);
+       GError *error = NULL;
+       GList *list;
+       gboolean from_dialog;
+       gboolean is_exists;
+
+       is_exists = TRUE;
+       list = totem_cmml_read_file_finish (G_FILE (source_object), res, &error);
+
+       if (list == NULL) {
+               /* Ignore errors if file is not present */
+               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) &&
+                   !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) {
+                       totem_action_error (plugin->priv->totem, _("Error while reading file with chapters"),
+                                           error->message);
+                       g_error_free (error);
 
-       if (G_UNLIKELY (!adata->successful)) {
-               if (G_UNLIKELY (g_cancellable_is_cancelled (adata->cancellable))) {
-                       /* if operation was cancelled due to plugin deactivation only clean up */
-                       g_object_unref (adata->cancellable);
-                       g_free (adata->file);
-                       g_free (adata->error);
-                       g_list_foreach (adata->list, (GFunc) totem_cmml_clip_free, NULL);
-                       g_list_free (adata->list);
-                       g_free (adata);
+                       set_no_data_visible (TRUE, TRUE, plugin);
                        return;
-               } else
-                       totem_action_error (plugin->priv->totem, _("Error while reading file with chapters"),
-                                           adata->error);
+               }
+               g_error_free (error);
+               is_exists = FALSE;
        }
 
-       if (adata->is_exists && adata->from_dialog) {
+       from_dialog = GPOINTER_TO_INT(g_object_get_data (source_object, "from-dialog"));
+
+       if (from_dialog) {
                g_free (plugin->priv->cmml_mrl);
-               plugin->priv->cmml_mrl = g_strdup (adata->file);
+               plugin->priv->cmml_mrl = g_file_get_uri (G_FILE (source_object));
        }
 
-       g_list_foreach (adata->list, (GFunc) add_chapter_to_the_list, plugin);
-       g_list_foreach (adata->list, (GFunc) totem_cmml_clip_free, NULL);
-       g_list_free (adata->list);
+       g_list_foreach (list, (GFunc) add_chapter_to_the_list, plugin);
+       g_list_foreach (list, (GFunc) totem_cmml_clip_free, NULL);
+       g_list_free (list);
 
        /* do not show tree if read operation failed */
-       set_no_data_visible (!adata->successful || !adata->is_exists, TRUE, plugin);
-
-       g_object_unref (adata->cancellable);
-       g_free (adata->file);
-       g_free (adata->error);
-       g_free (adata);
+       set_no_data_visible (!is_exists, TRUE, plugin);
 }
 
 static void
@@ -607,7 +606,7 @@ load_chapters_from_file (const gchar                *uri,
                         gboolean               from_dialog,
                         TotemChaptersPlugin    *plugin)
 {
-       TotemCmmlAsyncData      *data;
+       GFile *file;
 
        g_return_if_fail (TOTEM_IS_CHAPTERS_PLUGIN (plugin));
 
@@ -616,27 +615,14 @@ load_chapters_from_file (const gchar              *uri,
                g_object_unref (plugin->priv->cancellable[0]);
        }
 
-       data = g_new0 (TotemCmmlAsyncData, 1);
-       /* do not forget to save this pointer in the result function */
-       data->file = g_strdup (uri);
-       data->final = totem_file_opened_result_cb;
-       data->user_data = (gpointer) plugin;
-       if (from_dialog)
-               data->from_dialog = TRUE;
+       file = g_file_new_for_uri (uri);
+       g_object_set_data (G_OBJECT (file), "from-dialog", GINT_TO_POINTER (from_dialog));
        /* cancellable object shouldn't be finalized during result func */
        plugin->priv->cancellable[0] = g_cancellable_new ();
        g_object_add_weak_pointer (G_OBJECT (plugin->priv->cancellable[0]),
                                   (gpointer *) &(plugin->priv->cancellable[0]));
-       data->cancellable = plugin->priv->cancellable[0];
-
-       if (G_UNLIKELY (totem_cmml_read_file_async (data) < 0)) {
-               g_warning ("chapters: wrong parameters for reading CMML file, may be a bug");
-
-               set_no_data_visible (TRUE, TRUE, plugin);
 
-               g_object_unref (plugin->priv->cancellable[0]);
-               g_free (data);
-       }
+       totem_cmml_read_file (file, plugin->priv->cancellable[0], totem_file_opened_result_cb, plugin);
 }
 
 static void
diff --git a/src/plugins/chapters/totem-cmml-parser.c b/src/plugins/chapters/totem-cmml-parser.c
index e0ca7b2..39dc19d 100644
--- a/src/plugins/chapters/totem-cmml-parser.c
+++ b/src/plugins/chapters/totem-cmml-parser.c
@@ -607,55 +607,45 @@ totem_cmml_clip_copy (TotemCmmlClip *clip)
 }
 
 static void
-totem_cmml_read_file_result (GObject           *source_object,
-                            GAsyncResult       *result,
-                            gpointer           user_data)
+totem_cmml_read_file_cb (GObject       *source_object,
+                        GAsyncResult   *result,
+                        gpointer        user_data)
 {
        GError                  *error = NULL;
        xmlTextReaderPtr        reader;
        TotemCmmlContext        *context;
-       TotemCmmlAsyncData      *data;
        gint                    ret;
        gchar                   *contents;
        gsize                   length;
+       gboolean                load_ret;
 
+       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+       GList *list = NULL;
 
-       data = (TotemCmmlAsyncData *) user_data;
-       data->is_exists = TRUE;
-
-       g_file_load_contents_finish (G_FILE (source_object), result, &contents, &length, NULL, &error);
+       load_ret = g_file_load_contents_finish (G_FILE (source_object), result, &contents, &length, NULL, 
&error);
        g_object_unref (source_object);
 
-       if (G_UNLIKELY (error != NULL)) {
-               if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) ||
-                   g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) {
-                       /* it's ok if file doesn't exist */
-                       data->successful = TRUE;
-                       data->is_exists = FALSE;
-               } else {
-                       data->successful = FALSE;
-                       data->error = g_strdup (error->message);
-                       g_warning ("chapters: failed to load CMML file %s: %s", data->file, error->message);
-               }
+       if (!load_ret) {
+               g_simple_async_result_set_from_error (simple, error);
+               g_simple_async_result_complete_in_idle (simple);
+               g_object_unref (simple);
                g_error_free (error);
-               (data->final) (data, NULL);
                return;
        }
 
        /* parse in-memory xml data */
        reader = xmlReaderForMemory (contents, length, "", NULL, 0);
        if (G_UNLIKELY (reader == NULL)) {
-               g_warning ("chapters: failed to parse CMML file %s", data->file);
-               g_free (contents);
-               data->successful = FALSE;
-               data->error = g_strdup (_("Failed to parse CMML file"));
-               (data->final) (data, NULL);
+               g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
+                                                "Failed to parse CMML file");
+               g_simple_async_result_complete_in_idle (simple);
+               g_object_unref (simple);
                return;
        }
 
        context = totem_cmml_context_new ();
        context->reader = reader;
-       totem_cmml_context_set_callback (context, totem_cmml_read_clip_cb, &(data->list));
+       totem_cmml_context_set_callback (context, totem_cmml_read_clip_cb, &list);
 
        ret = xmlTextReaderRead (reader);
        while (ret == 1) {
@@ -669,32 +659,61 @@ totem_cmml_read_file_result (GObject              *source_object,
        totem_cmml_context_free (context);
 
        /* sort clips by time growth */
-       data->list = g_list_sort (data->list, (GCompareFunc) totem_cmml_compare_clips);
-       data->successful = TRUE;
-       (data->final) (data, NULL);
+       list = g_list_sort (list, (GCompareFunc) totem_cmml_compare_clips);
+
+       g_simple_async_result_set_op_res_gpointer (simple, list, NULL);
+       g_simple_async_result_complete_in_idle (simple);
+       g_object_unref (simple);
 }
 
 /**
- * totem_cmml_read_file_async:
- * @data: #TotemCmmlAsyncData structure with info needed
+ * totem_cmml_read_file:
+ * @file: a #GFile representing the file to read
+ * @cancellable: optional #GCancellable object, %NULL to ignore
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied.
+ * @user_data: the data to pass to callback function.
  *
- * Reads CMML file and parse it for clips in async way.
+ * Reads and parses a CMML file asynchronously.
+ **/
+void
+totem_cmml_read_file (GFile               *file,
+                     GCancellable        *cancellable,
+                     GAsyncReadyCallback  callback,
+                     gpointer             user_data)
+{
+       GSimpleAsyncResult *simple;
+
+       simple = g_simple_async_result_new (G_OBJECT (file),
+                                           callback,
+                                           user_data,
+                                           totem_cmml_read_file);
+
+       g_file_load_contents_async (file, cancellable, totem_cmml_read_file_cb, simple);
+}
+
+/**
+ * totem_ccml_read_file_finish:
+ * @file: a #GFile representing the file to read
+ * @res: a #GAsyncResult
+ * @error: a #GError, or %NULL
  *
- * Returns: 0 if no errors occurred while starting async reading, -1 otherwise.
+ * Returns a list of parsed chapters or %NULL on error
  **/
-gint
-totem_cmml_read_file_async (TotemCmmlAsyncData *data)
+GList *
+totem_cmml_read_file_finish (GFile        *file,
+                            GAsyncResult *res,
+                            GError      **error)
 {
-       GFile   *gio_file;
+       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
 
-       g_return_val_if_fail (data != NULL, -1);
-       g_return_val_if_fail (data->file != NULL, -1);
-       g_return_val_if_fail (data->list == NULL, -1);
-       g_return_val_if_fail (data->final != NULL, -1);
+       g_return_val_if_fail (G_IS_FILE (file), NULL);
 
-       gio_file = g_file_new_for_uri (data->file);
-       g_file_load_contents_async (gio_file, data->cancellable, totem_cmml_read_file_result, data);
-       return 0;
+       g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == totem_cmml_read_file);
+
+       if (g_simple_async_result_propagate_error (simple, error))
+               return NULL;
+
+       return g_simple_async_result_get_op_res_gpointer (simple);
 }
 
 static void
diff --git a/src/plugins/chapters/totem-cmml-parser.h b/src/plugins/chapters/totem-cmml-parser.h
index 649a29c..f5db15f 100644
--- a/src/plugins/chapters/totem-cmml-parser.h
+++ b/src/plugins/chapters/totem-cmml-parser.h
@@ -76,7 +76,14 @@ gchar *      totem_cmml_convert_msecs_to_str (gint64 time_msecs);
 TotemCmmlClip * totem_cmml_clip_new (const gchar *title, const gchar *desc, gint64 start, GdkPixbuf *pixbuf);
 void totem_cmml_clip_free (TotemCmmlClip *clip);
 TotemCmmlClip * totem_cmml_clip_copy (TotemCmmlClip *clip);
-gint totem_cmml_read_file_async (TotemCmmlAsyncData *data);
+
+void totem_cmml_read_file (GFile               *file,
+                          GCancellable        *cancellable,
+                          GAsyncReadyCallback  callback,
+                          gpointer             user_data);
+GList *totem_cmml_read_file_finish (GFile        *file,
+                                   GAsyncResult *res,
+                                   GError      **error);
 gint totem_cmml_write_file_async (TotemCmmlAsyncData *data);
 
 #endif /* TOTEM_CMML_PARSER_H_ */


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