[gnome-documents] pdf-loader: rewrite the PDF loader with an async/cancellable API



commit d2b2c4013d903749cde2b0b4df2dcf845d7fed46
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Tue Jul 26 19:05:01 2011 +0200

    pdf-loader: rewrite the PDF loader with an async/cancellable API
    
    This allows more flexibility and reporting load errors to the calling
    application.

 src/lib/gd-pdf-loader.c |  508 ++++++++++++++++++++++++++---------------------
 src/lib/gd-pdf-loader.h |   14 +-
 src/mainWindow.js       |   32 ++--
 3 files changed, 313 insertions(+), 241 deletions(-)
---
diff --git a/src/lib/gd-pdf-loader.c b/src/lib/gd-pdf-loader.c
index 342ebb8..afdbd77 100644
--- a/src/lib/gd-pdf-loader.c
+++ b/src/lib/gd-pdf-loader.c
@@ -30,72 +30,189 @@
 #include <evince-view.h>
 
 /* TODO:
- * - error forwarding to the caller, don't die silently
- * - possibly better to turn the loader into an explicit
- *   _load() API passing a GCancellable, so we can control it
- *   from the application too
  * - investigate the GDataDocumentsType bug
  */
 
 G_DEFINE_TYPE (GdPdfLoader, gd_pdf_loader, G_TYPE_OBJECT);
 
 enum {
-  PROP_DOCUMENT = 1,
-  PROP_URI,
-  PROP_SOURCE_ID
+  PROP_SOURCE_ID = 1,
 };
 
