]> www.fi.muni.cz Git - evince.git/commitdiff
Move save a copy task to its own job so that it's carried out in a thread
authorCarlos Garcia Campos <carlosgc@gnome.org>
Tue, 4 Sep 2007 15:25:46 +0000 (15:25 +0000)
committerCarlos Garcia Campos <carlosgc@src.gnome.org>
Tue, 4 Sep 2007 15:25:46 +0000 (15:25 +0000)
2007-09-04  Carlos Garcia Campos  <carlosgc@gnome.org>
* shell/ev-job-queue.c: (handle_job), (search_for_jobs_unlocked),
(no_jobs_available_unlocked), (ev_job_queue_init), (find_queue),
(ev_job_queue_remove_job):
* shell/ev-jobs.[ch]: (ev_job_save_init), (ev_job_save_dispose),
(ev_job_save_class_init), (ev_job_save_new), (ev_job_save_run):
* shell/ev-window.c: (ev_window_clear_save_job),
(ev_window_save_job_cb), (file_save_dialog_response_cb),
(ev_window_dispose):
Move save a copy task to its own job so that it's carried out in a
thread avoiding another lock in the main thread. Use
ev_xfer_uri_simple() instead of gnome_vfs_move() so that document
can be saved to a pathin another file system. Fixes bug #456891.

svn path=/trunk/; revision=2664

ChangeLog
shell/ev-job-queue.c
shell/ev-jobs.c
shell/ev-jobs.h
shell/ev-window.c

index ae2b7e500512199400560263194349ef4c375bc1..f819b9716825083405ab15ae4e1de4c3d225fede 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2007-09-04  Carlos Garcia Campos  <carlosgc@gnome.org>
+
+       * shell/ev-job-queue.c: (handle_job), (search_for_jobs_unlocked),
+       (no_jobs_available_unlocked), (ev_job_queue_init), (find_queue),
+       (ev_job_queue_remove_job):
+       * shell/ev-jobs.[ch]: (ev_job_save_init), (ev_job_save_dispose),
+       (ev_job_save_class_init), (ev_job_save_new), (ev_job_save_run):
+       * shell/ev-window.c: (ev_window_clear_save_job),
+       (ev_window_save_job_cb), (file_save_dialog_response_cb),
+       (ev_window_dispose):
+
+       Move save a copy task to its own job so that it's carried out in a
+       thread avoiding another lock in the main thread. Use
+       ev_xfer_uri_simple() instead of gnome_vfs_move() so that document
+       can be saved to a pathin another file system. Fixes bug #456891.
+       
 2007-09-04  Nickolay V. Shmyrev  <nshmyrev@yandex.ru>
 
        * NEWS:
index bd7b86c55a026231eec264fe63dc1ce9d5cd57a6..b1b98f12fabc0ca4badbbbae17dabb3b12579e3e 100644 (file)
@@ -13,6 +13,7 @@ static GQueue *render_queue_low = NULL;
 static GQueue *thumbnail_queue_high = NULL;
 static GQueue *thumbnail_queue_low = NULL;
 static GQueue *load_queue = NULL;
+static GQueue *save_queue = NULL;
 static GQueue *fonts_queue = NULL;
 static GQueue *print_queue = NULL;
 
@@ -129,6 +130,8 @@ handle_job (EvJob *job)
                ev_job_links_run (EV_JOB_LINKS (job));
        else if (EV_IS_JOB_LOAD (job))
                ev_job_load_run (EV_JOB_LOAD (job));
+       else if (EV_IS_JOB_SAVE (job))
+               ev_job_save_run (EV_JOB_SAVE (job));
        else if (EV_IS_JOB_RENDER (job))
                ev_job_render_run (EV_JOB_RENDER (job));
        else if (EV_IS_JOB_FONTS (job))
@@ -188,6 +191,10 @@ search_for_jobs_unlocked (void)
        if (job)
                return job;
 
+       job = (EvJob *) g_queue_pop_head (save_queue);
+       if (job)
+               return job;
+
        job = (EvJob *) g_queue_pop_head (thumbnail_queue_low);
        if (job)
                return job;
