X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;ds=sidebyside;f=shell%2Fev-window.c;h=455c6a59a1fbe97f869fc132c4a5bf109a748d11;hb=refs%2Ftags%2FEVINCE_2_25_92;hp=a39b775bd552220fc32f65e523dc4d5df9f730f4;hpb=9b1e68d80f9b514c2f37faf8d448e2730a833b2a;p=evince.git diff --git a/shell/ev-window.c b/shell/ev-window.c index a39b775b..455c6a59 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -1,6 +1,7 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */ /* this file is part of evince, a gnome document viewer * + * Copyright (C) 2008 Carlos Garcia Campos * Copyright (C) 2004 Martin Kretzschmar * Copyright (C) 2004 Red Hat, Inc. * Copyright (C) 2000, 2001, 2002, 2003, 2004 Marco Pesenti Gritti @@ -37,8 +38,14 @@ #include #include #include +#if GTK_CHECK_VERSION (2, 14, 0) #include +#else +#include +#endif +#ifdef WITH_GCONF #include +#endif #include "egg-editable-toolbar.h" #include "egg-toolbar-editor.h" @@ -56,6 +63,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" @@ -69,7 +77,6 @@ #include "ev-navigation-action.h" #include "ev-open-recent-action.h" #include "ev-page-action.h" -#include "ev-password.h" #include "ev-password-view.h" #include "ev-properties-dialog.h" #include "ev-sidebar-attachments.h" @@ -77,11 +84,16 @@ #include "ev-sidebar-links.h" #include "ev-sidebar-page.h" #include "ev-sidebar-thumbnails.h" +#include "ev-sidebar-layers.h" #include "ev-stock-icons.h" #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" +#include "ev-progress-message-area.h" #ifdef ENABLE_DBUS #include "ev-media-player-keys.h" @@ -107,6 +119,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; @@ -125,11 +143,15 @@ struct _EvWindowPrivate { GtkWidget *sidebar_thumbs; GtkWidget *sidebar_links; GtkWidget *sidebar_attachments; + GtkWidget *sidebar_layers; + + /* Progress Messages */ + guint progress_idle; + GCancellable *progress_cancellable; /* Dialogs */ GtkWidget *properties; GtkWidget *print_dialog; - GtkWidget *password_dialog; /* UI Builders */ GtkActionGroup *action_group; @@ -161,8 +183,8 @@ struct _EvWindowPrivate { /* Document */ char *uri; + glong uri_mtime; char *local_uri; - EvLinkDest *dest; gboolean unlink_temp_file; gboolean in_reload; EvFileMonitor *monitor; @@ -174,20 +196,23 @@ 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; EvJob *save_job; - EvJob *print_job; EvJob *find_job; /* Printing */ - gboolean print_preview; - GtkPrintJob *gtk_print_job; + GQueue *print_queue; GtkPrinter *printer; GtkPrintSettings *print_settings; GtkPageSetup *print_page_setup; - + gboolean close_after_print; }; #define EV_WINDOW_GET_PRIVATE(object) \ @@ -207,6 +232,7 @@ struct _EvWindowPrivate { #define LINKS_SIDEBAR_ID "links" #define THUMBNAILS_SIDEBAR_ID "thumbnails" #define ATTACHMENTS_SIDEBAR_ID "attachments" +#define LAYERS_SIDEBAR_ID "layers" static const gchar *document_print_settings[] = { GTK_PRINT_SETTINGS_N_COPIES, @@ -216,7 +242,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); @@ -232,8 +259,6 @@ static void ev_window_reload_job_cb (EvJob *job, EvWindow *window); static void ev_window_set_icon_from_thumbnail (EvJobThumbnail *job, EvWindow *ev_window); -static void ev_window_print_job_cb (EvJob *job, - EvWindow *window); static void ev_window_save_job_cb (EvJob *save, EvWindow *window); static void ev_window_sizing_mode_changed_cb (EvView *view, @@ -288,6 +313,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) @@ -316,8 +342,9 @@ ev_window_setup_action_sensitivity (EvWindow *ev_window) gboolean can_get_text = FALSE; gboolean has_pages = FALSE; gboolean can_find = FALSE; - +#ifdef WITH_GCONF GConfClient *client; +#endif if (document) { has_document = TRUE; @@ -340,10 +367,12 @@ ev_window_setup_action_sensitivity (EvWindow *ev_window) can_find = TRUE; } +#ifdef WITH_GCONF client = gconf_client_get_default (); override_restrictions = gconf_client_get_bool (client, GCONF_OVERRIDE_RESTRICTIONS, NULL); +#endif if (!override_restrictions && info && info->fields_mask & EV_DOCUMENT_INFO_PERMISSIONS) { ok_to_print = (info->permissions & EV_DOCUMENT_PERMISSIONS_OK_TO_PRINT); ok_to_copy = (info->permissions & EV_DOCUMENT_PERMISSIONS_OK_TO_COPY); @@ -352,7 +381,7 @@ ev_window_setup_action_sensitivity (EvWindow *ev_window) if (has_document && !EV_IS_FILE_EXPORTER(document)) ok_to_print = FALSE; - +#ifdef WITH_GCONF if (gconf_client_get_bool (client, GCONF_LOCKDOWN_SAVE, NULL)) { ok_to_copy = FALSE; } @@ -362,6 +391,7 @@ ev_window_setup_action_sensitivity (EvWindow *ev_window) } g_object_unref (client); +#endif /* File menu */ ev_window_set_action_sensitive (ev_window, "FileOpenCopy", has_document); @@ -654,18 +684,29 @@ ev_window_message_area_response_cb (EvMessageArea *area, } static void -ev_window_error_message (EvWindow *window, const gchar *msg, GError *error) +ev_window_error_message (EvWindow *window, + GError *error, + const gchar *format, + ...) { GtkWidget *area; + va_list args; + gchar *msg = NULL; if (window->priv->message_area) return; + va_start (args, format); + msg = g_strdup_vprintf (format, args); + va_end (args); + area = ev_message_area_new (GTK_MESSAGE_ERROR, msg, GTK_STOCK_CLOSE, - GTK_RESPONSE_CANCEL, + GTK_RESPONSE_CLOSE, NULL); + g_free (msg); + if (error) ev_message_area_set_secondary_text (EV_MESSAGE_AREA (area), error->message); g_signal_connect (area, "response", @@ -676,18 +717,27 @@ ev_window_error_message (EvWindow *window, const gchar *msg, GError *error) } static void -ev_window_warning_message (EvWindow *window, const gchar *msg) +ev_window_warning_message (EvWindow *window, + const gchar *format, + ...) { GtkWidget *area; + va_list args; + gchar *msg = NULL; if (window->priv->message_area) return; + va_start (args, format); + msg = g_strdup_vprintf (format, args); + va_end (args); + area = ev_message_area_new (GTK_MESSAGE_WARNING, msg, GTK_STOCK_CLOSE, - GTK_RESPONSE_CANCEL, + GTK_RESPONSE_CLOSE, NULL); + g_free (msg); g_signal_connect (area, "response", G_CALLBACK (ev_window_message_area_response_cb), @@ -837,29 +887,6 @@ update_document_mode (EvWindow *window, EvDocumentMode mode) } } -static void -setup_document_from_metadata (EvWindow *window) -{ - char *uri = window->priv->uri; - GValue page = { 0, }; - gint n_pages; - gint new_page; - - /* View the previously shown page, but make sure to not open a document on - * the last page, since closing it on the last page most likely means the - * user was finished reading the document. In that case, reopening should - * show the first page. */ - if (uri && ev_metadata_manager_get (uri, "page", &page, TRUE)) { - n_pages = ev_page_cache_get_n_pages (window->priv->page_cache); - new_page = CLAMP (g_value_get_int (&page), 0, n_pages - 1); - if (!window->priv->in_reload && new_page == n_pages - 1) - new_page = 0; - ev_page_cache_set_current_page (window->priv->page_cache, - new_page); - g_value_unset (&page); - } -} - static void setup_chrome_from_metadata (EvWindow *window) { @@ -875,16 +902,18 @@ setup_chrome_from_metadata (EvWindow *window) } static void -setup_sidebar_from_metadata (EvWindow *window, EvDocument *document) +setup_sidebar_from_metadata (EvWindow *window) { - char *uri = window->priv->uri; - GtkWidget *sidebar = window->priv->sidebar; - GtkWidget *links = window->priv->sidebar_links; - GtkWidget *thumbs = window->priv->sidebar_thumbs; - GtkWidget *attachments = window->priv->sidebar_attachments; - GValue sidebar_size = { 0, }; - GValue sidebar_page = { 0, }; - GValue sidebar_visibility = { 0, }; + gchar *uri = window->priv->uri; + EvDocument *document = window->priv->document; + GtkWidget *sidebar = window->priv->sidebar; + GtkWidget *links = window->priv->sidebar_links; + GtkWidget *thumbs = window->priv->sidebar_thumbs; + GtkWidget *attachments = window->priv->sidebar_attachments; + GtkWidget *layers = window->priv->sidebar_layers; + GValue sidebar_size = { 0, }; + GValue sidebar_page = { 0, }; + GValue sidebar_visibility = { 0, }; if (ev_metadata_manager_get (uri, "sidebar_size", &sidebar_size, FALSE)) { gtk_paned_set_position (GTK_PANED (window->priv->hpaned), @@ -892,19 +921,29 @@ setup_sidebar_from_metadata (EvWindow *window, EvDocument *document) g_value_unset(&sidebar_size); } - if (document && ev_metadata_manager_get (uri, "sidebar_page", &sidebar_page, FALSE)) { + if (document && ev_metadata_manager_get (uri, "sidebar_page", &sidebar_page, TRUE)) { const char *page_id = g_value_get_string (&sidebar_page); - + if (strcmp (page_id, LINKS_SIDEBAR_ID) == 0 && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (links), document)) { ev_sidebar_set_page (EV_SIDEBAR (sidebar), links); - } else if (strcmp (page_id, THUMBNAILS_SIDEBAR_ID) && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (thumbs), document)) { + } else if (strcmp (page_id, THUMBNAILS_SIDEBAR_ID) == 0 && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (thumbs), document)) { ev_sidebar_set_page (EV_SIDEBAR (sidebar), thumbs); - } else if (strcmp (page_id, ATTACHMENTS_SIDEBAR_ID) && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (attachments), document)) { + } else if (strcmp (page_id, ATTACHMENTS_SIDEBAR_ID) == 0 && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (attachments), document)) { ev_sidebar_set_page (EV_SIDEBAR (sidebar), attachments); + } else if (strcmp (page_id, LAYERS_SIDEBAR_ID) == 0 && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (layers), document)) { + ev_sidebar_set_page (EV_SIDEBAR (sidebar), layers); } g_value_unset (&sidebar_page); - } else if (document && ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (links), document)) { - ev_sidebar_set_page (EV_SIDEBAR (sidebar), links); + } else if (document) { + if (ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (links), document)) { + ev_sidebar_set_page (EV_SIDEBAR (sidebar), links); + } else if (ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (thumbs), document)) { + ev_sidebar_set_page (EV_SIDEBAR (sidebar), thumbs); + } else if (ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (attachments), document)) { + ev_sidebar_set_page (EV_SIDEBAR (sidebar), attachments); + } else if (ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (layers), document)) { + ev_sidebar_set_page (EV_SIDEBAR (sidebar), layers); + } } if (ev_metadata_manager_get (uri, "sidebar_visibility", &sidebar_visibility, FALSE)) { @@ -915,56 +954,43 @@ setup_sidebar_from_metadata (EvWindow *window, EvDocument *document) } static void -setup_size_from_metadata (EvWindow *window) +setup_document_from_metadata (EvWindow *window) { - char *uri = window->priv->uri; + gchar *uri = window->priv->uri; + GValue page = { 0, }; GValue width = { 0, }; GValue height = { 0, }; GValue width_ratio = { 0, }; GValue height_ratio = { 0, }; - GValue maximized = { 0, }; - GValue x = { 0, }; - GValue y = { 0, }; - if (ev_metadata_manager_get (uri, "window_maximized", &maximized, FALSE)) { - if (g_value_get_boolean (&maximized)) { - gtk_window_maximize (GTK_WINDOW (window)); - return; - } else { - gtk_window_unmaximize (GTK_WINDOW (window)); - } - g_value_unset (&maximized); + /* View the previously shown page, but make sure to not open a document on + * the last page, since closing it on the last page most likely means the + * user was finished reading the document. In that case, reopening should + * show the first page. */ + if (uri && ev_metadata_manager_get (uri, "page", &page, TRUE)) { + gint n_pages; + gint new_page; + + n_pages = ev_page_cache_get_n_pages (window->priv->page_cache); + new_page = CLAMP (g_value_get_int (&page), 0, n_pages - 1); + ev_page_cache_set_current_page (window->priv->page_cache, + new_page); + g_value_unset (&page); } - if (ev_metadata_manager_get (uri, "window_x", &x, TRUE) && - ev_metadata_manager_get (uri, "window_y", &y, TRUE)) { - gtk_window_move (GTK_WINDOW (window), g_value_get_int (&x), - g_value_get_int (&y)); - g_value_unset (&x); - g_value_unset (&y); - } + setup_sidebar_from_metadata (window); - if (ev_metadata_manager_get (uri, "window_width", &width, TRUE) && - ev_metadata_manager_get (uri, "window_height", &height, TRUE)) { - gtk_window_resize (GTK_WINDOW (window), - g_value_get_int (&width), - g_value_get_int (&height)); - g_value_unset (&width); - g_value_unset (&height); - return; - } + if (ev_metadata_manager_get (uri, "window_width", &width, TRUE) && + ev_metadata_manager_get (uri, "window_height", &height, TRUE)) + return; /* size was already set in setup_size_from_metadata */ - if (window->priv->page_cache && - ev_metadata_manager_get (uri, "window_width_ratio", &width_ratio, FALSE) && + if (ev_metadata_manager_get (uri, "window_width_ratio", &width_ratio, FALSE) && ev_metadata_manager_get (uri, "window_height_ratio", &height_ratio, FALSE)) { - - gint document_width; - gint document_height; - + gint document_width; + gint document_height; GdkScreen *screen; - - gint request_width; - gint request_height; + gint request_width; + gint request_height; ev_page_cache_get_max_width (window->priv->page_cache, 0, 1.0, @@ -992,34 +1018,62 @@ setup_size_from_metadata (EvWindow *window) } static void -setup_view_from_metadata (EvWindow *window) +setup_size_from_metadata (EvWindow *window) { - EvView *view = EV_VIEW (window->priv->view); char *uri = window->priv->uri; - GEnumValue *enum_value; - GValue sizing_mode = { 0, }; - GValue zoom = { 0, }; - GValue continuous = { 0, }; - GValue dual_page = { 0, }; - GValue presentation = { 0, }; - GValue fullscreen = { 0, }; - GValue rotation = { 0, }; + GValue width = { 0, }; + GValue height = { 0, }; GValue maximized = { 0, }; + GValue x = { 0, }; + GValue y = { 0, }; - /* Maximized */ if (ev_metadata_manager_get (uri, "window_maximized", &maximized, FALSE)) { if (g_value_get_boolean (&maximized)) { gtk_window_maximize (GTK_WINDOW (window)); + g_value_unset (&maximized); + return; } else { gtk_window_unmaximize (GTK_WINDOW (window)); } g_value_unset (&maximized); } + if (ev_metadata_manager_get (uri, "window_x", &x, TRUE) && + ev_metadata_manager_get (uri, "window_y", &y, TRUE)) { + gtk_window_move (GTK_WINDOW (window), g_value_get_int (&x), + g_value_get_int (&y)); + g_value_unset (&x); + g_value_unset (&y); + } + + if (ev_metadata_manager_get (uri, "window_width", &width, TRUE) && + ev_metadata_manager_get (uri, "window_height", &height, TRUE)) { + gtk_window_resize (GTK_WINDOW (window), + g_value_get_int (&width), + g_value_get_int (&height)); + g_value_unset (&width); + g_value_unset (&height); + } +} + +static void +setup_view_from_metadata (EvWindow *window) +{ + EvView *view = EV_VIEW (window->priv->view); + gchar *uri = window->priv->uri; + GEnumValue *enum_value; + GValue sizing_mode = { 0, }; + GValue zoom = { 0, }; + GValue continuous = { 0, }; + GValue dual_page = { 0, }; + GValue presentation = { 0, }; + GValue fullscreen = { 0, }; + GValue rotation = { 0, }; + /* 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); } @@ -1167,6 +1221,7 @@ ev_window_setup_document (EvWindow *ev_window) if (ev_window->priv->properties) { ev_properties_dialog_set_document (EV_PROPERTIES_DIALOG (ev_window->priv->properties), + ev_window->priv->uri, ev_window->priv->document); } @@ -1193,14 +1248,22 @@ ev_window_set_document (EvWindow *ev_window, EvDocument *document) g_signal_connect (ev_window->priv->page_cache, "history-changed", G_CALLBACK (history_changed_cb), ev_window); - setup_size_from_metadata (ev_window); - setup_sidebar_from_metadata (ev_window, document); - setup_document_from_metadata (ev_window); + if (ev_window->priv->in_reload && ev_window->priv->dest) { + gint page; + + /* Restart the current page */ + page = CLAMP (ev_link_dest_get_page (ev_window->priv->dest), + 0, + ev_page_cache_get_n_pages (ev_window->priv->page_cache) - 1); + ev_page_cache_set_current_page (ev_window->priv->page_cache, page); + g_object_unref (ev_window->priv->dest); + ev_window->priv->dest = NULL; + } if (ev_page_cache_get_n_pages (ev_window->priv->page_cache) > 0) { ev_view_set_document (view, document); } else { - ev_window_warning_message (ev_window, + ev_window_warning_message (ev_window, "%s", _("The document contains no pages")); } @@ -1217,57 +1280,15 @@ ev_window_document_changed (EvWindow *ev_window, } static void -password_dialog_response (GtkWidget *password_dialog, - gint response_id, - EvWindow *ev_window) -{ - if (response_id == GTK_RESPONSE_OK) { - ev_job_load_set_password (EV_JOB_LOAD (ev_window->priv->load_job), - ev_password_dialog_get_password (EV_PASSWORD_DIALOG (password_dialog))); - - ev_password_dialog_save_password (EV_PASSWORD_DIALOG (password_dialog)); - - ev_window_title_set_type (ev_window->priv->title, EV_WINDOW_TITLE_DOCUMENT); - ev_job_scheduler_push_job (ev_window->priv->load_job, EV_JOB_PRIORITY_NONE); - - gtk_widget_destroy (password_dialog); - - return; - } - - gtk_widget_set_sensitive (ev_window->priv->password_view, TRUE); - gtk_widget_destroy (password_dialog); -} - -/* Called either by ev_window_load_job_cb or by the "unlock" callback on the - * password_view page. It assumes that ev_window->priv->password_* has been set - * correctly. These are cleared by password_dialog_response() */ - -static void -ev_window_popup_password_dialog (EvWindow *ev_window) +ev_window_password_view_unlock (EvWindow *ev_window) { + const gchar *password; + g_assert (ev_window->priv->load_job); - gtk_widget_set_sensitive (ev_window->priv->password_view, FALSE); - - ev_window_title_set_uri (ev_window->priv->title, ev_window->priv->uri); - ev_window_title_set_type (ev_window->priv->title, EV_WINDOW_TITLE_PASSWORD); - - if (ev_window->priv->password_dialog == NULL) { - ev_window->priv->password_dialog = - g_object_new (EV_TYPE_PASSWORD_DIALOG, "uri", ev_window->priv->uri, NULL); - gtk_window_set_transient_for (GTK_WINDOW (ev_window->priv->password_dialog), GTK_WINDOW (ev_window)); - - g_object_add_weak_pointer (G_OBJECT (ev_window->priv->password_dialog), - (gpointer) &(ev_window->priv->password_dialog)); - g_signal_connect (ev_window->priv->password_dialog, - "response", - G_CALLBACK (password_dialog_response), - ev_window); - gtk_widget_show (ev_window->priv->password_dialog); - } else { - ev_password_dialog_set_bad_pass (EV_PASSWORD_DIALOG (ev_window->priv->password_dialog)); - } + password = ev_password_view_get_password (EV_PASSWORD_VIEW (ev_window->priv->password_view)); + ev_job_load_set_password (EV_JOB_LOAD (ev_window->priv->load_job), password); + ev_job_scheduler_push_job (ev_window->priv->load_job, EV_JOB_PRIORITY_NONE); } static void @@ -1358,8 +1379,10 @@ ev_window_load_job_cb (EvJob *job, /* Success! */ if (!ev_job_is_failed (job)) { ev_window_set_document (ev_window, document); + + setup_document_from_metadata (ev_window); - if (job_load->mode != EV_WINDOW_MODE_PREVIEW) { + if (ev_window->priv->window_mode != EV_WINDOW_MODE_PREVIEW) { setup_view_from_metadata (ev_window); } @@ -1367,17 +1390,35 @@ ev_window_load_job_cb (EvJob *job, ev_window_add_recent (ev_window, ev_window->priv->uri); } - if (job_load->dest) { + ev_window_title_set_type (ev_window->priv->title, + EV_WINDOW_TITLE_DOCUMENT); + if (job_load->password) { + GPasswordSave flags; + + flags = ev_password_view_get_password_save_flags ( + EV_PASSWORD_VIEW (ev_window->priv->password_view)); + ev_keyring_save_password (ev_window->priv->uri, + job_load->password, + flags); + } + + 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; @@ -1391,15 +1432,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 (job_load->uri); - g_signal_connect_swapped (G_OBJECT (ev_window->priv->monitor), "changed", + ev_window->priv->monitor = ev_file_monitor_new (ev_window->priv->uri); + g_signal_connect_swapped (ev_window->priv->monitor, "changed", G_CALLBACK (ev_window_document_changed), ev_window); @@ -1407,26 +1451,44 @@ ev_window_load_job_cb (EvJob *job, return; } - if (job->error->domain == EV_DOCUMENT_ERROR && - job->error->code == EV_DOCUMENT_ERROR_ENCRYPTED) { - GFile *file; - gchar *base_name; - + if (g_error_matches (job->error, EV_DOCUMENT_ERROR, EV_DOCUMENT_ERROR_ENCRYPTED)) { + gchar *password; + setup_view_from_metadata (ev_window); + + /* First look whether password is in keyring */ + password = ev_keyring_lookup_password (ev_window->priv->uri); + if (password) { + if (job_load->password && strcmp (password, job_load->password) == 0) { + /* Password in kering is wrong */ + ev_job_load_set_password (job_load, NULL); + /* FIXME: delete password from keyring? */ + } else { + ev_job_load_set_password (job_load, password); + ev_job_scheduler_push_job (job, EV_JOB_PRIORITY_NONE); + g_free (password); + return; + } + + g_free (password); + } + + /* We need to ask the user for a password */ + ev_window_title_set_uri (ev_window->priv->title, + ev_window->priv->uri); + ev_window_title_set_type (ev_window->priv->title, + EV_WINDOW_TITLE_PASSWORD); + + ev_password_view_set_uri (EV_PASSWORD_VIEW (ev_window->priv->password_view), + job_load->uri); - file = g_file_new_for_uri (job_load->uri); - base_name = g_file_get_basename (file); - ev_password_view_set_file_name (EV_PASSWORD_VIEW (ev_window->priv->password_view), - base_name); - g_object_unref (file); - g_free (base_name); ev_window_set_page_mode (ev_window, PAGE_MODE_PASSWORD); - - ev_window_popup_password_dialog (ev_window); + + ev_job_load_set_password (job_load, NULL); + ev_password_view_ask_password (EV_PASSWORD_VIEW (ev_window->priv->password_view)); } else { - ev_window_error_message (ev_window, - _("Unable to open document"), - job->error); + ev_window_error_message (ev_window, job->error, + "%s", _("Unable to open document")); ev_window_clear_load_job (ev_window); } } @@ -1440,11 +1502,14 @@ ev_window_reload_job_cb (EvJob *job, if (ev_job_is_failed (job)) { ev_window_clear_reload_job (ev_window); ev_window->priv->in_reload = FALSE; + g_object_unref (ev_window->priv->dest); + ev_window->priv->dest = NULL; + return; } ev_window_set_document (ev_window, job->document); - + /* Restart the search after reloading */ widget = gtk_window_get_focus (GTK_WINDOW (ev_window)); if (widget && gtk_widget_get_ancestor (widget, EGG_TYPE_FIND_BAR)) { @@ -1480,10 +1545,6 @@ ev_window_get_uri (EvWindow *ev_window) static void ev_window_close_dialogs (EvWindow *ev_window) { - if (ev_window->priv->password_dialog) - gtk_widget_destroy (ev_window->priv->password_dialog); - ev_window->priv->password_dialog = NULL; - if (ev_window->priv->print_dialog) gtk_widget_destroy (ev_window->priv->print_dialog); ev_window->priv->print_dialog = NULL; @@ -1493,17 +1554,116 @@ 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) { ev_view_set_loading (EV_VIEW (ev_window->priv->view), FALSE); ev_window->priv->in_reload = FALSE; - ev_window_error_message (ev_window, - _("Unable to open document"), - error); + ev_window_error_message (ev_window, error, + "%s", _("Unable to open document")); g_free (ev_window->priv->local_uri); ev_window->priv->local_uri = NULL; + ev_window->priv->uri_mtime = 0; +} + +static void +set_uri_mtime (GFile *source, + GAsyncResult *async_result, + EvWindow *ev_window) +{ + GFileInfo *info; + GError *error = NULL; + + info = g_file_query_info_finish (source, async_result, &error); + + if (error) { + ev_window->priv->uri_mtime = 0; + g_error_free (error); + } else { + GTimeVal mtime; + + g_file_info_get_modification_time (info, &mtime); + ev_window->priv->uri_mtime = mtime.tv_sec; + g_object_unref (info); + } + + g_object_unref (source); } static void @@ -1532,12 +1692,18 @@ 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) { ev_job_scheduler_push_job (ev_window->priv->load_job, EV_JOB_PRIORITY_NONE); - g_object_unref (source); - + g_file_query_info_async (source, + G_FILE_ATTRIBUTE_TIME_MODIFIED, + 0, G_PRIORITY_DEFAULT, + NULL, + (GAsyncReadyCallback)set_uri_mtime, + ev_window); return; } @@ -1552,6 +1718,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); @@ -1561,8 +1737,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; @@ -1581,14 +1780,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 @@ -1622,6 +1828,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 ? @@ -1632,9 +1839,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), @@ -1650,21 +1866,177 @@ ev_window_open_uri (EvWindow *ev_window, } static void -ev_window_reload_document (EvWindow *ev_window) +ev_window_reload_local (EvWindow *ev_window) { const gchar *uri; - - ev_window_clear_reload_job (ev_window); - ev_window->priv->in_reload = TRUE; 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) +{ + 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, + EvWindow *ev_window) +{ + GFileInfo *info; + GTimeVal mtime; + GError *error = NULL; + + info = g_file_query_info_finish (remote, async_result, &error); + if (error) { + g_error_free (error); + g_object_unref (remote); + ev_window_reload_local (ev_window); + + return; + } + + g_file_info_get_modification_time (info, &mtime); + if (ev_window->priv->uri_mtime != mtime.tv_sec) { + GFile *target_file; + + /* 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, + 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); + } + + g_object_unref (info); +} + +static void +ev_window_reload_remote (EvWindow *ev_window) +{ + GFile *remote; + + remote = g_file_new_for_uri (ev_window->priv->uri); + /* Reload the remote uri only if it has changed */ + g_file_query_info_async (remote, + G_FILE_ATTRIBUTE_TIME_MODIFIED, + 0, G_PRIORITY_DEFAULT, + NULL, + (GAsyncReadyCallback)query_remote_uri_mtime_cb, + ev_window); +} + +static void +ev_window_reload_document (EvWindow *ev_window) +{ + gint page; + + + ev_window_clear_reload_job (ev_window); + ev_window->priv->in_reload = TRUE; + + page = ev_page_cache_get_current_page (ev_window->priv->page_cache); + + if (ev_window->priv->dest) + g_object_unref (ev_window->priv->dest); + /* FIXME: save the scroll position too (xyz dest) */ + ev_window->priv->dest = ev_link_dest_new_page (page); + + if (ev_window->priv->local_uri) { + ev_window_reload_remote (ev_window); + } else { + ev_window_reload_local (ev_window); + } +} + static void file_open_dialog_response_cb (GtkWidget *chooser, gint response_id, @@ -1786,10 +2158,8 @@ ev_window_cmd_file_open_copy_at_dest (EvWindow *window, EvLinkDest *dest) new_filename = ev_window_create_tmp_symlink (old_filename, &error); if (error) { - ev_window_error_message (window, - _("Cannot open a copy."), - error); - + ev_window_error_message (window, error, + "%s", _("Cannot open a copy.")); g_error_free (error); g_free (old_filename); g_free (new_filename); @@ -1984,7 +2354,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); @@ -2010,53 +2380,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; - GtkWidget *dialog; - 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 = g_object_get_data (G_OBJECT (dst), "ev-window"); - name = g_file_get_basename (dst); - dialog = gtk_message_dialog_new (GTK_WINDOW (window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_CLOSE, + 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); - gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), - "%s", error->message); - g_signal_connect (dialog, "response", - G_CALLBACK (gtk_widget_destroy), - NULL); - gtk_widget_show (dialog); + 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 @@ -2079,12 +2546,9 @@ ev_window_save_job_cb (EvJob *job, EvWindow *window) { if (ev_job_is_failed (job)) { - gchar *msg; - - msg = g_strdup_printf (_("The file could not be saved as “%s”."), - EV_JOB_SAVE (job)->uri); - ev_window_error_message (window, msg, job->error); - g_free (msg); + ev_window_error_message (window, job->error, + _("The file could not be saved as “%s”."), + EV_JOB_SAVE (job)->uri); } ev_window_clear_save_job (window); @@ -2103,6 +2567,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, @@ -2155,50 +2622,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_clear_print_job (EvWindow *window) -{ - if (window->priv->print_job) { - if (!ev_job_is_finished (window->priv->print_job)) - ev_job_cancel (window->priv->print_job); - - g_signal_handlers_disconnect_by_func (window->priv->print_job, - ev_window_print_job_cb, - window); - g_object_unref (window->priv->print_job); - window->priv->print_job = NULL; - } - - if (window->priv->gtk_print_job) { - g_object_unref (window->priv->gtk_print_job); - window->priv->gtk_print_job = NULL; - } -} - static void ev_window_load_print_settings_from_metadata (EvWindow *window) { @@ -2214,6 +2637,8 @@ ev_window_load_print_settings_from_metadata (EvWindow *window) gtk_print_settings_set (window->priv->print_settings, document_print_settings[i], success ? g_value_get_string (&value) : NULL); + if (success) + g_value_unset (&value); } } @@ -2234,286 +2659,326 @@ ev_window_save_print_settings (EvWindow *window) } static void -ev_window_print_finished (GtkPrintJob *print_job, - EvWindow *window, - GError *error) +ev_window_save_print_page_setup (EvWindow *window) { - ev_window_clear_print_job (window); - - if (error) { - GtkWidget *dialog; - - dialog = gtk_message_dialog_new (GTK_WINDOW (window), - GTK_DIALOG_MODAL, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - _("Failed to print document")); - gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), - "%s", error->message); + gchar *uri = window->priv->uri; + GtkPageSetup *page_setup = window->priv->print_page_setup; - gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); - } else { - /* If printed successfully, save print settings */ - ev_application_set_print_settings (EV_APP, - window->priv->print_settings); - ev_window_save_print_settings (window); - } + /* 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_print_send (EvWindow *window, - const gchar *filename) +ev_window_load_print_page_setup_from_metadata (EvWindow *window) { - GtkPrintSettings *settings; - EvFileExporterCapabilities capabilities; + 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); - /* Some printers take into account some print settings, - * and others don't. However we have exported the document - * to a ps or pdf file according to such print settings. So, - * we want to send the exported file to printer with those - * settings set to default values. - */ - settings = gtk_print_settings_copy (window->priv->print_settings); - capabilities = ev_file_exporter_get_capabilities (EV_FILE_EXPORTER (window->priv->document)); - - gtk_print_settings_set_page_ranges (settings, NULL, 0); - gtk_print_settings_set_print_pages (settings, GTK_PRINT_PAGES_ALL); - if (capabilities & EV_FILE_EXPORTER_CAN_COPIES) - gtk_print_settings_set_n_copies (settings, 1); - if (capabilities & EV_FILE_EXPORTER_CAN_PAGE_SET) - gtk_print_settings_set_page_set (settings, GTK_PAGE_SET_ALL); - if (capabilities & EV_FILE_EXPORTER_CAN_SCALE) - gtk_print_settings_set_scale (settings, 1.0); - if (capabilities & EV_FILE_EXPORTER_CAN_COLLATE) - gtk_print_settings_set_collate (settings, FALSE); - if (capabilities & EV_FILE_EXPORTER_CAN_REVERSE) - gtk_print_settings_set_reverse (settings, FALSE); - if (capabilities & EV_FILE_EXPORTER_CAN_NUMBER_UP) { - gtk_print_settings_set_number_up (settings, 1); - gtk_print_settings_set_int (settings, "cups-"GTK_PRINT_SETTINGS_NUMBER_UP, 1); - } - - if (window->priv->print_preview) { - gchar *uri; - gchar *print_settings_file = NULL; - - ev_application_set_print_settings (EV_APP, - window->priv->print_settings); - - print_settings_file = ev_tmp_filename ("print-settings"); - gtk_print_settings_to_file (settings, print_settings_file, NULL); - - uri = g_filename_to_uri (filename, NULL, NULL); - ev_application_open_uri_at_dest (EV_APP, - uri, - gtk_window_get_screen (GTK_WINDOW (window)), - NULL, - EV_WINDOW_MODE_PREVIEW, - NULL, - TRUE, - print_settings_file, - GDK_CURRENT_TIME); - g_free (print_settings_file); - g_free (uri); + /* 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 { - GtkPrintJob *job; - GError *error = NULL; - - job = gtk_print_job_new (gtk_window_get_title (GTK_WINDOW (window)), - window->priv->printer, - settings, - window->priv->print_page_setup); - - if (window->priv->gtk_print_job) - g_object_unref (window->priv->gtk_print_job); - window->priv->gtk_print_job = job; - - if (gtk_print_job_set_source_file (job, filename, &error)) { - gtk_print_job_send (job, - (GtkPrintJobCompleteFunc)ev_window_print_finished, - window, NULL); - } else { - ev_window_clear_print_job (window); - g_warning ("%s", error->message); - g_error_free (error); - } + 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); } - g_object_unref (settings); + 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_job_cb (EvJob *job, - EvWindow *window) +ev_window_print_page_setup_done_cb (GtkPageSetup *page_setup, + EvWindow *window) { - if (ev_job_is_failed (job)) { - g_warning ("%s", job->error->message); - ev_window_clear_print_job (window); + /* Dialog was canceled */ + if (!page_setup) return; - } - g_assert (EV_JOB_PRINT (job)->temp_file != NULL); + 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); +} - ev_window_print_send (window, EV_JOB_PRINT (job)->temp_file); +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 gboolean -ev_window_print_dialog_response_cb (GtkDialog *dialog, - gint response, - EvWindow *window) +static void +ev_window_print_cancel (EvWindow *ev_window) { - EvPrintRange *ranges = NULL; - EvPrintPageSet page_set; - gint n_ranges = 0; - gint copies; - gint pages_per_sheet; - gboolean collate; - gboolean reverse; - gdouble scale; - gint current_page; - gdouble width; - gdouble height; - GtkPrintPages print_pages; - const gchar *file_format; - - if (response != GTK_RESPONSE_OK && - response != GTK_RESPONSE_APPLY) { - gtk_widget_destroy (GTK_WIDGET (dialog)); - window->priv->print_dialog = NULL; + EvPrintOperation *op; + + if (!ev_window->priv->print_queue) + return; - return FALSE; + while ((op = g_queue_peek_tail (ev_window->priv->print_queue))) { + ev_print_operation_cancel (op); } +} - window->priv->print_preview = (response == GTK_RESPONSE_APPLY); - - if (window->priv->printer) - g_object_unref (window->priv->printer); - if (window->priv->print_settings) - g_object_unref (window->priv->print_settings); - if (window->priv->print_page_setup) - g_object_unref (window->priv->print_page_setup); +static void +ev_window_print_update_pending_jobs_message (EvWindow *ev_window, + gint n_jobs) +{ + gchar *text = NULL; - window->priv->printer = g_object_ref ( - gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (dialog))); - window->priv->print_settings = g_object_ref ( - gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (dialog))); - window->priv->print_page_setup = g_object_ref ( - gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (dialog))); + if (!EV_IS_PROGRESS_MESSAGE_AREA (ev_window->priv->message_area) || + !ev_window->priv->print_queue) + return; - file_format = gtk_print_settings_get (window->priv->print_settings, - GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT); + if (n_jobs == 0) { + ev_window_set_message_area (ev_window, NULL); + return; + } - if (!gtk_printer_accepts_ps (window->priv->printer)) { - GtkWidget *msgdialog; - - msgdialog = gtk_message_dialog_new (GTK_WINDOW (dialog), - GTK_DIALOG_MODAL, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - _("Printing is not supported on this printer.")); - - gtk_dialog_run (GTK_DIALOG (msgdialog)); - gtk_widget_destroy (msgdialog); - - return FALSE; + if (n_jobs > 1) { + text = g_strdup_printf (ngettext ("%d pending job in queue", + "%d pending jobs in queue", + n_jobs - 1), n_jobs - 1); } - ev_window_clear_print_job (window); + ev_message_area_set_secondary_text (EV_MESSAGE_AREA (ev_window->priv->message_area), + text); + g_free (text); +} + +static gboolean +destroy_window (GtkWidget *window) +{ + gtk_widget_destroy (window); - current_page = gtk_print_unix_dialog_get_current_page (GTK_PRINT_UNIX_DIALOG (dialog)); - print_pages = gtk_print_settings_get_print_pages (window->priv->print_settings); + return FALSE; +} + +static void +ev_window_print_operation_done (EvPrintOperation *op, + GtkPrintOperationResult result, + EvWindow *ev_window) +{ + gint n_jobs; - switch (print_pages) { - case GTK_PRINT_PAGES_CURRENT: - ranges = g_new0 (EvPrintRange, 1); + switch (result) { + case GTK_PRINT_OPERATION_RESULT_APPLY: { + GtkPrintSettings *print_settings; - ranges->start = current_page; - ranges->end = current_page; - n_ranges = 1; - - break; - case GTK_PRINT_PAGES_RANGES: { - GtkPageRange *page_range; + print_settings = ev_print_operation_get_print_settings (op); + if (ev_window->priv->print_settings != print_settings) { + if (ev_window->priv->print_settings) + g_object_unref (ev_window->priv->print_settings); + ev_window->priv->print_settings = g_object_ref (print_settings); + } - page_range = gtk_print_settings_get_page_ranges (window->priv->print_settings, - &n_ranges); - if (n_ranges > 0) - ranges = g_memdup (page_range, n_ranges * sizeof (GtkPageRange)); + ev_application_set_print_settings (EV_APP, print_settings); + ev_window_save_print_settings (ev_window); } + break; - case GTK_PRINT_PAGES_ALL: { - gint n_pages; + case GTK_PRINT_OPERATION_RESULT_ERROR: { + GtkWidget *dialog; + GError *error = NULL; - n_pages = ev_page_cache_get_n_pages (ev_page_cache_get (window->priv->document)); - - ranges = g_new0 (EvPrintRange, 1); - ranges->start = 0; - ranges->end = n_pages - 1; - n_ranges = 1; + ev_print_operation_get_error (op, &error); + + /* The message area is already used by + * the printing progress, so it's better to + * use a popup dialog in this case + */ + dialog = gtk_message_dialog_new (GTK_WINDOW (ev_window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "%s", _("Failed to print document")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", error->message); + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_widget_destroy), + NULL); + gtk_widget_show (dialog); + + g_error_free (error); } break; + case GTK_PRINT_OPERATION_RESULT_CANCEL: + default: + break; } - page_set = (EvPrintPageSet)gtk_print_settings_get_page_set (window->priv->print_settings); + g_queue_remove (ev_window->priv->print_queue, op); + g_object_unref (op); + n_jobs = g_queue_get_length (ev_window->priv->print_queue); + ev_window_print_update_pending_jobs_message (ev_window, n_jobs); - scale = gtk_print_settings_get_scale (window->priv->print_settings) * 0.01; - - width = gtk_page_setup_get_paper_width (window->priv->print_page_setup, - GTK_UNIT_POINTS); - height = gtk_page_setup_get_paper_height (window->priv->print_page_setup, - GTK_UNIT_POINTS); - - if (scale != 1.0) { - width *= scale; - height *= scale; + if (n_jobs == 0 && ev_window->priv->close_after_print) + g_idle_add ((GSourceFunc)destroy_window, + ev_window); +} + +static void +ev_window_print_progress_response_cb (EvProgressMessageArea *area, + gint response, + EvWindow *ev_window) +{ + if (response == GTK_RESPONSE_CANCEL) { + EvPrintOperation *op; + + op = g_queue_peek_tail (ev_window->priv->print_queue); + ev_print_operation_cancel (op); + } else { + gtk_widget_hide (GTK_WIDGET (area)); } +} - pages_per_sheet = gtk_print_settings_get_number_up (window->priv->print_settings); - - copies = gtk_print_settings_get_n_copies (window->priv->print_settings); - collate = gtk_print_settings_get_collate (window->priv->print_settings); - reverse = gtk_print_settings_get_reverse (window->priv->print_settings); - - window->priv->print_job = ev_job_print_new (window->priv->document, - file_format ? file_format : "ps", - width, height, - ranges, n_ranges, - page_set, - pages_per_sheet, - copies, collate, - reverse); +static void +ev_window_print_operation_status_changed (EvPrintOperation *op, + EvWindow *ev_window) +{ + const gchar *status; + gdouble fraction; + + status = ev_print_operation_get_status (op); + fraction = ev_print_operation_get_progress (op); - g_signal_connect (window->priv->print_job, "finished", - G_CALLBACK (ev_window_print_job_cb), - window); - /* The priority doesn't matter for this job */ - ev_job_scheduler_push_job (window->priv->print_job, EV_JOB_PRIORITY_NONE); + if (!ev_window->priv->message_area) { + GtkWidget *area; + const gchar *job_name; + gchar *text; + + job_name = ev_print_operation_get_job_name (op); + text = g_strdup_printf (_("Printing job “%s”"), job_name); + + area = ev_progress_message_area_new (GTK_STOCK_PRINT, + text, + GTK_STOCK_CLOSE, + GTK_RESPONSE_CLOSE, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + NULL); + ev_window_print_update_pending_jobs_message (ev_window, 1); + g_signal_connect (area, "response", + G_CALLBACK (ev_window_print_progress_response_cb), + ev_window); + gtk_widget_show (area); + ev_window_set_message_area (ev_window, area); + g_free (text); + } + + 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); +} + +static void +ev_window_print_operation_begin_print (EvPrintOperation *op, + EvWindow *ev_window) +{ + GtkPrintSettings *print_settings; - gtk_widget_destroy (GTK_WIDGET (dialog)); - window->priv->print_dialog = NULL; + if (!ev_window->priv->print_queue) + ev_window->priv->print_queue = g_queue_new (); - return TRUE; + g_queue_push_head (ev_window->priv->print_queue, op); + ev_window_print_update_pending_jobs_message (ev_window, + g_queue_get_length (ev_window->priv->print_queue)); + + if (ev_window->priv->print_settings) + g_object_unref (ev_window->priv->print_settings); + print_settings = ev_print_operation_get_print_settings (op); + ev_window->priv->print_settings = g_object_ref (print_settings); } void -ev_window_print_range (EvWindow *ev_window, int first_page, int last_page) +ev_window_print_range (EvWindow *ev_window, + gint first_page, + gint last_page) { - GtkWidget *dialog; - EvPageCache *page_cache; - gint current_page; - gint document_last_page; - GtkPrintCapabilities capabilities; + EvPrintOperation *op; + EvPageCache *page_cache; + gint current_page; + gint document_last_page; g_return_if_fail (EV_IS_WINDOW (ev_window)); g_return_if_fail (ev_window->priv->document != NULL); - if (ev_window->priv->print_dialog) { - gtk_window_present (GTK_WINDOW (ev_window->priv->print_dialog)); - return; - } - + if (!ev_window->priv->print_queue) + ev_window->priv->print_queue = g_queue_new (); + + op = ev_print_operation_new (ev_window->priv->document); + g_signal_connect (op, "begin_print", + G_CALLBACK (ev_window_print_operation_begin_print), + (gpointer)ev_window); + g_signal_connect (op, "status_changed", + G_CALLBACK (ev_window_print_operation_status_changed), + (gpointer)ev_window); + g_signal_connect (op, "done", + G_CALLBACK (ev_window_print_operation_done), + (gpointer)ev_window); + page_cache = ev_page_cache_get (ev_window->priv->document); current_page = ev_page_cache_get_current_page (page_cache); document_last_page = ev_page_cache_get_n_pages (page_cache); @@ -2537,29 +3002,13 @@ ev_window_print_range (EvWindow *ev_window, int first_page, int last_page) &range, 1); } - dialog = gtk_print_unix_dialog_new (_("Print"), GTK_WINDOW (ev_window)); - ev_window->priv->print_dialog = dialog; - - capabilities = GTK_PRINT_CAPABILITY_PREVIEW | - ev_file_exporter_get_capabilities (EV_FILE_EXPORTER (ev_window->priv->document)); - gtk_print_unix_dialog_set_manual_capabilities (GTK_PRINT_UNIX_DIALOG (dialog), - capabilities); - - gtk_print_unix_dialog_set_current_page (GTK_PRINT_UNIX_DIALOG (dialog), - current_page); - - gtk_print_unix_dialog_set_settings (GTK_PRINT_UNIX_DIALOG (dialog), - ev_window->priv->print_settings); - + ev_print_operation_set_job_name (op, gtk_window_get_title (GTK_WINDOW (ev_window))); + ev_print_operation_set_current_page (op, current_page); + ev_print_operation_set_print_settings (op, ev_window->priv->print_settings); if (ev_window->priv->print_page_setup) - gtk_print_unix_dialog_set_page_setup (GTK_PRINT_UNIX_DIALOG (dialog), - ev_window->priv->print_page_setup); - - g_signal_connect (G_OBJECT (dialog), "response", - G_CALLBACK (ev_window_print_dialog_response_cb), - ev_window); + ev_print_operation_set_default_page_setup (op, ev_window->priv->print_page_setup); - gtk_widget_show (dialog); + ev_print_operation_run (op, GTK_WINDOW (ev_window)); } static void @@ -2586,6 +3035,7 @@ ev_window_cmd_file_properties (GtkAction *action, EvWindow *ev_window) if (ev_window->priv->properties == NULL) { ev_window->priv->properties = ev_properties_dialog_new (); ev_properties_dialog_set_document (EV_PROPERTIES_DIALOG (ev_window->priv->properties), + ev_window->priv->uri, ev_window->priv->document); g_object_add_weak_pointer (G_OBJECT (ev_window->priv->properties), (gpointer) &(ev_window->priv->properties)); @@ -2597,13 +3047,97 @@ ev_window_cmd_file_properties (GtkAction *action, EvWindow *ev_window) gtk_widget_show (ev_window->priv->properties); ev_document_fc_mutex_unlock (); } - + +static void +print_jobs_confirmation_dialog_response (GtkDialog *dialog, + gint response, + EvWindow *ev_window) +{ + gtk_widget_destroy (GTK_WIDGET (dialog)); + + switch (response) { + case GTK_RESPONSE_YES: + if (!ev_window->priv->print_queue || + g_queue_is_empty (ev_window->priv->print_queue)) + gtk_widget_destroy (GTK_WIDGET (ev_window)); + else + ev_window->priv->close_after_print = TRUE; + break; + case GTK_RESPONSE_NO: + ev_window->priv->close_after_print = TRUE; + if (ev_window->priv->print_queue && + !g_queue_is_empty (ev_window->priv->print_queue)) { + gtk_widget_set_sensitive (GTK_WIDGET (ev_window), FALSE); + ev_window_print_cancel (ev_window); + } else { + gtk_widget_destroy (GTK_WIDGET (ev_window)); + } + break; + case GTK_RESPONSE_CANCEL: + default: + ev_window->priv->close_after_print = FALSE; + } +} + static void ev_window_cmd_file_close_window (GtkAction *action, EvWindow *ev_window) { - g_return_if_fail (EV_IS_WINDOW (ev_window)); + GtkWidget *dialog; + gchar *text, *markup; + gint n_print_jobs; + + n_print_jobs = ev_window->priv->print_queue ? + g_queue_get_length (ev_window->priv->print_queue) : 0; + + if (n_print_jobs == 0) { + gtk_widget_destroy (GTK_WIDGET (ev_window)); + return; + } + + dialog = gtk_message_dialog_new (GTK_WINDOW (ev_window), + GTK_DIALOG_MODAL, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, + NULL); + if (n_print_jobs == 1) { + EvPrintOperation *op; + const gchar *job_name; + + op = g_queue_peek_tail (ev_window->priv->print_queue); + job_name = ev_print_operation_get_job_name (op); + + text = g_strdup_printf (_("Wait until print job “%s” finishes before closing?"), + job_name); + } else { + text = g_strdup_printf (_("There are %d print jobs active. " + "Wait until print finishes before closing?"), + n_print_jobs); + } + + markup = g_strdup_printf ("%s", text); + g_free (text); + + gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), markup); + g_free (markup); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", + _("If you close the window, pending print " + "jobs will not be printed.")); + + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + _("Cancel _print and Close"), + GTK_RESPONSE_NO, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + _("Close _after Printing"), + GTK_RESPONSE_YES, + NULL); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES); - gtk_widget_destroy (GTK_WIDGET (ev_window)); + g_signal_connect (dialog, "response", + G_CALLBACK (print_jobs_confirmation_dialog_response), + ev_window); + gtk_widget_show (dialog); } static void @@ -3329,9 +3863,8 @@ ev_window_cmd_help_contents (GtkAction *action, EvWindow *ev_window) GDK_CURRENT_TIME, &error); if (error) { - ev_window_error_message (ev_window, - _("There was an error displaying help"), - error); + ev_window_error_message (ev_window, error, + "%s", _("There was an error displaying help")); g_error_free (error); } } @@ -3428,18 +3961,8 @@ ev_window_preview_print_finished (GtkPrintJob *print_job, GError *error) { if (error) { - GtkWidget *dialog; - - dialog = gtk_message_dialog_new (GTK_WINDOW (window), - GTK_DIALOG_MODAL, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - _("Failed to print document")); - gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), - "%s", error->message); - - gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); + ev_window_error_message (window, error, + "%s", _("Failed to print document")); } g_object_unref (print_job); @@ -3450,7 +3973,6 @@ static void ev_window_do_preview_print (EvWindow *window) { EvWindowPrivate *priv = window->priv; - GtkPageSetup *page_setup; GtkPrintJob *job; gchar *filename; GError *error = NULL; @@ -3458,18 +3980,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, @@ -3492,31 +4013,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); @@ -3564,7 +4104,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", @@ -3843,6 +4383,8 @@ ev_window_sidebar_current_page_changed_cb (EvSidebar *ev_sidebar, id = THUMBNAILS_SIDEBAR_ID; } else if (current_page == ev_window->priv->sidebar_attachments) { id = ATTACHMENTS_SIDEBAR_ID; + } else if (current_page == ev_window->priv->sidebar_layers) { + id = LAYERS_SIDEBAR_ID; } else { g_assert_not_reached(); } @@ -4186,6 +4728,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) { @@ -4307,14 +4883,14 @@ ev_window_dispose (GObject *object) priv->local_uri = NULL; } - ev_window_close_dialogs (window); - ev_window_clear_print_job (window); - - if (window->priv->gtk_print_job) { - g_object_unref (window->priv->gtk_print_job); - window->priv->gtk_print_job = 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) { g_object_unref (window->priv->printer); window->priv->printer = NULL; @@ -4363,6 +4939,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; @@ -4383,6 +4964,11 @@ ev_window_dispose (GObject *object) priv->presentation_timeout_id = 0; } + if (priv->print_queue) { + g_queue_free (priv->print_queue); + priv->print_queue = NULL; + } + G_OBJECT_CLASS (ev_window_parent_class)->dispose (object); } @@ -4397,6 +4983,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)); } @@ -4616,6 +5203,13 @@ navigation_action_activate_link_cb (EvNavigationAction *action, EvLink *link, Ev gtk_widget_grab_focus (window->priv->view); } +static void +sidebar_layers_visibility_changed (EvSidebarLayers *layers, + EvWindow *window) +{ + ev_view_reload (EV_VIEW (window->priv->view)); +} + static void register_custom_actions (EvWindow *window, GtkActionGroup *group) { @@ -4868,9 +5462,11 @@ launch_action (EvWindow *window, EvLinkAction *action) app_info = g_file_query_default_handler (file, NULL, &error); if (!app_info) { - /* FIXME: use ev_window_error_message */ - g_warning ("%s", error->message); + ev_window_error_message (window, error, + "%s", + _("Unable to launch external application.")); g_object_unref (file); + g_error_free (error); return; } @@ -4884,8 +5480,9 @@ launch_action (EvWindow *window, EvLinkAction *action) file_list.data = file; if (!g_app_info_launch (app_info, &file_list, context, &error)) { - /* FIXME: use ev_window_error_message */ - g_warning ("%s", error->message); + ev_window_error_message (window, error, + "%s", + _("Unable to launch external application.")); g_error_free (error); } @@ -4900,9 +5497,11 @@ static void launch_external_uri (EvWindow *window, EvLinkAction *action) { const gchar *uri = ev_link_action_get_uri (action); - GAppLaunchContext *context = NULL; GError *error = NULL; gboolean ret; +#if GTK_CHECK_VERSION (2, 14, 0) + GAppLaunchContext *context = NULL; +#endif #if GTK_CHECK_VERSION (2, 14, 0) context = G_APP_LAUNCH_CONTEXT (gdk_app_launch_context_new ()); @@ -4925,9 +5524,8 @@ launch_external_uri (EvWindow *window, EvLinkAction *action) } if (ret == FALSE) { - ev_window_error_message (window, - _("Unable to open external link"), - error); + ev_window_error_message (window, error, + "%s", _("Unable to open external link")); g_error_free (error); } } @@ -5081,9 +5679,9 @@ image_save_dialog_response_cb (GtkWidget *fc, } if (format == NULL) { - ev_window_error_message (ev_window, - _("Couldn't find appropriate format to save image"), - NULL); + ev_window_error_message (ev_window, NULL, + "%s", + _("Couldn't find appropriate format to save image")); g_free (uri); gtk_widget_destroy (fc); @@ -5121,9 +5719,8 @@ image_save_dialog_response_cb (GtkWidget *fc, g_object_unref (pixbuf); if (error) { - ev_window_error_message (ev_window, - _("The image could not be saved."), - error); + ev_window_error_message (ev_window, error, + "%s", _("The image could not be saved.")); g_error_free (error); g_free (filename); g_object_unref (target_file); @@ -5135,9 +5732,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); } @@ -5215,9 +5813,8 @@ ev_attachment_popup_cmd_open_attachment (GtkAction *action, EvWindow *window) ev_attachment_open (attachment, screen, GDK_CURRENT_TIME, &error); if (error) { - ev_window_error_message (window, - _("Unable to open attachment"), - error); + ev_window_error_message (window, error, + "%s", _("Unable to open attachment")); g_error_free (error); } } @@ -5267,9 +5864,8 @@ attachment_save_dialog_response_cb (GtkWidget *fc, ev_attachment_save (attachment, save_to, &error); if (error) { - ev_window_error_message (ev_window, - _("The attachment could not be saved."), - error); + ev_window_error_message (ev_window, error, + "%s", _("The attachment could not be saved.")); g_error_free (error); g_object_unref (save_to); @@ -5286,7 +5882,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); } @@ -5518,6 +6115,16 @@ ev_window_init (EvWindow *ev_window) ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar), sidebar_widget); + sidebar_widget = ev_sidebar_layers_new (); + ev_window->priv->sidebar_layers = sidebar_widget; + g_signal_connect (sidebar_widget, + "layers_visibility_changed", + G_CALLBACK (sidebar_layers_visibility_changed), + ev_window); + gtk_widget_show (sidebar_widget); + ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar), + sidebar_widget); + ev_window->priv->view_box = gtk_vbox_new (FALSE, 0); ev_window->priv->scrolled_window = GTK_WIDGET (g_object_new (GTK_TYPE_SCROLLED_WINDOW, @@ -5535,10 +6142,10 @@ ev_window_init (EvWindow *ev_window) ev_window->priv->view = ev_view_new (); ev_view_set_screen_dpi (EV_VIEW (ev_window->priv->view), get_screen_dpi (GTK_WINDOW (ev_window))); - ev_window->priv->password_view = ev_password_view_new (); + ev_window->priv->password_view = ev_password_view_new (GTK_WINDOW (ev_window)); g_signal_connect_swapped (ev_window->priv->password_view, "unlock", - G_CALLBACK (ev_window_popup_password_dialog), + G_CALLBACK (ev_window_password_view_unlock), ev_window); g_signal_connect_object (ev_window->priv->view, "focus_in_event", G_CALLBACK (view_actions_focus_in_cb), @@ -5668,10 +6275,17 @@ ev_window_init (EvWindow *ev_window) gtk_window_set_default_size (GTK_WINDOW (ev_window), 600, 600); setup_view_from_metadata (ev_window); - setup_sidebar_from_metadata (ev_window, NULL); + setup_sidebar_from_metadata (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)); } /**