-struct _GdPdfLoaderPrivate {
+typedef struct {
+  GSimpleAsyncResult *result;
+  GCancellable *cancellable;
+
   EvDocument *document;
   gchar *uri;
   gchar *pdf_path;
-  gchar *source_id;
-
   GPid unoconv_pid;
   GDataDownloadStream *stream;
+} PdfLoadJob;
+
+struct _GdPdfLoaderPrivate {
+  gchar *source_id;
 };
 
+/* --------------------------- utils -------------------------------- */
+
+#define GOA_DOCS_TRACKER_PREFIX "goa:documents:"
+
+static gchar *
+strip_tracker_prefix (const gchar *source_id)
+{
+  if (g_str_has_prefix (source_id, GOA_DOCS_TRACKER_PREFIX))
+    return g_strdup (source_id + strlen (GOA_DOCS_TRACKER_PREFIX));
+
+  return NULL;
+}
+
+static gchar **
+query_supported_document_types (void)
+{
+  GList *infos, *l;
+  gchar **retval = NULL;
+  GPtrArray *array;
+  EvTypeInfo *info;
+  gint idx;
+
+  infos = ev_backends_manager_get_all_types_info ();
+
+  if (infos == NULL)
+    return NULL;
+
+  array = g_ptr_array_new ();
+
+  for (l = infos; l != NULL; l = l->next) {
+    info = l->data;
+
+    for (idx = 0; info->mime_types[idx] != NULL; idx++)
+      g_ptr_array_add (array, g_strdup (info->mime_types[idx]));
+  }
+
+  g_ptr_array_add (array, NULL);
+  retval = (gchar **) g_ptr_array_free (array, FALSE);
+
+  return retval;
+}
+
+static gboolean
+content_type_is_native (const gchar *content_type)
+{
+  gchar **native_types;
+  gint idx;
+  gboolean found = FALSE;
+
+  native_types = query_supported_document_types ();
+
+  for (idx = 0; native_types[idx] != NULL; idx++) {
+    found = g_content_type_is_a (content_type, native_types[idx]);
+    if (found)
+      break;
+  }
+
+  g_strfreev (native_types);
+
+  return found;
+}
+
+/* ----------------------- load job ------------------------------ */
+
 static void
-load_job_done (EvJob *job,
-               gpointer user_data)
+pdf_load_job_free (PdfLoadJob *job)
 {
-  GdPdfLoader *self = user_data;
+  g_clear_object (&job->document);
+  g_clear_object (&job->result);
+  g_clear_object (&job->cancellable);
+  g_clear_object (&job->stream);
 
-  if (ev_job_is_failed (job)) {
-    g_print ("Failed to load document: %s", job->error->message);
-    g_object_unref (job);
+  g_free (job->uri);
 
-    return;
+  if (job->pdf_path != NULL) {
+    g_unlink (job->pdf_path);
+    g_free (job->pdf_path);
   }
 
-  self->priv->document = g_object_ref (job->document);
-  g_object_unref (job);
+  if (job->unoconv_pid != -1) {
+    kill (job->unoconv_pid, SIGKILL);
+    job->unoconv_pid = -1;
+  }
 
-  g_object_notify (G_OBJECT (self), "document");
+  g_slice_free (PdfLoadJob, job);
+}
+
+static PdfLoadJob *
+pdf_load_job_new (GSimpleAsyncResult *result,
+                  const gchar *uri,
+                  GCancellable *cancellable)
+{
+  PdfLoadJob *retval;
+
+  retval = g_slice_new0 (PdfLoadJob);
+  retval->result = g_object_ref (result);
+  retval->cancellable = g_object_ref (cancellable);
+  retval->uri = g_strdup (uri);
+  retval->unoconv_pid = -1;
+
+  return retval;
 }
 
 static void
-load_pdf (GdPdfLoader *self,
-          const gchar *uri)
+pdf_load_job_complete_error (PdfLoadJob *job,
+                             GError *error)
 {
-  EvJob *job;
+    g_simple_async_result_take_error (job->result, error);
+    g_simple_async_result_complete_in_idle (job->result);
+
+    pdf_load_job_free (job);
+}
 
-  job = ev_job_load_new (uri);
-  g_signal_connect (job, "finished",
-                    G_CALLBACK (load_job_done), self);
+static void
+pdf_load_job_complete_success (PdfLoadJob *job)
+{
+  g_simple_async_result_set_op_res_gpointer (job->result, g_object_ref (job->document), NULL);
+  g_simple_async_result_complete_in_idle (job->result);
 
-  ev_job_scheduler_push_job (job, EV_JOB_PRIORITY_NONE);
+  pdf_load_job_free (job);
 }
 
-#define GOA_DOCS_TRACKER_PREFIX "goa:documents:"
+static void
+ev_load_job_done (EvJob *ev_job,
+                  gpointer user_data)
+{
+  PdfLoadJob *job = user_data;
 
-static gchar *
-strip_tracker_prefix (const gchar *source_id)
+  if (ev_job_is_failed (ev_job)) {
+    pdf_load_job_complete_error (job, g_error_copy (ev_job->error));
+    return;
+  }
+
+  job->document = g_object_ref (ev_job->document);
+  g_object_unref (ev_job);
+
+  pdf_load_job_complete_success (job);
+}
+
+static void
+pdf_load_job_from_pdf (PdfLoadJob *job)
 {
-  if (g_str_has_prefix (source_id, GOA_DOCS_TRACKER_PREFIX))
-    return g_strdup (source_id + strlen (GOA_DOCS_TRACKER_PREFIX));
+  EvJob *ev_job;
+  gchar *uri = NULL;
+  GFile *file;
 
-  return NULL;
+  if (job->pdf_path != NULL) {
+    file = g_file_new_for_path (job->pdf_path);
+    uri = g_file_get_uri (file);
+    g_object_unref (file);
+  }
+
+  ev_job = ev_job_load_new ((uri != NULL) ? (uri) : (job->uri));
+  g_signal_connect (ev_job, "finished",
+                    G_CALLBACK (ev_load_job_done), job);
+
+  ev_job_scheduler_push_job (ev_job, EV_JOB_PRIORITY_NONE);
+
+  g_free (uri);
 }
 
 static void
@@ -103,25 +220,19 @@ os_splice_ready_cb (GObject *source,
                     GAsyncResult *res,
                     gpointer user_data)
 {
-  GdPdfLoader *self = user_data;
   GError *error = NULL;
   GFile *file;
   gchar *uri;
+  PdfLoadJob *job = user_data;
 
   g_output_stream_splice_finish (G_OUTPUT_STREAM (source), res, &error);
 
   if (error != NULL) {
-    g_warning ("Unable to download the PDF file from google: %s\n", error->message);
-    g_error_free (error);
+    pdf_load_job_complete_error (job, error);
     return;
   }
 
-  file = g_file_new_for_path (self->priv->pdf_path);
-  uri = g_file_get_uri (file);
-  load_pdf (self, uri);
-
-  g_object_unref (file);
-  g_free (uri);
+  pdf_load_job_from_pdf (job);
 }
 
 static void
@@ -131,23 +242,22 @@ file_replace_ready_cb (GObject *source,
 {
   GFileOutputStream *os;
   GError *error = NULL;
-  GdPdfLoader *self = user_data;
+  PdfLoadJob *job = user_data;
 
   os = g_file_replace_finish (G_FILE (source), res, &error);
 
   if (error != NULL) {
-    g_warning ("Unable to open the temp file for writing: %s\n", error->message);
-    g_error_free (error);
+    pdf_load_job_complete_error (job, error);
     return;
   }
 
   g_output_stream_splice_async (G_OUTPUT_STREAM (os),
-                                G_INPUT_STREAM (self->priv->stream),
+                                G_INPUT_STREAM (job->stream),
                                 G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
                                 G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
                                 G_PRIORITY_DEFAULT,
-                                NULL,
-                                os_splice_ready_cb, self);
+                                job->cancellable,
+                                os_splice_ready_cb, job);
 
   g_object_unref (os);
 }
@@ -158,36 +268,34 @@ single_entry_ready_cb (GObject *source,
                        gpointer user_data)
 {
   GDataEntry *entry;
-  GdPdfLoader *self = user_data;
   GDataDownloadStream *stream;
   GError *error = NULL;
   gchar *tmp_name;
   gchar *tmp_path, *pdf_path;
   GFile *pdf_file;
+  PdfLoadJob *job = user_data;
 
   entry = gdata_service_query_single_entry_finish (GDATA_SERVICE (source), res, &error);
 
   if (error != NULL) {
-    g_warning ("Unable to query the requested entry from GData: %s\n", error->message);
-    g_error_free (error);
+    pdf_load_job_complete_error (job, error);
     return;
   }
 
   stream = gdata_documents_document_download (GDATA_DOCUMENTS_DOCUMENT (entry),
                                               GDATA_DOCUMENTS_SERVICE (source),
-                                              "pdf", NULL, &error);
+                                              "pdf", job->cancellable, &error);
 
   if (error != NULL) {
-    g_warning ("Unable to get the download stream for the requested document from GData: %s\n", error->message);
-    g_error_free (error);
+    pdf_load_job_complete_error (job, error);
     return;
   }
 
-  self->priv->stream = stream;
+  job->stream = stream;
 
   tmp_name = g_strdup_printf ("gnome-documents-%d.pdf", getpid ());
   tmp_path = g_build_filename (g_get_user_cache_dir (), "gnome-documents", NULL);
-  self->priv->pdf_path = pdf_path =
+  job->pdf_path = pdf_path =
     g_build_filename (tmp_path, tmp_name, NULL);
   g_mkdir_with_parents (tmp_path, 0700);
 
@@ -195,8 +303,8 @@ single_entry_ready_cb (GObject *source,
   g_file_replace_async (pdf_file, NULL, FALSE,
                         G_FILE_CREATE_PRIVATE,
                         G_PRIORITY_DEFAULT,
-                        NULL, file_replace_ready_cb,
-                        self);
+                        job->cancellable, file_replace_ready_cb,
+                        job);
 
   g_free (tmp_name);
   g_free (tmp_path);
@@ -205,8 +313,8 @@ single_entry_ready_cb (GObject *source,
 }
 
 static void
-load_from_google_documents_with_object (GdPdfLoader *self,
-                                        GoaObject *object)
+pdf_load_job_from_google_documents_with_object (PdfLoadJob *job,
+                                                GoaObject *object)
 {
   EGDataGoaAuthorizer *authorizer;
   GDataDocumentsService *service;
@@ -222,9 +330,9 @@ load_from_google_documents_with_object (GdPdfLoader *self,
    */
   gdata_service_query_single_entry_async (GDATA_SERVICE (service),
                                           gdata_documents_service_get_primary_authorization_domain (),
-                                          self->priv->uri,
+                                          job->uri,
                                           NULL, GDATA_TYPE_DOCUMENTS_TEXT,
-                                          NULL, single_entry_ready_cb, self);
+                                          job->cancellable, single_entry_ready_cb, job);
 
   g_object_unref (service);
   g_object_unref (authorizer);
@@ -241,22 +349,26 @@ client_ready_cb (GObject *source,
   GError *error = NULL;
   GList *accounts, *l;
   gchar *stripped_id;
-  GdPdfLoader *self = user_data;
+  PdfLoadJob *job = user_data;
+  GdPdfLoader *self;
 
   client = goa_client_new_finish (res, &error);
 
   if (error != NULL) {
-    g_warning ("Error while getting the GOA client: %s",
-               error->message);
-    g_error_free (error);
-
+    pdf_load_job_complete_error (job, error);
     return;
   }
 
+  self = GD_PDF_LOADER (g_async_result_get_source_object (G_ASYNC_RESULT (job->result)));
   stripped_id = strip_tracker_prefix (self->priv->source_id);
+  g_object_unref (self);
 
   if (stripped_id == NULL) {
-    g_warning ("Wrong source ID; passed in a google URL, but the source ID is not coming from GOA");
+    pdf_load_job_complete_error 
+      (job,
+       g_error_new_literal (G_IO_ERROR, 0,
+                            "Wrong source ID; passed in a google URL, "
+                            "but the source ID is not coming from GOA"));
     return;
   }
 
@@ -277,8 +389,14 @@ client_ready_cb (GObject *source,
     }
   }
 
-  if (target != NULL)
-    load_from_google_documents_with_object (self, target);
+  if (target != NULL) {
+    pdf_load_job_from_google_documents_with_object (job, target);
+  } else {
+    pdf_load_job_complete_error 
+      (job,
+       g_error_new_literal (G_IO_ERROR, 0,
+                            "Cannot find the specified GOA account"));
+  }
 
   g_free (stripped_id);
   g_list_free_full (accounts, g_object_unref);
@@ -286,9 +404,9 @@ client_ready_cb (GObject *source,
 }
 
 static void
-load_from_google_documents (GdPdfLoader *self)
+pdf_load_job_from_google_documents (PdfLoadJob *job)
 {
-  goa_client_new (NULL, client_ready_cb, self);
+  goa_client_new (job->cancellable, client_ready_cb, job);
 }
 
 static void
@@ -296,27 +414,28 @@ unoconv_child_watch_cb (GPid pid,
                         gint status,
                         gpointer user_data)
 {
-  GdPdfLoader *self = user_data;
-  GFile *file;
-  gchar *uri;
+  PdfLoadJob *job = user_data;
 
   g_spawn_close_pid (pid);
-  self->priv->unoconv_pid = -1;
+  job->unoconv_pid = -1;
 
-  file = g_file_new_for_path (self->priv->pdf_path);
-  uri = g_file_get_uri (file);
-  load_pdf (self, uri);
+  if (g_cancellable_is_cancelled (job->cancellable)) {
+    pdf_load_job_complete_error 
+      (job, 
+       g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED,
+                            "Operation cancelled"));
 
-  g_object_unref (file);
-  g_free (uri);
+    return;
+  }
+
+  pdf_load_job_from_pdf (job);
 }
 
 static void
-load_openoffice (GdPdfLoader *self)
+pdf_load_job_from_openoffice (PdfLoadJob *job)
 {
   gchar *doc_path, *pdf_path, *tmp_name, *tmp_path;
   GFile *file;
-  gboolean res;
   gchar *cmd;
 
   gint argc;
@@ -324,100 +443,50 @@ load_openoffice (GdPdfLoader *self)
   gchar **argv = NULL;
   GError *error = NULL;
 
-  file = g_file_new_for_uri (self->priv->uri);
+  /* build the temporary PDF file path */
+  file = g_file_new_for_uri (job->uri);
   doc_path = g_file_get_path (file);
   g_object_unref (file);
 
   tmp_name = g_strdup_printf ("gnome-documents-%d.pdf", getpid ());
   tmp_path = g_build_filename (g_get_user_cache_dir (), "gnome-documents", NULL);
-  self->priv->pdf_path = pdf_path =
+  job->pdf_path = pdf_path =
     g_build_filename (tmp_path, tmp_name, NULL);
   g_mkdir_with_parents (tmp_path, 0700);
 
+  /* call into the unoconv executable to convert the OpenOffice document
+   * to the temporary PDF.
+   */
   cmd = g_strdup_printf ("unoconv -f pdf -o %s %s", pdf_path, doc_path);
 
   g_free (doc_path);
   g_free (tmp_name);
   g_free (tmp_path);
 
-  res = g_shell_parse_argv (cmd, &argc, &argv, &error);
+  g_shell_parse_argv (cmd, &argc, &argv, &error);
   g_free (cmd);
 
-  if (!res) {
-    g_warning ("Error while parsing the unoconv command line: %s",
-               error->message);
-    g_error_free (error);
-
+  if (error != NULL) {
+    pdf_load_job_complete_error (job, error);
     return;
   }
 
-  res = g_spawn_async (NULL, argv, NULL,
-                       G_SPAWN_DO_NOT_REAP_CHILD |
-                       G_SPAWN_SEARCH_PATH,
-                       NULL, NULL,
-                       &pid, &error);
+  g_spawn_async (NULL, argv, NULL,
+                 G_SPAWN_DO_NOT_REAP_CHILD |
+                 G_SPAWN_SEARCH_PATH,
+                 NULL, NULL,
+                 &pid, &error);
 
   g_strfreev (argv);
 
-  if (!res) {
-    g_warning ("Error while spawning unoconv: %s",
-               error->message);
-    g_error_free (error);
-
+  if (error != NULL) {
+    pdf_load_job_complete_error (job, error);
     return;
   }
 
-  g_child_watch_add (pid, unoconv_child_watch_cb, self);
-  self->priv->unoconv_pid = pid;
-}
-
-static gchar **
-query_supported_document_types (void)
-{
-  GList *infos, *l;
-  gchar **retval = NULL;
-  GPtrArray *array;
-  EvTypeInfo *info;
-  gint idx;
-
-  infos = ev_backends_manager_get_all_types_info ();
-
-  if (infos == NULL)
-    return NULL;
-
-  array = g_ptr_array_new ();
-
-  for (l = infos; l != NULL; l = l->next) {
-    info = l->data;
-
-    for (idx = 0; info->mime_types[idx] != NULL; idx++)
-      g_ptr_array_add (array, g_strdup (info->mime_types[idx]));
-  }
-
-  g_ptr_array_add (array, NULL);
-  retval = (gchar **) g_ptr_array_free (array, FALSE);
-
-  return retval;
-}
-
-static gboolean
-content_type_is_native (const gchar *content_type)
-{
-  gchar **native_types;
-  gint idx;
-  gboolean found = FALSE;
-
-  native_types = query_supported_document_types ();
-
-  for (idx = 0; native_types[idx] != NULL; idx++) {
-    found = g_content_type_is_a (content_type, native_types[idx]);
-    if (found)
-      break;
-  }
-
-  g_strfreev (native_types);
-
-  return found;
+  /* now watch when the unoconv child process dies */
+  g_child_watch_add (pid, unoconv_child_watch_cb, job);
+  job->unoconv_pid = pid;
 }
 
 static void
@@ -425,7 +494,7 @@ query_info_ready_cb (GObject *obj,
                      GAsyncResult *res,
                      gpointer user_data)
 {
-  GdPdfLoader *self = user_data;
+  PdfLoadJob *job = user_data;
   GError *error = NULL;
   GFileInfo *info;
   const gchar *content_type;
@@ -434,66 +503,44 @@ query_info_ready_cb (GObject *obj,
                                    res, &error);
 
   if (error != NULL) {
-    g_warning ("Unable to query the mimetype of %s: %s",
-               self->priv->uri, error->message);
-    g_error_free (error);
-
+    pdf_load_job_complete_error (job, error);
     return;
   }
 
   content_type = g_file_info_get_content_type (info);
-  g_object_unref (info);
 
   if (content_type_is_native (content_type))
-    load_pdf (self, self->priv->uri);
+    pdf_load_job_from_pdf (job);
   else
-    load_openoffice (self);
+    pdf_load_job_from_openoffice (job);
+
+  g_object_unref (info);
 }
 
 static void
-start_loading_document (GdPdfLoader *self)
+pdf_load_job_from_regular_file (PdfLoadJob *job)
 {
   GFile *file;
 
-  if (g_str_has_prefix (self->priv->uri, "https://docs.google.com";)) {
-    load_from_google_documents (self);
-    return;
-  }
-
-  file = g_file_new_for_uri (self->priv->uri);
+  file = g_file_new_for_uri (job->uri);
   g_file_query_info_async (file,
                            G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
                            G_FILE_QUERY_INFO_NONE,
                            G_PRIORITY_DEFAULT,
-                           NULL,
+                           job->cancellable,
                            query_info_ready_cb,
-                           self);
+                           job);
 
   g_object_unref (file);
 }
 
 static void
-gd_pdf_loader_set_uri (GdPdfLoader *self,
-                       const gchar *uri)
+pdf_load_job_start (PdfLoadJob *job)
 {
-  g_clear_object (&self->priv->document);
-  g_free (self->priv->uri);
-
-  self->priv->uri = g_strdup (uri);
-  start_loading_document (self);
-}
-
-void
-gd_pdf_loader_cleanup_document (GdPdfLoader *self)
-{
-  if (self->priv->pdf_path) {
-    g_unlink (self->priv->pdf_path);
-    g_free (self->priv->pdf_path);
-  }
-
-  if (self->priv->unoconv_pid != -1) {
-    kill (self->priv->unoconv_pid, SIGKILL);
-    self->priv->unoconv_pid = -1;
+  if (g_str_has_prefix (job->uri, "https://docs.google.com";)) {
+    pdf_load_job_from_google_documents (job);
+  } else {
+    pdf_load_job_from_regular_file (job);
   }
 }
 
@@ -502,11 +549,6 @@ gd_pdf_loader_dispose (GObject *object)
 {
   GdPdfLoader *self = GD_PDF_LOADER (object);
 
-  gd_pdf_loader_cleanup_document (self);
-
-  g_clear_object (&self->priv->document);
-  g_clear_object (&self->priv->stream);
-  g_free (self->priv->uri);
   g_free (self->priv->source_id);
 
   G_OBJECT_CLASS (gd_pdf_loader_parent_class)->dispose (object);
@@ -521,12 +563,6 @@ gd_pdf_loader_get_property (GObject *object,
   GdPdfLoader *self = GD_PDF_LOADER (object);
 
   switch (prop_id) {
-  case PROP_DOCUMENT:
-    g_value_set_object (value, self->priv->document);
-    break;
-  case PROP_URI:
-    g_value_set_string (value, self->priv->uri);
-    break;
   case PROP_SOURCE_ID:
     g_value_set_string (value, self->priv->source_id);
     break;
@@ -545,9 +581,6 @@ gd_pdf_loader_set_property (GObject *object,
   GdPdfLoader *self = GD_PDF_LOADER (object);
 
   switch (prop_id) {
-  case PROP_URI:
-    gd_pdf_loader_set_uri (self, g_value_get_string (value));
-    break;
   case PROP_SOURCE_ID:
     self->priv->source_id = g_value_dup_string (value);
     break;
@@ -569,30 +602,12 @@ gd_pdf_loader_class_init (GdPdfLoaderClass *klass)
 
   g_object_class_install_property
     (oclass,
-     PROP_DOCUMENT,
-     g_param_spec_object ("document",
-                          "Document",
-                          "The loaded document",
-                          EV_TYPE_DOCUMENT,
-                          G_PARAM_READABLE));
-
-  g_object_class_install_property
-    (oclass,
-     PROP_URI,
-     g_param_spec_string ("uri",
-                          "URI",
-                          "The URI to load",
-                          NULL,
-                          G_PARAM_READWRITE));
-
-  g_object_class_install_property
-    (oclass,
      PROP_SOURCE_ID,
      g_param_spec_string ("source-id",
                           "Source ID",
                           "The ID of the source we're loading from",
                           NULL,
-                          G_PARAM_READWRITE));
+                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
 
   g_type_class_add_private (klass, sizeof (GdPdfLoaderPrivate));
 }
@@ -604,13 +619,56 @@ gd_pdf_loader_init (GdPdfLoader *self)
     G_TYPE_INSTANCE_GET_PRIVATE (self,
                                  GD_TYPE_PDF_LOADER,
                                  GdPdfLoaderPrivate);
-  self->priv->unoconv_pid = -1;
 }
 
 GdPdfLoader *
-gd_pdf_loader_new (const gchar *uri)
+gd_pdf_loader_new (const gchar *source_id)
 {
   return g_object_new (GD_TYPE_PDF_LOADER,
-                       "uri", uri,
+                       "source-id", source_id,
                        NULL);
 }
+
+void
+gd_pdf_loader_load_uri_async (GdPdfLoader *self,
+                              const gchar *uri,
+                              GCancellable *cancellable,
+                              GAsyncReadyCallback callback,
+                              gpointer user_data)
+{
+  PdfLoadJob *job;
+  GSimpleAsyncResult *result;
+
+  result = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+                                      gd_pdf_loader_load_uri_async);
+
+  job = pdf_load_job_new (result, uri, cancellable);
+
+  pdf_load_job_start (job);
+
+  g_object_unref (result);
+  g_object_unref (cancellable);
+}
+
+/**
+ * gd_pdf_loader_load_uri_finish:
+ * @self:
+ * @res:
+ * @error: (allow-none) (out):
+ *
+ * Returns: (transfer full):
+ */
+EvDocument *
+gd_pdf_loader_load_uri_finish (GdPdfLoader *self,
+                               GAsyncResult *res,
+                               GError **error)
+{
+  gpointer r;
+  EvDocument *retval;
+
+  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
+    return NULL;
+
+  retval = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
+  return retval;
+}
diff --git a/src/lib/gd-pdf-loader.h b/src/lib/gd-pdf-loader.h
index 3d66fd7..81a4d12 100644
--- a/src/lib/gd-pdf-loader.h
+++ b/src/lib/gd-pdf-loader.h
@@ -24,6 +24,8 @@
 #define __GD_PDF_LOADER_H__
 
 #include <glib-object.h>
+#include <gio/gio.h>
+#include <evince-document.h>
 
 G_BEGIN_DECLS
 
@@ -52,8 +54,16 @@ struct _GdPdfLoaderClass
 
 GType    gd_pdf_loader_get_type     (void) G_GNUC_CONST;
 
-GdPdfLoader *gd_pdf_loader_new (const gchar *uri);
-void gd_pdf_loader_cleanup_document (GdPdfLoader *self);
+GdPdfLoader *gd_pdf_loader_new (const gchar *source_id);
+
+void gd_pdf_loader_load_uri_async (GdPdfLoader *self,
+                                   const gchar *uri,
+                                   GCancellable *cancellable,
+                                   GAsyncReadyCallback callback,
+                                   gpointer user_data);
+EvDocument *gd_pdf_loader_load_uri_finish (GdPdfLoader *self,
+                                           GAsyncResult *res,
+                                           GError **error);
 
 G_END_DECLS
 
diff --git a/src/mainWindow.js b/src/mainWindow.js
index d30052d..ce0c933 100644
--- a/src/mainWindow.js
+++ b/src/mainWindow.js
@@ -21,6 +21,7 @@
 
 const EvView = imports.gi.EvinceView;
 const Gd = imports.gi.Gd;
+const Gio = imports.gi.Gio;
 const GLib = imports.gi.GLib;
 const GObject = imports.gi.GObject;
 const Gtk = imports.gi.Gtk;
@@ -50,8 +51,9 @@ function MainWindow() {
 
 MainWindow.prototype = {
     _init: function() {
+        this._pdfLoader = null;
+        this._loaderCancellable = null;
         this._loaderTimeout = 0;
-        this._loaderSignal = 0;
         this._lastFilter = '';
 
         //TODO save this in GSettings?
@@ -160,15 +162,13 @@ MainWindow.prototype = {
     },
 
     _prepareForOverview: function() {
-        if (this._loaderSignal) {
-            this._pdfLoader.disconnect(this._loaderSignal);
-            this._loaderSignal = 0;
+        if (this._loaderCancellable) {
+            this._loaderCancellable.cancel();
+            this._loaderCancellable = null;
         }
 
-        if (this._pdfLodaer) {
-            this._pdfLoader.cleanup_document();
+        if (this._pdfLodaer)
             this._pdfLoader = null;
-        }
 
         if (this._preview) {
             this._preview.destroy();
@@ -202,10 +202,9 @@ MainWindow.prototype = {
 
         this._model.sourceIdFromResourceUrn(resource, Lang.bind(this,
             function(sourceId) {
+                this._loaderCancellable = new Gio.Cancellable();
                 this._pdfLoader = new Gd.PdfLoader({ source_id: sourceId });
-                this._loaderSignal =
-                    this._pdfLoader.connect('notify::document', Lang.bind(this, this._onDocumentLoaded));
-                this._pdfLoader.uri = uri;
+                this._pdfLoader.load_uri_async(uri, this._loaderCancellable, Lang.bind(this, this._onDocumentLoaded));
 
                 this._loaderTimeout = Mainloop.timeout_add(_PDF_LOADER_TIMEOUT,
                                                            Lang.bind(this, this._onPdfLoaderTimeout));
@@ -223,11 +222,16 @@ MainWindow.prototype = {
         return false;
     },
 
-    _onDocumentLoaded: function(loader) {
-        let document = loader.document;
-        let model = EvView.DocumentModel.new_with_document(document);
+    _onDocumentLoaded: function(loader, res) {
+        let document = null;
+        try {
+            document = loader.load_uri_finish(res);
+        } catch (e) {
+            log("Unable to load the PDF document: " + e.toString());
+            return;
+        }
 
-        this._loaderSignal = 0;
+        let model = EvView.DocumentModel.new_with_document(document);
 
         if (this._loaderTimeout) {
             Mainloop.source_remove(this._loaderTimeout);



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