@@ -219,6 +226,7 @@ no_jobs_available_unlocked (void)
                && g_queue_is_empty (render_queue_low)
                && g_queue_is_empty (links_queue)
                && g_queue_is_empty (load_queue)
+               && g_queue_is_empty (save_queue)
                && g_queue_is_empty (thumbnail_queue_high)
                && g_queue_is_empty (thumbnail_queue_low)
                && g_queue_is_empty (fonts_queue)
@@ -301,6 +309,7 @@ ev_job_queue_init (void)
 
        links_queue = g_queue_new ();
        load_queue = g_queue_new ();
+       save_queue = g_queue_new ();
        render_queue_high = g_queue_new ();
        render_queue_low = g_queue_new ();
        async_render_queue_high = g_queue_new ();
@@ -339,6 +348,9 @@ find_queue (EvJob         *job,
                } else if (EV_IS_JOB_LOAD (job)) {
                        /* the priority doesn't effect load */
                        return load_queue;
+               } else if (EV_IS_JOB_SAVE (job)) {
+                       /* the priority doesn't effect save */
+                       return save_queue;
                } else if (EV_IS_JOB_LINKS (job)) {
                        /* the priority doesn't effect links */
                        return links_queue;
@@ -485,6 +497,8 @@ ev_job_queue_remove_job (EvJob *job)
                        retval = remove_job_from_queue_locked (links_queue, job);
                } else if (EV_IS_JOB_LOAD (job)) {
                        retval = remove_job_from_queue_locked (load_queue, job);
+               } else if (EV_IS_JOB_SAVE (job)) {
+                       retval = remove_job_from_queue_locked (save_queue, job);
                } else if (EV_IS_JOB_FONTS (job)) {
                        retval = remove_job_from_queue_locked (fonts_queue, job);
                } else if (EV_IS_JOB_PRINT (job)) {
index acd4cb3a59e8081b4202ce0aa0280bb64bc9c0e8..c08fb0839ca72ea0f9ef7aa0224b789eaeae90c5 100644 (file)
@@ -11,7 +11,9 @@
 #include "ev-document-fonts.h"
 #include "ev-async-renderer.h"
 
+#include <errno.h>
 #include <glib/gstdio.h>
+#include <glib/gi18n.h>
 #include <unistd.h>
 #include <libgnomevfs/gnome-vfs-uri.h>
 #include <libgnomevfs/gnome-vfs-utils.h>
@@ -27,6 +29,8 @@ static void ev_job_thumbnail_init       (EvJobThumbnail      *job);
 static void ev_job_thumbnail_class_init (EvJobThumbnailClass *class);
 static void ev_job_load_init           (EvJobLoad           *job);
 static void ev_job_load_class_init     (EvJobLoadClass      *class);
+static void ev_job_save_init            (EvJobSave           *job);
+static void ev_job_save_class_init      (EvJobSaveClass      *class);
 static void ev_job_print_init           (EvJobPrint          *job);
 static void ev_job_print_class_init     (EvJobPrintClass     *class);
 
@@ -49,6 +53,7 @@ G_DEFINE_TYPE (EvJobRender, ev_job_render, EV_TYPE_JOB)
 G_DEFINE_TYPE (EvJobThumbnail, ev_job_thumbnail, EV_TYPE_JOB)
 G_DEFINE_TYPE (EvJobFonts, ev_job_fonts, EV_TYPE_JOB)
 G_DEFINE_TYPE (EvJobLoad, ev_job_load, EV_TYPE_JOB)
+G_DEFINE_TYPE (EvJobSave, ev_job_save, EV_TYPE_JOB)
 G_DEFINE_TYPE (EvJobPrint, ev_job_print, EV_TYPE_JOB)
 
 static void ev_job_init (EvJob *job) { /* Do Nothing */ }
@@ -561,6 +566,143 @@ ev_job_load_run (EvJobLoad *job)
        EV_JOB (job)->finished = TRUE;
 }
 
