]> www.fi.muni.cz Git - evince.git/blobdiff - shell/ev-window.c
Make this return TRUE only if any backends were loaded, so the ev_init()
[evince.git] / shell / ev-window.c
index 3c61eabf69fc3d883fe7fa05a614ad939359c2e4..523a8c6aa164342bde35b792b2512eb5f026ef21 100644 (file)
@@ -61,6 +61,7 @@
 #include "ev-document-images.h"
 #include "ev-document-links.h"
 #include "ev-document-thumbnails.h"
+#include "ev-document-type-builtins.h"
 #include "ev-file-exporter.h"
 #include "ev-file-helpers.h"
 #include "ev-file-monitor.h"
@@ -86,6 +87,7 @@
 #include "ev-utils.h"
 #include "ev-keyring.h"
 #include "ev-view.h"
+#include "ev-view-type-builtins.h"
 #include "ev-window.h"
 #include "ev-window-title.h"
 #include "ev-print-operation.h"
@@ -115,6 +117,12 @@ typedef enum {
        EV_CHROME_NORMAL        = EV_CHROME_MENUBAR | EV_CHROME_TOOLBAR | EV_CHROME_SIDEBAR
 } EvChrome;
 
+typedef enum {
+       EV_SAVE_DOCUMENT,
+       EV_SAVE_ATTACHMENT,
+       EV_SAVE_IMAGE
+} EvSaveType;
+
 struct _EvWindowPrivate {
        /* UI */
        EvChrome chrome;
@@ -135,6 +143,10 @@ struct _EvWindowPrivate {
        GtkWidget *sidebar_attachments;
        GtkWidget *sidebar_layers;
 
+       /* Progress Messages */
+       guint progress_idle;
+       GCancellable *progress_cancellable;
+
        /* Dialogs */
        GtkWidget *properties;
        GtkWidget *print_dialog;
@@ -171,7 +183,6 @@ struct _EvWindowPrivate {
        char *uri;
        glong uri_mtime;
        char *local_uri;
-       EvLinkDest *dest;
        gboolean unlink_temp_file;
        gboolean in_reload;
        EvFileMonitor *monitor;
@@ -183,6 +194,11 @@ struct _EvWindowPrivate {
        EvWindowPageMode page_mode;
        EvWindowTitle *title;
 
+       /* Load params */
+       EvLinkDest       *dest;
+       gchar            *search_string;
+       EvWindowRunMode   window_mode;
+
        EvJob            *load_job;
        EvJob            *reload_job;
        EvJob            *thumbnail_job;
@@ -224,7 +240,8 @@ static const gchar *document_print_settings[] = {
        GTK_PRINT_SETTINGS_SCALE,
        GTK_PRINT_SETTINGS_PRINT_PAGES,
        GTK_PRINT_SETTINGS_PAGE_RANGES,
-       GTK_PRINT_SETTINGS_PAGE_SET
+       GTK_PRINT_SETTINGS_PAGE_SET,
+       GTK_PRINT_SETTINGS_OUTPUT_URI
 };
 
 static void    ev_window_update_actions                (EvWindow         *ev_window);
@@ -294,6 +311,7 @@ static void     ev_window_load_file_remote              (EvWindow         *ev_wi
 static void     ev_window_media_player_key_pressed      (EvWindow         *window,
                                                         const gchar      *key,
                                                         gpointer          user_data);
+static void     ev_window_save_print_page_setup         (EvWindow         *window);
 
 G_DEFINE_TYPE (EvWindow, ev_window, GTK_TYPE_WINDOW)
 
@@ -1057,7 +1075,7 @@ setup_view_from_metadata (EvWindow *window)
        /* Sizing mode */
        if (ev_metadata_manager_get (uri, "sizing_mode", &sizing_mode, FALSE)) {
                enum_value = g_enum_get_value_by_nick
-                       (EV_SIZING_MODE_CLASS, g_value_get_string (&sizing_mode));
+                       (g_type_class_peek (EV_TYPE_SIZING_MODE), g_value_get_string (&sizing_mode));
                g_value_unset (&sizing_mode);
                ev_view_set_sizing_mode (view, enum_value->value);
        }
@@ -1356,7 +1374,7 @@ ev_window_load_job_cb (EvJob *job,
        if (!ev_job_is_failed (job)) {
                ev_window_set_document (ev_window, document);
                
-               if (job_load->mode != EV_WINDOW_MODE_PREVIEW) {
+               if (ev_window->priv->window_mode != EV_WINDOW_MODE_PREVIEW) {
                        setup_view_from_metadata (ev_window);
                }
 
@@ -1376,17 +1394,23 @@ ev_window_load_job_cb (EvJob *job,
                                                  flags);
                }
 
-               if (job_load->dest) {
+               if (ev_window->priv->dest) {
                        EvLink *link;
                        EvLinkAction *link_action;
        
-                       link_action = ev_link_action_new_dest (g_object_ref (job_load->dest));
+                       link_action = ev_link_action_new_dest (ev_window->priv->dest);
                        link = ev_link_new (NULL, link_action);
                        ev_view_handle_link (EV_VIEW (ev_window->priv->view), link);
                        g_object_unref (link);
+
+                       /* Already unrefed by ev_link_action
+                        * FIXME: link action should inc dest ref counting
+                        * or not unref it at all
+                        */
+                       ev_window->priv->dest = NULL;
                }
 
-               switch (job_load->mode) {
+               switch (ev_window->priv->window_mode) {
                        case EV_WINDOW_MODE_FULLSCREEN:
                                ev_window_run_fullscreen (ev_window);
                                break;
@@ -1400,15 +1424,18 @@ ev_window_load_job_cb (EvJob *job,
                                break;
                }
 
-               if (job_load->search_string && EV_IS_DOCUMENT_FIND (document)) {
+               if (ev_window->priv->search_string && EV_IS_DOCUMENT_FIND (document)) {
                        ev_window_cmd_edit_find (NULL, ev_window);
                        egg_find_bar_set_search_string (EGG_FIND_BAR (ev_window->priv->find_bar),
-                                                       job_load->search_string);
+                                                       ev_window->priv->search_string);
                }
 
+               g_free (ev_window->priv->search_string);
+               ev_window->priv->search_string = NULL;
+
                /* Create a monitor for the document */
                ev_window->priv->monitor = ev_file_monitor_new (ev_window->priv->uri);
-               g_signal_connect_swapped (G_OBJECT (ev_window->priv->monitor), "changed",
+               g_signal_connect_swapped (ev_window->priv->monitor, "changed",
                                          G_CALLBACK (ev_window_document_changed),
                                          ev_window);
                
@@ -1517,6 +1544,81 @@ ev_window_close_dialogs (EvWindow *ev_window)
        ev_window->priv->properties = NULL;
 }
 
+static void
+ev_window_clear_progress_idle (EvWindow *ev_window)
+{
+       if (ev_window->priv->progress_idle > 0)
+               g_source_remove (ev_window->priv->progress_idle);
+       ev_window->priv->progress_idle = 0;
+}
+
+static void
+reset_progress_idle (EvWindow *ev_window)
+{
+       ev_window->priv->progress_idle = 0;
+}
+
+static void
+ev_window_show_progress_message (EvWindow   *ev_window,
+                                guint       interval,
+                                GSourceFunc function)
+{
+       if (ev_window->priv->progress_idle > 0)
+               g_source_remove (ev_window->priv->progress_idle);
+       ev_window->priv->progress_idle =
+               g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
+                                           interval, function,
+                                           ev_window,
+                                           (GDestroyNotify)reset_progress_idle);
+}
+
+static void
+ev_window_reset_progress_cancellable (EvWindow *ev_window)
+{
+       if (ev_window->priv->progress_cancellable)
+               g_cancellable_reset (ev_window->priv->progress_cancellable);
+       else
+               ev_window->priv->progress_cancellable = g_cancellable_new ();
+}
+
+static void
+ev_window_progress_response_cb (EvProgressMessageArea *area,
+                               gint                   response,
+                               EvWindow              *ev_window)
+{
+       if (response == GTK_RESPONSE_CANCEL)
+               g_cancellable_cancel (ev_window->priv->progress_cancellable);
+       ev_window_set_message_area (ev_window, NULL);
+}
+
+static gboolean 
+show_loading_progress (EvWindow *ev_window)
+{
+       GtkWidget *area;
+       gchar     *text;
+       
+       if (ev_window->priv->message_area)
+               return FALSE;
+       
+       text = g_strdup_printf (_("Loading document from %s"),
+                               ev_window->priv->uri);
+       area = ev_progress_message_area_new (GTK_STOCK_OPEN,
+                                            text,
+                                            GTK_STOCK_CLOSE,
+                                            GTK_RESPONSE_CLOSE,
+                                            GTK_STOCK_CANCEL,
+                                            GTK_RESPONSE_CANCEL,
+                                            NULL);
+       g_signal_connect (area, "response",
+                         G_CALLBACK (ev_window_progress_response_cb),
+                         ev_window);
+       gtk_widget_show (area);
+       ev_window_set_message_area (ev_window, area);
+       g_free (text);
+
+       return FALSE;
+}
+
 static void
 ev_window_load_remote_failed (EvWindow *ev_window,
                              GError   *error)
@@ -1580,6 +1682,8 @@ window_open_file_copy_ready_cb (GFile        *source,
                                EvWindow     *ev_window)
 {
        GError *error = NULL;
+
+       ev_window_clear_progress_idle (ev_window);
        
        g_file_copy_finish (source, async_result, &error);
        if (!error) {
@@ -1604,6 +1708,16 @@ window_open_file_copy_ready_cb (GFile        *source,
                                               (GAsyncReadyCallback)mount_volume_ready_cb,
                                               ev_window);
                g_object_unref (operation);
+       } else if (error->domain == G_IO_ERROR &&
+                  error->code == G_IO_ERROR_CANCELLED) {
+               ev_window_clear_load_job (ev_window);
+               ev_window_clear_local_uri (ev_window);
+               ev_window_clear_print_settings_file (ev_window);
+               g_free (ev_window->priv->uri);
+               ev_window->priv->uri = NULL;
+               g_object_unref (source);
+               
+               ev_view_set_loading (EV_VIEW (ev_window->priv->view), FALSE);
        } else {
                ev_window_load_remote_failed (ev_window, error);
                g_object_unref (source);
@@ -1613,8 +1727,31 @@ window_open_file_copy_ready_cb (GFile        *source,
 }
 
 static void
-ev_window_load_file_remote (EvWindow  *ev_window,
-                           GFile     *source_file)
+window_open_file_copy_progress_cb (goffset   n_bytes,
+                                  goffset   total_bytes,
+                                  EvWindow *ev_window)
+{
+       gchar *status;
+       gdouble fraction;
+       
+       if (!ev_window->priv->message_area)
+               return;
+
+       fraction = n_bytes / (gdouble)total_bytes;
+       status = g_strdup_printf (_("Downloading document (%d%%)"),
+                                 (gint)(fraction * 100));
+       
+       ev_progress_message_area_set_status (EV_PROGRESS_MESSAGE_AREA (ev_window->priv->message_area),
+                                            status);
+       ev_progress_message_area_set_fraction (EV_PROGRESS_MESSAGE_AREA (ev_window->priv->message_area),
+                                              fraction);
+
+       g_free (status);
+}
+
+static void
+ev_window_load_file_remote (EvWindow *ev_window,
+                           GFile    *source_file)
 {
        GFile *target_file;
        
@@ -1633,14 +1770,21 @@ ev_window_load_file_remote (EvWindow  *ev_window,
                g_free (base_name);
                g_free (tmp_name);
        }
+
+       ev_window_reset_progress_cancellable (ev_window);
        
        target_file = g_file_new_for_uri (ev_window->priv->local_uri);
        g_file_copy_async (source_file, target_file,
-                          0, G_PRIORITY_DEFAULT, NULL,
-                          NULL, NULL, /* no progress callback */
-                          (GAsyncReadyCallback) window_open_file_copy_ready_cb,
+                          0, G_PRIORITY_DEFAULT,
+                          ev_window->priv->progress_cancellable,
+                          (GFileProgressCallback)window_open_file_copy_progress_cb,
+                          ev_window, 
+                          (GAsyncReadyCallback)window_open_file_copy_ready_cb,
                           ev_window);
        g_object_unref (target_file);
+
+       ev_window_show_progress_message (ev_window, 1,
+                                        (GSourceFunc)show_loading_progress);
 }
 
 void
@@ -1674,6 +1818,7 @@ ev_window_open_uri (EvWindow       *ev_window,
        ev_view_set_loading (EV_VIEW (ev_window->priv->view), TRUE);
 
        ev_window->priv->unlink_temp_file = unlink_temp_file;
+       ev_window->priv->window_mode = mode;
 
        if (mode == EV_WINDOW_MODE_PREVIEW) {
                ev_window->priv->print_settings_file = print_settings ? 
@@ -1684,9 +1829,18 @@ ev_window_open_uri (EvWindow       *ev_window,
                g_free (ev_window->priv->uri);
        ev_window->priv->uri = g_strdup (uri);
 
+       if (ev_window->priv->search_string)
+               g_free (ev_window->priv->search_string);
+       ev_window->priv->search_string = search_string ?
+               g_strdup (search_string) : NULL;
+
+       if (ev_window->priv->dest)
+               g_object_unref (ev_window->priv->dest);
+       ev_window->priv->dest = dest ? g_object_ref (dest) : NULL;
+
        setup_size_from_metadata (ev_window);
        
-       ev_window->priv->load_job = ev_job_load_new (uri, dest, mode, search_string);
+       ev_window->priv->load_job = ev_job_load_new (uri);
        g_signal_connect (ev_window->priv->load_job,
                          "finished",
                          G_CALLBACK (ev_window_load_job_cb),
@@ -1707,23 +1861,87 @@ ev_window_reload_local (EvWindow *ev_window)
        const gchar *uri;
        
        uri = ev_window->priv->local_uri ? ev_window->priv->local_uri : ev_window->priv->uri;
-       ev_window->priv->reload_job = ev_job_load_new (uri, NULL, 0, NULL);
+       ev_window->priv->reload_job = ev_job_load_new (uri);
        g_signal_connect (ev_window->priv->reload_job, "finished",
                          G_CALLBACK (ev_window_reload_job_cb),
                          ev_window);
        ev_job_scheduler_push_job (ev_window->priv->reload_job, EV_JOB_PRIORITY_NONE);
 }
 
+static gboolean 
+show_reloading_progress (EvWindow *ev_window)
+{
+       GtkWidget *area;
+       gchar     *text;
+       
+       if (ev_window->priv->message_area)
+               return FALSE;
+       
+       text = g_strdup_printf (_("Reloading document from %s"),
+                               ev_window->priv->uri);
+       area = ev_progress_message_area_new (GTK_STOCK_REFRESH,
+                                            text,
+                                            GTK_STOCK_CLOSE,
+                                            GTK_RESPONSE_CLOSE,
+                                            GTK_STOCK_CANCEL,
+                                            GTK_RESPONSE_CANCEL,
+                                            NULL);
+       g_signal_connect (area, "response",
+                         G_CALLBACK (ev_window_progress_response_cb),
+                         ev_window);
+       gtk_widget_show (area);
+       ev_window_set_message_area (ev_window, area);
+       g_free (text);
+
+       return FALSE;
+}
+
 static void
 reload_remote_copy_ready_cb (GFile        *remote,
                             GAsyncResult *async_result,
                             EvWindow     *ev_window)
 {
-       g_file_copy_finish (remote, async_result, NULL);
-       ev_window_reload_local (ev_window);
+       GError *error = NULL;
+       
+       ev_window_clear_progress_idle (ev_window);
+       
+       g_file_copy_finish (remote, async_result, &error);
+       if (error) {
+               if (error->domain != G_IO_ERROR ||
+                   error->code != G_IO_ERROR_CANCELLED)
+                       ev_window_error_message (ev_window, error,
+                                                "%s", _("Failed to reload document."));
+               g_error_free (error);
+       } else {
+               ev_window_reload_local (ev_window);
+       }
+               
        g_object_unref (remote);
 }
 
+static void
+reload_remote_copy_progress_cb (goffset   n_bytes,
+                               goffset   total_bytes,
+                               EvWindow *ev_window)
+{
+       gchar *status;
+       gdouble fraction;
+       
+       if (!ev_window->priv->message_area)
+               return;
+       
+       fraction = n_bytes / (gdouble)total_bytes;
+       status = g_strdup_printf (_("Downloading document (%d%%)"),
+                                 (gint)(fraction * 100));
+       
+       ev_progress_message_area_set_status (EV_PROGRESS_MESSAGE_AREA (ev_window->priv->message_area),
+                                            status);
+       ev_progress_message_area_set_fraction (EV_PROGRESS_MESSAGE_AREA (ev_window->priv->message_area),
+                                              fraction);
+
+       g_free (status);
+}
+
 static void
 query_remote_uri_mtime_cb (GFile        *remote,
                           GAsyncResult *async_result,
@@ -1748,14 +1966,21 @@ query_remote_uri_mtime_cb (GFile        *remote,
                        
                /* Remote file has changed */
                ev_window->priv->uri_mtime = mtime.tv_sec;
+
+               ev_window_reset_progress_cancellable (ev_window);
+               
                target_file = g_file_new_for_uri (ev_window->priv->local_uri);
                g_file_copy_async (remote, target_file,
                                   G_FILE_COPY_OVERWRITE,
-                                  G_PRIORITY_DEFAULT, NULL,
-                                  NULL, NULL, /* no progress callback */
-                                  (GAsyncReadyCallback) reload_remote_copy_ready_cb,
+                                  G_PRIORITY_DEFAULT,
+                                  ev_window->priv->progress_cancellable,
+                                  (GFileProgressCallback)reload_remote_copy_progress_cb,
+                                  ev_window, 
+                                  (GAsyncReadyCallback)reload_remote_copy_ready_cb,
                                   ev_window);
                g_object_unref (target_file);
+               ev_window_show_progress_message (ev_window, 1,
+                                                (GSourceFunc)show_reloading_progress);
        } else {
                g_object_unref (remote);
                ev_window_reload_local (ev_window);
@@ -2109,7 +2334,7 @@ ev_window_setup_recent (EvWindow *ev_window)
                                        gtk_recent_info_ref (info),
                                        (GDestroyNotify) gtk_recent_info_unref);
                
-               g_signal_connect (G_OBJECT (action), "activate",
+               g_signal_connect (action, "activate",
                                  G_CALLBACK (ev_window_cmd_recent_file_activate),
                                  (gpointer) ev_window);
 
@@ -2135,42 +2360,150 @@ ev_window_setup_recent (EvWindow *ev_window)
        g_list_free (items);
 }
 
+static gboolean 
+show_saving_progress (GFile *dst)
+{
+       EvWindow  *ev_window;
+       GtkWidget *area;
+       gchar     *text;
+       gchar     *uri;
+       EvSaveType save_type;
+
+       ev_window = EV_WINDOW (g_object_get_data (G_OBJECT (dst), "ev-window"));
+       ev_window->priv->progress_idle = 0;
+       
+       if (ev_window->priv->message_area)
+               return FALSE;
+
+       save_type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dst), "save-type"));
+       uri = g_file_get_uri (dst);
+       switch (save_type) {
+       case EV_SAVE_DOCUMENT:
+               text = g_strdup_printf (_("Saving document to %s"), uri);
+               break;
+       case EV_SAVE_ATTACHMENT:
+               text = g_strdup_printf (_("Saving attachment to %s"), uri);
+               break;
+       case EV_SAVE_IMAGE:
+               text = g_strdup_printf (_("Saving image to %s"), uri);
+               break;
+       default:
+               g_assert_not_reached ();
+       }
+       g_free (uri);
+       area = ev_progress_message_area_new (GTK_STOCK_SAVE,
+                                            text,
+                                            GTK_STOCK_CLOSE,
+                                            GTK_RESPONSE_CLOSE,
+                                            GTK_STOCK_CANCEL,
+                                            GTK_RESPONSE_CANCEL,
+                                            NULL);
+       g_signal_connect (area, "response",
+                         G_CALLBACK (ev_window_progress_response_cb),
+                         ev_window);
+       gtk_widget_show (area);
+       ev_window_set_message_area (ev_window, area);
+       g_free (text);
+
+       return FALSE;
+}
+
 static void
 window_save_file_copy_ready_cb (GFile        *src,
                                GAsyncResult *async_result,
                                GFile        *dst)
 {
-       EvWindow  *window;
-       gchar     *name;
-       GError    *error = NULL;
+       EvWindow *ev_window;
+       GError   *error = NULL;
 
+       ev_window = EV_WINDOW (g_object_get_data (G_OBJECT (dst), "ev-window"));
+       ev_window_clear_progress_idle (ev_window);
+       
        if (g_file_copy_finish (src, async_result, &error)) {
                ev_tmp_file_unlink (src);
                return;
        }
 
-       window = EV_WINDOW (g_object_get_data (G_OBJECT (dst), "ev-window"));
-       name = g_file_get_basename (dst);
-       ev_window_error_message (window, error,
-                                _("The file could not be saved as “%s”."),
-                                name);
+       if (error->domain != G_IO_ERROR ||
+           error->code != G_IO_ERROR_CANCELLED) {
+               gchar *name;
+               
+               name = g_file_get_basename (dst);
+               ev_window_error_message (ev_window, error,
+                                        _("The file could not be saved as “%s”."),
+                                        name);
+               g_free (name);
+       }
        ev_tmp_file_unlink (src);
-       g_free (name);
        g_error_free (error);
 }
 
 static void
-ev_window_save_remote (EvWindow *ev_window,
-                      GFile    *src,
-                      GFile    *dst)
+window_save_file_copy_progress_cb (goffset n_bytes,
+                                  goffset total_bytes,
+                                  GFile  *dst)
 {
+       EvWindow  *ev_window;
+       EvSaveType save_type;
+       gchar     *status;
+       gdouble    fraction;
+
+       ev_window = EV_WINDOW (g_object_get_data (G_OBJECT (dst), "ev-window"));
+       
+       if (!ev_window->priv->message_area)
+               return;
+       
+       fraction = n_bytes / (gdouble)total_bytes;
+       save_type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dst), "save-type"));
+
+       switch (save_type) {
+       case EV_SAVE_DOCUMENT:
+               status = g_strdup_printf (_("Uploading document (%d%%)"),
+                                         (gint)(fraction * 100));
+               break;
+       case EV_SAVE_ATTACHMENT:
+               status = g_strdup_printf (_("Uploading attachment (%d%%)"),
+                                         (gint)(fraction * 100));
+               break;
+       case EV_SAVE_IMAGE:
+               status = g_strdup_printf (_("Uploading image (%d%%)"),
+                                         (gint)(fraction * 100));
+               break;
+       default:
+               g_assert_not_reached ();
+       }
+       
+       ev_progress_message_area_set_status (EV_PROGRESS_MESSAGE_AREA (ev_window->priv->message_area),
+                                            status);
+       ev_progress_message_area_set_fraction (EV_PROGRESS_MESSAGE_AREA (ev_window->priv->message_area),
+                                              fraction);
+
+       g_free (status);
+}
+
+static void
+ev_window_save_remote (EvWindow  *ev_window,
+                      EvSaveType save_type,
+                      GFile     *src,
+                      GFile     *dst)
+{
+       ev_window_reset_progress_cancellable (ev_window);
        g_object_set_data (G_OBJECT (dst), "ev-window", ev_window);
+       g_object_set_data (G_OBJECT (dst), "save-type", GINT_TO_POINTER (save_type));
        g_file_copy_async (src, dst,
                           G_FILE_COPY_OVERWRITE,
-                          G_PRIORITY_DEFAULT, NULL,
-                          NULL, NULL, /* no progress callback */
-                          (GAsyncReadyCallback) window_save_file_copy_ready_cb,
-                          dst);                
+                          G_PRIORITY_DEFAULT,
+                          ev_window->priv->progress_cancellable,
+                          (GFileProgressCallback)window_save_file_copy_progress_cb,
+                          dst,
+                          (GAsyncReadyCallback)window_save_file_copy_ready_cb,
+                          dst);
+       ev_window->priv->progress_idle =
+               g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
+                                           1,
+                                           (GSourceFunc)show_saving_progress,
+                                           dst,
+                                           NULL);
 }
 
 static void
@@ -2214,6 +2547,9 @@ file_save_dialog_response_cb (GtkWidget *fc,
        }
        
        uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (fc));
+       /* FIXME: remote copy should be done here rather than in the save job, 
+        * so that we can track progress and cancel the operation
+        */
        
        ev_window_clear_save_job (ev_window);
        ev_window->priv->save_job = ev_job_save_new (ev_window->priv->document,
@@ -2266,30 +2602,6 @@ ev_window_cmd_save_as (GtkAction *action, EvWindow *ev_window)
        gtk_widget_show (fc);
 }
 
-static void
-ev_window_print_page_setup_done_cb (GtkPageSetup *page_setup,
-                                   EvWindow     *window)
-{
-       /* Dialog was canceled */
-       if (!page_setup)
-               return;
-
-       if (window->priv->print_page_setup)
-               g_object_unref (window->priv->print_page_setup);
-       window->priv->print_page_setup = g_object_ref (page_setup);
-}
-
-static void
-ev_window_cmd_file_print_setup (GtkAction *action, EvWindow *ev_window)
-{
-       gtk_print_run_page_setup_dialog_async (
-               GTK_WINDOW (ev_window),
-               ev_window->priv->print_page_setup,
-               ev_window->priv->print_settings,
-               (GtkPageSetupDoneFunc) ev_window_print_page_setup_done_cb,
-               ev_window);
-}
-
 static void
 ev_window_load_print_settings_from_metadata (EvWindow *window)
 {
@@ -2326,6 +2638,115 @@ ev_window_save_print_settings (EvWindow *window)
        }
 }
 
+static void
+ev_window_save_print_page_setup (EvWindow *window)
+{
+       gchar        *uri = window->priv->uri;
+       GtkPageSetup *page_setup = window->priv->print_page_setup;
+
+       /* Save page setup options that are specific to the document */
+       ev_metadata_manager_set_int (uri, "page-setup-orientation",
+                                    gtk_page_setup_get_orientation (page_setup));
+       ev_metadata_manager_set_double (uri, "page-setup-margin-top",
+                                       gtk_page_setup_get_top_margin (page_setup, GTK_UNIT_MM));
+       ev_metadata_manager_set_double (uri, "page-setup-margin-bottom",
+                                       gtk_page_setup_get_bottom_margin (page_setup, GTK_UNIT_MM));
+       ev_metadata_manager_set_double (uri, "page-setup-margin-left",
+                                       gtk_page_setup_get_left_margin (page_setup, GTK_UNIT_MM));
+       ev_metadata_manager_set_double (uri, "page-setup-margin-right",
+                                       gtk_page_setup_get_right_margin (page_setup, GTK_UNIT_MM));
+}
+
+static void
+ev_window_load_print_page_setup_from_metadata (EvWindow *window)
+{
+       gchar        *uri = window->priv->uri;
+       GtkPageSetup *page_setup = window->priv->print_page_setup;
+       GtkPaperSize *paper_size;
+       GValue        value = { 0, };
+
+       paper_size = gtk_page_setup_get_paper_size (page_setup);
+       
+       /* Load page setup options that are specific to the document */
+       if (ev_metadata_manager_get (uri, "page-setup-orientation", &value, TRUE)) {
+               gtk_page_setup_set_orientation (page_setup, g_value_get_int (&value));
+               g_value_unset (&value);
+       } else {
+               gtk_page_setup_set_orientation (page_setup, GTK_PAGE_ORIENTATION_PORTRAIT);
+       }
+       
+       if (ev_metadata_manager_get (uri, "page-setup-margin-top", &value, TRUE)) {
+               gtk_page_setup_set_top_margin (page_setup, g_value_get_double (&value), GTK_UNIT_MM);
+               g_value_unset (&value);
+       } else {
+               gtk_page_setup_set_top_margin (page_setup,
+                                              gtk_paper_size_get_default_top_margin (paper_size, GTK_UNIT_MM),
+                                              GTK_UNIT_MM);
+       }
+
+       if (ev_metadata_manager_get (uri, "page-setup-margin-bottom", &value, TRUE)) {
+               gtk_page_setup_set_bottom_margin (page_setup, g_value_get_double (&value), GTK_UNIT_MM);
+               g_value_unset (&value);
+       } else {
+               gtk_page_setup_set_bottom_margin (page_setup,
+                                                 gtk_paper_size_get_default_bottom_margin (paper_size, GTK_UNIT_MM),
+                                                 GTK_UNIT_MM);
+       }
+
+       if (ev_metadata_manager_get (uri, "page-setup-margin-left", &value, TRUE)) {
+               gtk_page_setup_set_left_margin (page_setup, g_value_get_double (&value), GTK_UNIT_MM);
+               g_value_unset (&value);
+       } else {
+               gtk_page_setup_set_left_margin (page_setup,
+                                               gtk_paper_size_get_default_left_margin (paper_size, GTK_UNIT_MM),
+                                               GTK_UNIT_MM);
+       }       
+
+       if (ev_metadata_manager_get (uri, "page-setup-margin-right", &value, TRUE)) {
+               gtk_page_setup_set_right_margin (page_setup, g_value_get_double (&value), GTK_UNIT_MM);
+               g_value_unset (&value);
+       } else {
+               gtk_page_setup_set_right_margin (page_setup,
+                                                gtk_paper_size_get_default_right_margin (paper_size, GTK_UNIT_MM),
+                                                GTK_UNIT_MM);
+       }       
+}
+
+static void
+ev_window_print_page_setup_done_cb (GtkPageSetup *page_setup,
+                                   EvWindow     *window)
+{
+       /* Dialog was canceled */
+       if (!page_setup)
+               return;
+
+       if (window->priv->print_page_setup != page_setup) {
+               if (window->priv->print_page_setup)
+                       g_object_unref (window->priv->print_page_setup);
+               window->priv->print_page_setup = g_object_ref (page_setup);
+       }
+       
+       ev_application_set_page_setup (EV_APP, page_setup);
+       ev_window_save_print_page_setup (window);
+}
+
+static void
+ev_window_cmd_file_print_setup (GtkAction *action, EvWindow *ev_window)
+{
+       if (!ev_window->priv->print_page_setup) {
+               ev_window->priv->print_page_setup = gtk_page_setup_copy (
+                       ev_application_get_page_setup (EV_APP));
+               ev_window_load_print_page_setup_from_metadata (ev_window);
+       }
+       
+       gtk_print_run_page_setup_dialog_async (
+               GTK_WINDOW (ev_window),
+               ev_window->priv->print_page_setup,
+               ev_window->priv->print_settings,
+               (GtkPageSetupDoneFunc) ev_window_print_page_setup_done_cb,
+               ev_window);
+}
+
 static void
 ev_window_print_cancel (EvWindow *ev_window)
 {
@@ -2528,13 +2949,13 @@ ev_window_print_range (EvWindow *ev_window,
                ev_window->priv->print_queue = g_queue_new ();
 
        op = ev_print_operation_new (ev_window->priv->document);
-       g_signal_connect (G_OBJECT (op), "begin_print",
+       g_signal_connect (op, "begin_print",
                          G_CALLBACK (ev_window_print_operation_begin_print),
                          (gpointer)ev_window);
-       g_signal_connect (G_OBJECT (op), "status_changed",
+       g_signal_connect (op, "status_changed",
                          G_CALLBACK (ev_window_print_operation_status_changed),
                          (gpointer)ev_window);
-       g_signal_connect (G_OBJECT (op), "done",
+       g_signal_connect (op, "done",
                          G_CALLBACK (ev_window_print_operation_done),
                          (gpointer)ev_window);
 
@@ -2688,7 +3109,7 @@ ev_window_cmd_file_close_window (GtkAction *action, EvWindow *ev_window)
                                GTK_RESPONSE_NO,
                                GTK_STOCK_CANCEL,
                                GTK_RESPONSE_CANCEL,
-                               _("Close after _Printing"),
+                               _("Close _after Printing"),
                                GTK_RESPONSE_YES,
                                NULL);
        gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
@@ -3532,7 +3953,6 @@ static void
 ev_window_do_preview_print (EvWindow *window)
 {
        EvWindowPrivate  *priv = window->priv;
-       GtkPageSetup     *page_setup;
        GtkPrintJob      *job;
        gchar            *filename;
        GError           *error = NULL;
@@ -3540,18 +3960,17 @@ ev_window_do_preview_print (EvWindow *window)
        g_assert (priv->print_settings != NULL);
        g_assert (priv->printer != NULL);
 
-       page_setup = gtk_page_setup_new ();
-
        job = gtk_print_job_new (gtk_window_get_title (GTK_WINDOW (window)),
                                 priv->printer,
                                 priv->print_settings,
-                                page_setup);
+                                priv->print_page_setup);
 
        g_object_unref (priv->print_settings);
        priv->print_settings = NULL;
+       g_object_unref (priv->print_page_setup);
+       priv->print_page_setup = NULL;
        g_object_unref (priv->printer);
        priv->printer = NULL;
-       g_object_unref (page_setup);
 
        filename = g_filename_from_uri (priv->local_uri ?
                                        priv->local_uri : priv->uri,
@@ -3574,31 +3993,50 @@ ev_window_do_preview_print (EvWindow *window)
 static void
 ev_window_cmd_preview_print (GtkAction *action, EvWindow *window)
 {
-       EvWindowPrivate *priv = window->priv;
-       GtkPrintSettings *print_settings = NULL;
+       EvWindowPrivate  *priv = window->priv;
+       GtkPrintSettings *print_settings;
+       GtkPageSetup     *page_setup;
        const gchar      *print_settings_file = priv->print_settings_file;
 
-       if (print_settings_file) {
-               if (g_file_test (print_settings_file, G_FILE_TEST_IS_REGULAR)) {
-                       GError *error = NULL;
-
-                       print_settings = gtk_print_settings_new_from_file (print_settings_file,
-                                                                          &error);
+       if (print_settings_file && g_file_test (print_settings_file, G_FILE_TEST_IS_REGULAR)) {
+               GKeyFile *key_file;
+               GError   *error = NULL;
+
+               key_file = g_key_file_new ();
+               g_key_file_load_from_file (key_file,
+                                          print_settings_file,
+                                          G_KEY_FILE_KEEP_COMMENTS |
+                                          G_KEY_FILE_KEEP_TRANSLATIONS,
+                                          &error);
+               if (!error) {
+                       print_settings =
+                               gtk_print_settings_new_from_key_file (key_file,
+                                                                     "Print Settings",
+                                                                     NULL);
+                       print_settings = print_settings ? print_settings : gtk_print_settings_new ();
                        
-                       if (error) {
-                               g_warning ("%s", error->message);
-                               g_error_free (error);
-                               print_settings = NULL;
-                       }
+                       page_setup = gtk_page_setup_new_from_key_file (key_file,
+                                                                      "Page Setup",
+                                                                      NULL);
+                       page_setup = page_setup ? page_setup : gtk_page_setup_new ();
+               } else {
+                       print_settings = gtk_print_settings_new ();
+                       page_setup = gtk_page_setup_new ();
+                       g_error_free (error);
                }
+
+               g_key_file_free (key_file);
+       } else {
+               print_settings = gtk_print_settings_new ();
+               page_setup = gtk_page_setup_new ();
        }
        
-       if (!print_settings)
-               print_settings = gtk_print_settings_new ();
-
        if (priv->print_settings)
                g_object_unref (priv->print_settings);
        priv->print_settings = print_settings;
+       if (priv->print_page_setup)
+               g_object_unref (priv->print_page_setup);
+       priv->print_page_setup = page_setup;
 
        gtk_enumerate_printers ((GtkPrinterFunc) ev_window_enumerate_printer_cb,
                                window, NULL, FALSE);
@@ -3646,7 +4084,7 @@ save_sizing_mode (EvWindow *window)
        GEnumValue *enum_value;
 
        mode = ev_view_get_sizing_mode (EV_VIEW (window->priv->view));
-       enum_value = g_enum_get_value (EV_SIZING_MODE_CLASS, mode);
+       enum_value = g_enum_get_value (g_type_class_peek (EV_TYPE_SIZING_MODE), mode);
 
        if (!ev_window_is_empty (window))
                ev_metadata_manager_set_string (window->priv->uri, "sizing_mode",
@@ -4270,6 +4708,40 @@ zoom_control_changed_cb (EphyZoomAction *action,
        }
 }
 
+static void
+ev_window_drag_data_received (GtkWidget        *widget,
+                             GdkDragContext   *context,
+                             gint              x,
+                             gint              y,
+                             GtkSelectionData *selection_data,
+                             guint             info,
+                             guint             time)
+
+{
+       EvWindow *window = EV_WINDOW (widget);
+       gchar   **uris;
+       gint      i = 0;
+       GSList   *uri_list = NULL;
+
+       uris = gtk_selection_data_get_uris (selection_data);
+       if (!uris) {
+               gtk_drag_finish (context, FALSE, FALSE, time);
+               return;
+       }
+
+       for (i = 0; uris[i]; i++) {
+               uri_list = g_slist_prepend (uri_list, (gpointer) uris[i]);
+       }
+
+       ev_application_open_uri_list (EV_APP, uri_list,
+                                     gtk_window_get_screen (GTK_WINDOW (window)),
+                                     0);
+       gtk_drag_finish (context, TRUE, FALSE, time);
+
+       g_strfreev (uris);
+       g_slist_free (uri_list);
+}
+
 static void
 ev_window_finalize (GObject *object)
 {
@@ -4391,6 +4863,12 @@ ev_window_dispose (GObject *object)
                priv->local_uri = NULL;
        }
 
+       ev_window_clear_progress_idle (window);
+       if (priv->progress_cancellable) {
+               g_object_unref (priv->progress_cancellable);
+               priv->progress_cancellable = NULL;
+       }
+       
        ev_window_close_dialogs (window);
 
        if (window->priv->printer) {
@@ -4441,6 +4919,11 @@ ev_window_dispose (GObject *object)
                priv->uri = NULL;
        }
 
+       if (priv->search_string) {
+               g_free (priv->search_string);
+               priv->search_string = NULL;
+       }
+       
        if (priv->dest) {
                g_object_unref (priv->dest);
                priv->dest = NULL;
@@ -4480,6 +4963,7 @@ ev_window_class_init (EvWindowClass *ev_window_class)
 
        widget_class->screen_changed = ev_window_screen_changed;
        widget_class->window_state_event = ev_window_state_event;
+       widget_class->drag_data_received = ev_window_drag_data_received;
 
        g_type_class_add_private (g_object_class, sizeof (EvWindowPrivate));
 }
@@ -5228,9 +5712,10 @@ image_save_dialog_response_cb (GtkWidget *fc,
        if (!is_native) {
                GFile *source_file;
                
-               source_file = g_file_new_for_uri (filename);
+               source_file = g_file_new_for_path (filename);
                
-               ev_window_save_remote (ev_window, source_file, target_file);
+               ev_window_save_remote (ev_window, EV_SAVE_IMAGE,
+                                      source_file, target_file);
                g_object_unref (source_file);
        }
        
@@ -5377,7 +5862,8 @@ attachment_save_dialog_response_cb (GtkWidget *fc,
                                dest_file = g_object_ref (target_file);
                        }
 
-                       ev_window_save_remote (ev_window, save_to, dest_file);
+                       ev_window_save_remote (ev_window, EV_SAVE_ATTACHMENT,
+                                              save_to, dest_file);
 
                        g_object_unref (dest_file);
                }
@@ -5773,6 +6259,13 @@ ev_window_init (EvWindow *ev_window)
 
         ev_window_sizing_mode_changed_cb (EV_VIEW (ev_window->priv->view), NULL, ev_window);
        ev_window_setup_action_sensitivity (ev_window);
+
+       /* Drag and Drop */
+       gtk_drag_dest_set (GTK_WIDGET (ev_window),
+                          GTK_DEST_DEFAULT_ALL,
+                          NULL, 0,
+                          GDK_ACTION_COPY);
+       gtk_drag_dest_add_uri_targets (GTK_WIDGET (ev_window));
 }
 
 /**