+static void ev_job_save_init (EvJobSave *job) { /* Do Nothing */ }
+
+static void
+ev_job_save_dispose (GObject *object)
+{
+       EvJobSave *job = EV_JOB_SAVE (object);
+
+       if (job->uri) {
+               g_free (job->uri);
+               job->uri = NULL;
+       }
+
+       if (job->document_uri) {
+               g_free (job->document_uri);
+               job->document_uri = NULL;
+       }
+
+       if (job->error) {
+               g_error_free (job->error);
+               job->error = NULL;
+       }
+
+       (* G_OBJECT_CLASS (ev_job_save_parent_class)->dispose) (object);
+}
+
+static void
+ev_job_save_class_init (EvJobSaveClass *class)
+{
+       GObjectClass *oclass;
+
+       oclass = G_OBJECT_CLASS (class);
+
+       oclass->dispose = ev_job_save_dispose;
+}
+
+EvJob *
+ev_job_save_new (EvDocument  *document,
+                const gchar *uri,
+                const gchar *document_uri)
+{
+       EvJobSave *job;
+
+       job = g_object_new (EV_TYPE_JOB_SAVE, NULL);
+
+       EV_JOB (job)->document = g_object_ref (document);
+       job->uri = g_strdup (uri);
+       job->document_uri = g_strdup (document_uri);
+       job->error = NULL;
+
+       return EV_JOB (job);
+}
+
+void
+ev_job_save_run (EvJobSave *job)
+{
+       gint   fd;
+       gchar *filename;
+       gchar *tmp_filename;
+       gchar *local_uri;
+       
+       filename = ev_tmp_filename ("saveacopy");
+       tmp_filename = g_strdup_printf ("%s.XXXXXX", filename);
+       g_free (filename);
+
+       fd = g_mkstemp (tmp_filename);
+       if (fd == -1) {
+               gchar *display_name;
+               gint   save_errno = errno;
+
+               display_name = g_filename_display_name (tmp_filename);
+               g_set_error (&(job->error),
+                            G_FILE_ERROR,
+                            g_file_error_from_errno (save_errno),
+                            _("Failed to create file “%s”: %s"),
+                            display_name, g_strerror (save_errno));
+               g_free (display_name);
+               g_free (tmp_filename);
+
+               return;
+       }
+
+       ev_document_doc_mutex_lock ();
+
+       /* Save document to temp filename */
+       local_uri = g_filename_to_uri (tmp_filename, NULL, NULL);
+       ev_document_save (EV_JOB (job)->document, local_uri, &(job->error));
+       close (fd);
+
+       ev_document_doc_mutex_unlock ();
+
+       if (job->error) {
+               g_free (local_uri);
+               return;
+       }
+
+       /* If original document was compressed,
+        * compress it again before saving
+        */
+       if (g_object_get_data (G_OBJECT (EV_JOB (job)->document),
+                              "uri-uncompressed")) {
+               EvCompressionType ctype = EV_COMPRESSION_NONE;
+               const gchar      *ext;
+               gchar            *uri_comp;
+               
+               ext = g_strrstr (job->document_uri, ".gz");
+               if (ext && g_ascii_strcasecmp (ext, ".gz") == 0)
+                       ctype = EV_COMPRESSION_GZIP;
+               
+               ext = g_strrstr (job->document_uri, ".bz2");
+               if (ext && g_ascii_strcasecmp (ext, ".bz2") == 0)
+                       ctype = EV_COMPRESSION_BZIP2;
+
+               uri_comp = ev_file_compress (local_uri, ctype, &(job->error));
+               g_free (local_uri);
+               ev_tmp_filename_unlink (tmp_filename);
+
+               if (!uri_comp || job->error) {
+                       local_uri = NULL;
+               } else {
+                       local_uri = uri_comp;
+               }
+       }
+
+       g_free (tmp_filename);
+       
+       if (job->error) {
+               g_free (local_uri);
+               return;
+       }
+
+       if (!local_uri)
+               return;
+
+       ev_xfer_uri_simple (local_uri, job->uri, &(job->error));
+       ev_tmp_uri_unlink (local_uri);
+}
+
 EvJob *
 ev_job_print_new (EvDocument    *document,
                  const gchar   *format,
index 084ed6c0e109ada7740156c61944d9e4fae24f11..6a35c834e7c013a6baab4bee8141d978dcedee4e 100644 (file)
@@ -45,6 +45,9 @@ typedef struct _EvJobFontsClass EvJobFontsClass;
 typedef struct _EvJobLoad EvJobLoad;
 typedef struct _EvJobLoadClass EvJobLoadClass;
 
+typedef struct _EvJobSave EvJobSave;
+typedef struct _EvJobSaveClass EvJobSaveClass;
+
 typedef struct _EvJobPrint EvJobPrint;
 typedef struct _EvJobPrintClass EvJobPrintClass;
 
@@ -78,10 +81,15 @@ typedef struct _EvJobPrintClass EvJobPrintClass;
 #define EV_JOB_LOAD_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_LOAD, EvJobLoadClass))
 #define EV_IS_JOB_LOAD(object)              (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_LOAD))
 
-#define EV_TYPE_JOB_PRINT                     (ev_job_print_get_type())
-#define EV_JOB_PRINT(object)                  (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_PRINT, EvJobPrint))
-#define EV_JOB_PRINT_CLASS(klass)             (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_PRINT, EvJobPrintClass))
-#define EV_IS_JOB_PRINT(object)               (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_PRINT))
+#define EV_TYPE_JOB_SAVE                    (ev_job_save_get_type())
+#define EV_JOB_SAVE(object)                 (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_SAVE, EvJobSave))
+#define EV_JOB_SAVE_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_SAVE, EvJobSaveClass))
+#define EV_IS_JOB_SAVE(object)              (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_SAVE))
+
+#define EV_TYPE_JOB_PRINT                    (ev_job_print_get_type())
+#define EV_JOB_PRINT(object)                 (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_PRINT, EvJobPrint))
+#define EV_JOB_PRINT_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_PRINT, EvJobPrintClass))
+#define EV_IS_JOB_PRINT(object)              (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_PRINT))
 
 typedef enum {
        EV_JOB_PRIORITY_LOW,
@@ -190,6 +198,20 @@ struct _EvJobLoadClass
        EvJobClass parent_class;
 };
 
+struct _EvJobSave
+{
+       EvJob parent;
+
+       GError *error;
+       gchar *uri;
+       gchar *document_uri;
+};
+
+struct _EvJobSaveClass
+{
+       EvJobClass parent_class;
+};
+
 struct _EvJobPrint
 {
        EvJob parent;
@@ -259,6 +281,13 @@ void            ev_job_load_set_uri       (EvJobLoad       *load,
                                           const gchar     *uri);
 void           ev_job_load_run           (EvJobLoad       *load);
 
+/* EvJobSave */
+GType           ev_job_save_get_type      (void) G_GNUC_CONST;
+EvJob          *ev_job_save_new           (EvDocument      *document,
+                                          const gchar     *uri,
+                                          const gchar     *document_uri);
+void            ev_job_save_run           (EvJobSave       *save);
+
 /* EvJobPrint */
 GType           ev_job_print_get_type     (void) G_GNUC_CONST;
 EvJob          *ev_job_print_new          (EvDocument      *document,
index 34e94eb0eab391b868ee6bd394604e5f8b01d98c..7e247afb458a8bf1e403820bb4129e5c8f7cfa47 100644 (file)
@@ -189,6 +189,7 @@ struct _EvWindowPrivate {
 
        EvJob *load_job;
        EvJob *thumbnail_job;
+       EvJob *save_job;
 #ifdef WITH_GNOME_PRINT
        GnomePrintJob *print_job;
 #endif
@@ -235,6 +236,8 @@ static void     ev_window_set_icon_from_thumbnail       (EvJobThumbnail   *job,
 static void     ev_window_print_job_cb                  (EvJobPrint       *job,
                                                         EvWindow         *window);
 #endif
+static void     ev_window_save_job_cb                   (EvJobSave        *save,
+                                                        EvWindow         *window);
 static void     ev_window_sizing_mode_changed_cb        (EvView           *view,
                                                         GParamSpec       *pspec,
                                                         EvWindow         *ev_window);
@@ -1215,25 +1218,25 @@ ev_window_popup_password_dialog (EvWindow *ev_window)
 static void
 ev_window_clear_load_job (EvWindow *ev_window)
 {
-    if (ev_window->priv->load_job != NULL) {
-
-       if (!ev_window->priv->load_job->finished)
-               ev_job_queue_remove_job (ev_window->priv->load_job);
-
-       g_signal_handlers_disconnect_by_func (ev_window->priv->load_job, ev_window_load_job_cb, ev_window);
-       g_object_unref (ev_window->priv->load_job);
-       ev_window->priv->load_job = NULL;
-    }
+       if (ev_window->priv->load_job != NULL) {
+               
+               if (!ev_window->priv->load_job->finished)
+                       ev_job_queue_remove_job (ev_window->priv->load_job);
+               
+               g_signal_handlers_disconnect_by_func (ev_window->priv->load_job, ev_window_load_job_cb, ev_window);
+               g_object_unref (ev_window->priv->load_job);
+               ev_window->priv->load_job = NULL;
+       }
 }
 
 static void
 ev_window_clear_local_uri (EvWindow *ev_window)
 {
-    if (ev_window->priv->local_uri) {
-           ev_tmp_uri_unlink (ev_window->priv->local_uri);
-           g_free (ev_window->priv->local_uri);
-           ev_window->priv->local_uri = NULL;
-    }
+       if (ev_window->priv->local_uri) {
+               ev_tmp_uri_unlink (ev_window->priv->local_uri);
+               g_free (ev_window->priv->local_uri);
+               ev_window->priv->local_uri = NULL;
+       }
 }
 
 static void
@@ -1985,130 +1988,60 @@ ev_window_save_remote (EvWindow    *ev_window,
 }
 
 static void
-file_save_dialog_response_cb (GtkWidget *fc,
-                             gint       response_id,
-                             EvWindow  *ev_window)
+ev_window_clear_save_job (EvWindow *ev_window)
 {
-       gchar  *uri;
-       gchar  *local_uri;
-       gint    fd;
-       gchar  *filename;
-       gchar  *tmp_filename;
-       GError *error = NULL;
-
-       if (response_id != GTK_RESPONSE_OK) {
-               gtk_widget_destroy (fc);
-               return;
+       if (ev_window->priv->save_job != NULL) {
+               if (!ev_window->priv->save_job->finished)
+                       ev_job_queue_remove_job (ev_window->priv->save_job);
+               
+               g_signal_handlers_disconnect_by_func (ev_window->priv->save_job,
+                                                     ev_window_save_job_cb,
+                                                     ev_window);
+               g_object_unref (ev_window->priv->save_job);
+               ev_window->priv->save_job = NULL;
        }
+}
 
-       uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (fc));
-
-       filename = ev_tmp_filename ("saveacopy");
-       tmp_filename = g_strdup_printf ("%s.XXXXXX", filename);
-       g_free (filename);
-       
-       fd = g_mkstemp (tmp_filename);
-       if (fd == -1) {
+static void
+ev_window_save_job_cb (EvJobSave *job,
+                      EvWindow  *window)
+{
+       if (job->error) {
                gchar *msg;
-               gchar *display_name;
-               gint   save_errno = errno;
                
-               display_name = g_filename_display_name (tmp_filename);
-               g_set_error (&error,
-                            G_FILE_ERROR,
-                            g_file_error_from_errno (save_errno),
-                            _("Failed to create file “%s”: %s"),
-                            display_name, g_strerror (save_errno));
-               g_free (display_name);
-
-               msg = g_strdup_printf (_("The file could not be saved as “%s”."), uri);
-               ev_window_error_dialog (GTK_WINDOW (ev_window), msg, error);
-
-               g_free (tmp_filename);
-               g_free (uri);
+               msg = g_strdup_printf (_("The file could not be saved as “%s”."), job->uri);
+               ev_window_error_dialog (GTK_WINDOW (window), msg, job->error);
                g_free (msg);
-               g_error_free (error);
-               gtk_widget_destroy (fc);
-               
-               return;
-       }
-
-       /* Save document to temp filename */
-       local_uri = g_filename_to_uri (tmp_filename, NULL, NULL);
-       
-       ev_document_doc_mutex_lock ();
-       ev_document_save (ev_window->priv->document, local_uri, &error);
-       ev_document_doc_mutex_unlock ();
-       
-       close (fd);
-
-       if (!error) {
-               /* If original document was compressed,
-                * compress it again before saving
-                */
-               if (g_object_get_data (G_OBJECT (ev_window->priv->document),
-                                      "uri-uncompressed")) {
-                       EvCompressionType ctype = EV_COMPRESSION_NONE;
-                       const gchar      *ext;
-                       gchar            *uri_comp;
-
-                       ext = g_strrstr (ev_window->priv->uri, ".gz");
-                       if (ext && g_ascii_strcasecmp (ext, ".gz") == 0)
-                               ctype = EV_COMPRESSION_GZIP;
-
-                       ext = g_strrstr (ev_window->priv->uri, ".bz2");
-                       if (ext && g_ascii_strcasecmp (ext, ".bz2") == 0)
-                               ctype = EV_COMPRESSION_BZIP2;
-                       
-                       uri_comp = ev_file_compress (local_uri, ctype, &error);
-                       g_free (local_uri);
-                       ev_tmp_filename_unlink (tmp_filename);
-                       
-                       if (!uri_comp || error) {
-                               local_uri = NULL;
-                       } else {
-                               local_uri = uri_comp;
-                       }
-               }
        }
 
-       g_free (tmp_filename);
-
-       if (error) {
-               gchar *msg;
+       ev_window_clear_save_job (window);
+}
 
-               msg = g_strdup_printf (_("The file could not be saved as “%s”."), uri);
-               ev_window_error_dialog (GTK_WINDOW (ev_window), msg, error);
-               g_free (uri);
-               g_free (msg);
-               g_error_free (error);
-               g_free (local_uri);
+static void
+file_save_dialog_response_cb (GtkWidget *fc,
+                             gint       response_id,
+                             EvWindow  *ev_window)
+{
+       gchar *uri;
+       
+       if (response_id != GTK_RESPONSE_OK) {
                gtk_widget_destroy (fc);
-
                return;
        }
-
-       if (local_uri) {
-               GnomeVFSURI *target_uri;
-
-               target_uri = gnome_vfs_uri_new (uri);
-               if (gnome_vfs_uri_is_local (target_uri)) {
-                       /* If target uri is local, just rename local_uri */
-                       if (gnome_vfs_move (local_uri, uri, TRUE) != GNOME_VFS_OK)
-                               ev_tmp_uri_unlink (local_uri);
-               } else {
-                       GnomeVFSURI *source_uri;
-
-                       source_uri = gnome_vfs_uri_new (local_uri);
-                       ev_window_save_remote (ev_window, source_uri, target_uri);
-                       gnome_vfs_uri_unref (source_uri);
-               }
-
-               gnome_vfs_uri_unref (target_uri);
-               g_free (local_uri);
-       }
+       
+       uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (fc));
+       
+       ev_window_clear_save_job (ev_window);
+       ev_window->priv->save_job = ev_job_save_new (ev_window->priv->document,
+                                                    uri, ev_window->priv->uri);
+       g_signal_connect (ev_window->priv->save_job, "finished",
+                         G_CALLBACK (ev_window_save_job_cb),
+                         ev_window);
+       /* The priority doesn't matter for this job */
+       ev_job_queue_add_job (ev_window->priv->save_job, EV_JOB_PRIORITY_LOW);
 
        g_free (uri);
+
        gtk_widget_destroy (fc);
 }
 
@@ -4211,6 +4144,10 @@ ev_window_dispose (GObject *object)
                ev_window_clear_load_job (window);
        }
 
+       if (priv->save_job) {
+               ev_window_clear_save_job (window);
+       }
+
        if (priv->thumbnail_job) {
                ev_window_clear_thumbnail_job (window);
        }