+ setup_size_from_metadata (ev_window);
+ setup_model_from_metadata (ev_window);
+
+ 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),
+ ev_window);
+
+ if (!g_file_is_native (source_file) && !ev_window->priv->local_uri) {
+ ev_window_load_file_remote (ev_window, source_file);
+ } else {
+ g_object_unref (source_file);
+ ev_job_scheduler_push_job (ev_window->priv->load_job, EV_JOB_PRIORITY_NONE);
+ }
+}
+
+void
+ev_window_open_document (EvWindow *ev_window,
+ EvDocument *document,
+ EvLinkDest *dest,
+ EvWindowRunMode mode,
+ const gchar *search_string)
+{
+ if (document == ev_window->priv->document)
+ return;
+
+ ev_window_close_dialogs (ev_window);
+ ev_window_clear_load_job (ev_window);
+ ev_window_clear_local_uri (ev_window);
+
+ if (ev_window->priv->monitor) {
+ g_object_unref (ev_window->priv->monitor);
+ ev_window->priv->monitor = NULL;
+ }
+
+ if (ev_window->priv->uri)
+ g_free (ev_window->priv->uri);
+ ev_window->priv->uri = g_strdup (ev_document_get_uri (document));
+
+ setup_size_from_metadata (ev_window);
+ setup_model_from_metadata (ev_window);
+
+ ev_document_model_set_document (ev_window->priv->model, document);
+
+ setup_document_from_metadata (ev_window);
+ setup_view_from_metadata (ev_window);
+
+ if (dest) {
+ EvLink *link;
+ EvLinkAction *link_action;
+
+ link_action = ev_link_action_new_dest (dest);
+ link = ev_link_new (NULL, link_action);
+ ev_view_handle_link (EV_VIEW (ev_window->priv->view), link);
+ /* FIXME: link action should inc dest ref counting
+ * or not unref it at all
+ */
+ g_object_ref (dest);
+ g_object_unref (link);
+ }
+
+ switch (mode) {
+ case EV_WINDOW_MODE_FULLSCREEN:
+ ev_window_run_fullscreen (ev_window);
+ break;
+ case EV_WINDOW_MODE_PRESENTATION:
+ ev_window_run_presentation (ev_window);
+ break;
+ default:
+ break;
+ }
+
+ if (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),
+ search_string);
+ }
+
+ /* Create a monitor for the document */
+ 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);
+}
+
+static void
+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);
+ 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 (!g_error_matches (error, G_IO_ERROR, 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;
+
+ if (total_bytes <= 0)
+ 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,
+ EvLinkDest *dest)
+{
+ gint page;
+
+
+ ev_window_clear_reload_job (ev_window);
+ ev_window->priv->in_reload = TRUE;
+
+ page = ev_document_model_get_page (ev_window->priv->model);
+
+ if (ev_window->priv->dest)
+ g_object_unref (ev_window->priv->dest);
+ ev_window->priv->dest = dest ? g_object_ref (dest) : NULL;
+
+ 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,
+ EvWindow *ev_window)
+{
+ if (response_id == GTK_RESPONSE_OK) {
+ GSList *uris;
+ gchar *uri;
+
+ uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (chooser));
+
+ ev_application_open_uri_list (EV_APP, uris,
+ gtk_window_get_screen (GTK_WINDOW (ev_window)),
+ gtk_get_current_event_time ());
+
+ g_slist_foreach (uris, (GFunc)g_free, NULL);
+ g_slist_free (uris);
+
+ uri = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (chooser));
+ ev_application_set_filechooser_uri (EV_APP,
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ uri);
+ g_free (uri);
+ }
+
+ gtk_widget_destroy (chooser);
+}
+
+static void
+ev_window_cmd_file_open (GtkAction *action, EvWindow *window)
+{
+ GtkWidget *chooser;
+ const gchar *default_uri;
+ gchar *parent_uri = NULL;
+
+ chooser = gtk_file_chooser_dialog_new (_("Open Document"),
+ GTK_WINDOW (window),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_OK,
+ NULL);
+
+ ev_document_factory_add_filters (chooser, NULL);
+ gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (chooser), TRUE);
+ gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), FALSE);
+
+ default_uri = ev_application_get_filechooser_uri (EV_APP, GTK_FILE_CHOOSER_ACTION_OPEN);
+ if (!default_uri && window->priv->uri) {
+ GFile *file, *parent;
+
+ file = g_file_new_for_uri (window->priv->uri);
+ parent = g_file_get_parent (file);
+ if (parent) {
+ parent_uri = g_file_get_uri (parent);
+ default_uri = parent_uri;
+ g_object_unref (parent);
+ }
+ g_object_unref (file);
+ }
+
+ if (default_uri) {
+ gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (chooser), default_uri);
+ } else {
+ const gchar *folder;
+
+ folder = g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS);
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser),
+ folder ? folder : g_get_home_dir ());
+ }
+ g_free (parent_uri);
+
+ g_signal_connect (chooser, "response",
+ G_CALLBACK (file_open_dialog_response_cb),
+ window);
+
+ gtk_widget_show (chooser);
+}
+
+static void
+ev_window_open_copy_at_dest (EvWindow *window,
+ EvLinkDest *dest)
+{
+ EvWindow *new_window = EV_WINDOW (ev_window_new ());
+
+ ev_window_n_copies++;
+
+ if (window->priv->metadata)
+ new_window->priv->metadata = g_object_ref (window->priv->metadata);
+ ev_window_open_document (new_window,
+ window->priv->document,
+ dest, 0, NULL);
+ gtk_window_present (GTK_WINDOW (new_window));
+}
+
+static void
+ev_window_cmd_file_open_copy (GtkAction *action, EvWindow *window)
+{
+ ev_window_open_copy_at_dest (window, NULL);
+}
+
+static void
+ev_window_cmd_recent_file_activate (GtkAction *action,
+ EvWindow *window)
+{
+ GtkRecentInfo *info;
+ const gchar *uri;
+
+ info = g_object_get_data (G_OBJECT (action), "gtk-recent-info");
+ g_assert (info != NULL);
+
+ uri = gtk_recent_info_get_uri (info);
+
+ ev_application_open_uri_at_dest (EV_APP, uri,
+ gtk_window_get_screen (GTK_WINDOW (window)),
+ NULL, 0, NULL, gtk_get_current_event_time ());
+}
+
+static void
+ev_window_open_recent_action_item_activated (EvOpenRecentAction *action,
+ const gchar *uri,
+ EvWindow *window)
+{
+ ev_application_open_uri_at_dest (EV_APP, uri,
+ gtk_window_get_screen (GTK_WINDOW (window)),
+ NULL, 0, NULL, gtk_get_current_event_time ());
+}
+
+static void
+ev_window_add_recent (EvWindow *window, const char *filename)
+{
+ gtk_recent_manager_add_item (window->priv->recent_manager, filename);
+}
+
+static gint
+compare_recent_items (GtkRecentInfo *a, GtkRecentInfo *b)
+{
+ gboolean has_ev_a, has_ev_b;
+ const gchar *evince = g_get_application_name ();
+
+ has_ev_a = gtk_recent_info_has_application (a, evince);
+ has_ev_b = gtk_recent_info_has_application (b, evince);
+
+ if (has_ev_a && has_ev_b) {
+ time_t time_a, time_b;
+
+ time_a = gtk_recent_info_get_modified (a);
+ time_b = gtk_recent_info_get_modified (b);
+
+ return (time_b - time_a);
+ } else if (has_ev_a) {
+ return -1;
+ } else if (has_ev_b) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Doubles underscore to avoid spurious menu accels.
+ */
+static gchar *
+ev_window_get_recent_file_label (gint index, const gchar *filename)
+{
+ GString *str;
+ gint length;
+ const gchar *p;
+ const gchar *end;
+ gboolean is_rtl;
+
+ is_rtl = (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL);
+
+ g_return_val_if_fail (filename != NULL, NULL);
+
+ length = strlen (filename);
+ str = g_string_sized_new (length + 10);
+ g_string_printf (str, "%s_%d. ", is_rtl ? "\xE2\x80\x8F" : "", index);
+
+ p = filename;
+ end = filename + length;
+
+ while (p != end) {
+ const gchar *next;
+ next = g_utf8_next_char (p);
+
+ switch (*p) {
+ case '_':
+ g_string_append (str, "__");
+ break;
+ default:
+ g_string_append_len (str, p, next - p);
+ break;
+ }
+
+ p = next;
+ }
+
+ return g_string_free (str, FALSE);
+}
+
+static void
+ev_window_setup_recent (EvWindow *ev_window)
+{
+ GList *items, *l;
+ guint n_items = 0;
+ const gchar *evince = g_get_application_name ();
+ static guint i = 0;
+
+ if (ev_window->priv->recent_ui_id > 0) {
+ gtk_ui_manager_remove_ui (ev_window->priv->ui_manager,
+ ev_window->priv->recent_ui_id);
+ gtk_ui_manager_ensure_update (ev_window->priv->ui_manager);
+ }
+ ev_window->priv->recent_ui_id = gtk_ui_manager_new_merge_id (ev_window->priv->ui_manager);
+
+ if (ev_window->priv->recent_action_group) {
+ gtk_ui_manager_remove_action_group (ev_window->priv->ui_manager,
+ ev_window->priv->recent_action_group);
+ g_object_unref (ev_window->priv->recent_action_group);
+ }
+ ev_window->priv->recent_action_group = gtk_action_group_new ("RecentFilesActions");
+ gtk_ui_manager_insert_action_group (ev_window->priv->ui_manager,
+ ev_window->priv->recent_action_group, 0);
+
+ items = gtk_recent_manager_get_items (ev_window->priv->recent_manager);
+ items = g_list_sort (items, (GCompareFunc) compare_recent_items);
+
+ for (l = items; l && l->data; l = g_list_next (l)) {
+ GtkRecentInfo *info;
+ GtkAction *action;
+ gchar *action_name;
+ gchar *label;
+
+ info = (GtkRecentInfo *) l->data;
+
+ if (!gtk_recent_info_has_application (info, evince) ||
+ (gtk_recent_info_is_local (info) && !gtk_recent_info_exists (info)))
+ continue;
+
+ action_name = g_strdup_printf ("RecentFile%u", i++);
+ label = ev_window_get_recent_file_label (
+ n_items + 1, gtk_recent_info_get_display_name (info));
+
+ action = g_object_new (GTK_TYPE_ACTION,
+ "name", action_name,
+ "label", label,
+ NULL);
+
+ g_object_set_data_full (G_OBJECT (action),
+ "gtk-recent-info",
+ gtk_recent_info_ref (info),
+ (GDestroyNotify) gtk_recent_info_unref);
+
+ g_signal_connect (action, "activate",
+ G_CALLBACK (ev_window_cmd_recent_file_activate),
+ (gpointer) ev_window);
+
+ gtk_action_group_add_action (ev_window->priv->recent_action_group,
+ action);
+ g_object_unref (action);
+
+ gtk_ui_manager_add_ui (ev_window->priv->ui_manager,
+ ev_window->priv->recent_ui_id,
+ "/MainMenu/FileMenu/RecentFilesMenu",
+ label,
+ action_name,
+ GTK_UI_MANAGER_MENUITEM,
+ FALSE);
+ g_free (action_name);
+ g_free (label);
+
+ if (++n_items == 5)
+ break;
+ }
+
+ g_list_foreach (items, (GFunc) gtk_recent_info_unref, NULL);
+ 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 *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;
+ }
+
+ if (!g_error_matches (error, G_IO_ERROR, 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_error_free (error);
+}
+
+static void
+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;
+
+ if (total_bytes <= 0)
+ 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,
+ 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
+ev_window_clear_save_job (EvWindow *ev_window)
+{
+ if (ev_window->priv->save_job != NULL) {
+ if (!ev_job_is_finished (ev_window->priv->save_job))
+ ev_job_cancel (ev_window->priv->save_job);
+
+ g_signal_handlers_disconnect_by_func (ev_window->priv->save_job,
+ ev_window_save_job_cb,
+ ev_window);
+ g_object_unref (ev_window->priv->save_job);
+ ev_window->priv->save_job = NULL;
+ }
+}
+
+static void
+ev_window_save_job_cb (EvJob *job,
+ EvWindow *window)
+{
+ if (ev_job_is_failed (job)) {
+ 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);
+}
+
+static void
+file_save_dialog_response_cb (GtkWidget *fc,
+ gint response_id,
+ EvWindow *ev_window)
+{
+ gchar *uri;
+ GFile *file, *parent;
+
+ if (response_id != GTK_RESPONSE_OK) {
+ gtk_widget_destroy (fc);
+ return;
+ }
+
+ uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (fc));
+ file = g_file_new_for_uri (uri);
+ parent = g_file_get_parent (file);
+ g_object_unref (file);
+ if (parent) {
+ gchar *folder_uri;
+
+ folder_uri = g_file_get_uri (parent);
+ ev_application_set_filechooser_uri (EV_APP,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ folder_uri);
+ g_free (folder_uri);
+ g_object_unref (parent);
+ }
+
+ /* 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,
+ uri, ev_window->priv->uri);
+ g_signal_connect (ev_window->priv->save_job, "finished",
+ G_CALLBACK (ev_window_save_job_cb),
+ ev_window);
+ /* The priority doesn't matter for this job */
+ ev_job_scheduler_push_job (ev_window->priv->save_job, EV_JOB_PRIORITY_NONE);
+
+ g_free (uri);
+ gtk_widget_destroy (fc);
+}
+
+static void
+ev_window_cmd_save_as (GtkAction *action, EvWindow *ev_window)
+{
+ GtkWidget *fc;
+ gchar *base_name;
+ GFile *file;
+ const gchar *default_uri;
+
+ fc = gtk_file_chooser_dialog_new (
+ _("Save a Copy"),
+ GTK_WINDOW (ev_window), GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_OK,
+ NULL);
+
+ ev_document_factory_add_filters (fc, ev_window->priv->document);
+ gtk_dialog_set_default_response (GTK_DIALOG (fc), GTK_RESPONSE_OK);
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (fc),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (fc), FALSE);
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (fc), TRUE);
+ file = g_file_new_for_uri (ev_window->priv->uri);
+ base_name = g_file_get_basename (file);
+ gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (fc), base_name);
+
+ default_uri = ev_application_get_filechooser_uri (EV_APP, GTK_FILE_CHOOSER_ACTION_SAVE);
+ if (default_uri) {
+ gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (fc), default_uri);
+ } else {
+ const gchar *folder;
+
+ folder = g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS);
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (fc),
+ folder ? folder : g_get_home_dir ());
+ }
+
+ g_object_unref (file);
+ g_free (base_name);
+
+ g_signal_connect (fc, "response",
+ G_CALLBACK (file_save_dialog_response_cb),
+ ev_window);
+
+ gtk_widget_show (fc);
+}
+
+static GKeyFile *
+get_print_settings_file (void)
+{
+ GKeyFile *print_settings_file;
+ gchar *filename;
+ GError *error = NULL;
+
+ print_settings_file = g_key_file_new ();
+
+ filename = g_build_filename (ev_application_get_dot_dir (EV_APP, FALSE),
+ EV_PRINT_SETTINGS_FILE, NULL);
+ if (!g_key_file_load_from_file (print_settings_file,
+ filename,
+ G_KEY_FILE_KEEP_COMMENTS |
+ G_KEY_FILE_KEEP_TRANSLATIONS,
+ &error)) {
+
+ /* Don't warn if the file simply doesn't exist */
+ if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
+ g_warning ("%s", error->message);
+
+ g_error_free (error);
+ }
+
+ g_free (filename);
+
+ return print_settings_file;
+}
+
+static void
+save_print_setting_file (GKeyFile *key_file)
+{
+ gchar *filename;
+ gchar *data;
+ gsize data_length;
+ GError *error = NULL;
+
+ filename = g_build_filename (ev_application_get_dot_dir (EV_APP, TRUE),
+ EV_PRINT_SETTINGS_FILE, NULL);
+ data = g_key_file_to_data (key_file, &data_length, NULL);
+ g_file_set_contents (filename, data, data_length, &error);
+ if (error) {
+ g_warning ("Failed to save print settings: %s", error->message);
+ g_error_free (error);
+ }
+ g_free (data);
+ g_free (filename);
+}
+
+static void
+ev_window_save_print_settings (EvWindow *window,
+ GtkPrintSettings *print_settings)
+{
+ GKeyFile *key_file;
+ gint i;
+
+ key_file = get_print_settings_file ();
+ gtk_print_settings_to_key_file (print_settings, key_file, EV_PRINT_SETTINGS_GROUP);
+ save_print_setting_file (key_file);
+ g_key_file_free (key_file);
+
+ if (!window->priv->metadata)
+ return;
+
+ /* Save print settings that are specific to the document */
+ for (i = 0; i < G_N_ELEMENTS (document_print_settings); i++) {
+ const gchar *value;
+
+ value = gtk_print_settings_get (print_settings,
+ document_print_settings[i]);
+ ev_metadata_set_string (window->priv->metadata,
+ document_print_settings[i], value);
+ }
+}
+
+static void
+ev_window_save_print_page_setup (EvWindow *window,
+ GtkPageSetup *page_setup)
+{
+ GKeyFile *key_file;
+
+ key_file = get_print_settings_file ();
+ gtk_page_setup_to_key_file (page_setup, key_file, EV_PAGE_SETUP_GROUP);
+ save_print_setting_file (key_file);
+ g_key_file_free (key_file);
+
+ if (!window->priv->metadata)
+ return;
+
+ /* Save page setup options that are specific to the document */
+ ev_metadata_set_int (window->priv->metadata, "page-setup-orientation",
+ gtk_page_setup_get_orientation (page_setup));
+ ev_metadata_set_double (window->priv->metadata, "page-setup-margin-top",
+ gtk_page_setup_get_top_margin (page_setup, GTK_UNIT_MM));
+ ev_metadata_set_double (window->priv->metadata, "page-setup-margin-bottom",
+ gtk_page_setup_get_bottom_margin (page_setup, GTK_UNIT_MM));
+ ev_metadata_set_double (window->priv->metadata, "page-setup-margin-left",
+ gtk_page_setup_get_left_margin (page_setup, GTK_UNIT_MM));
+ ev_metadata_set_double (window->priv->metadata, "page-setup-margin-right",
+ gtk_page_setup_get_right_margin (page_setup, GTK_UNIT_MM));
+}
+
+static void
+ev_window_load_print_settings_from_metadata (EvWindow *window,
+ GtkPrintSettings *print_settings)
+{
+ gint i;
+
+ if (!window->priv->metadata)
+ return;
+
+ /* Load print setting that are specific to the document */
+ for (i = 0; i < G_N_ELEMENTS (document_print_settings); i++) {
+ gchar *value = NULL;
+
+ ev_metadata_get_string (window->priv->metadata,
+ document_print_settings[i], &value);
+ gtk_print_settings_set (print_settings,
+ document_print_settings[i], value);
+ }
+}
+
+static void
+ev_window_load_print_page_setup_from_metadata (EvWindow *window,
+ GtkPageSetup *page_setup)
+{
+ gint int_value;
+ gdouble double_value;
+ GtkPaperSize *paper_size = gtk_page_setup_get_paper_size (page_setup);
+
+ /* Load page setup options that are specific to the document */
+ if (window->priv->metadata &&
+ ev_metadata_get_int (window->priv->metadata, "page-setup-orientation", &int_value)) {
+ gtk_page_setup_set_orientation (page_setup, int_value);
+ } else {
+ gtk_page_setup_set_orientation (page_setup, GTK_PAGE_ORIENTATION_PORTRAIT);
+ }
+
+ if (window->priv->metadata &&
+ ev_metadata_get_double (window->priv->metadata, "page-setup-margin-top", &double_value)) {
+ gtk_page_setup_set_top_margin (page_setup, double_value, GTK_UNIT_MM);
+ } 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 (window->priv->metadata &&
+ ev_metadata_get_double (window->priv->metadata, "page-setup-margin-bottom", &double_value)) {
+ gtk_page_setup_set_bottom_margin (page_setup, double_value, GTK_UNIT_MM);
+ } 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 (window->priv->metadata &&
+ ev_metadata_get_double (window->priv->metadata, "page-setup-margin-left", &double_value)) {
+ gtk_page_setup_set_left_margin (page_setup, double_value, GTK_UNIT_MM);
+ } 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 (window->priv->metadata &&
+ ev_metadata_get_double (window->priv->metadata, "page-setup-margin-right", &double_value)) {
+ gtk_page_setup_set_right_margin (page_setup, double_value, GTK_UNIT_MM);
+ } 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 GtkPrintSettings *
+get_print_settings (GKeyFile *key_file)
+{
+ GtkPrintSettings *print_settings;
+
+ print_settings = g_key_file_has_group (key_file, EV_PRINT_SETTINGS_GROUP) ?
+ gtk_print_settings_new_from_key_file (key_file, EV_PRINT_SETTINGS_GROUP, NULL) :
+ gtk_print_settings_new ();
+
+ return print_settings ? print_settings : gtk_print_settings_new ();
+}
+
+static GtkPageSetup *
+get_print_page_setup (GKeyFile *key_file)
+{
+ GtkPageSetup *page_setup;
+
+ page_setup = g_key_file_has_group (key_file, EV_PAGE_SETUP_GROUP) ?
+ gtk_page_setup_new_from_key_file (key_file, EV_PAGE_SETUP_GROUP, NULL) :
+ gtk_page_setup_new ();
+
+ return page_setup ? page_setup : gtk_page_setup_new ();
+}
+
+static void
+ev_window_print_page_setup_done_cb (GtkPageSetup *page_setup,
+ EvWindow *window)
+{
+ /* Dialog was canceled */
+ if (!page_setup)
+ return;
+
+ ev_window_save_print_page_setup (window, page_setup);
+}
+
+static void
+ev_window_cmd_file_print_setup (GtkAction *action,
+ EvWindow *ev_window)
+{
+ GKeyFile *print_settings_file;
+ GtkPrintSettings *print_settings;
+ GtkPageSetup *print_page_setup;
+
+ print_settings_file = get_print_settings_file ();
+
+ print_settings = get_print_settings (print_settings_file);
+ ev_window_load_print_settings_from_metadata (ev_window, print_settings);
+
+ print_page_setup = get_print_page_setup (print_settings_file);
+ ev_window_load_print_page_setup_from_metadata (ev_window, print_page_setup);
+
+ gtk_print_run_page_setup_dialog_async (GTK_WINDOW (ev_window),
+ print_page_setup,
+ print_settings,
+ (GtkPageSetupDoneFunc)ev_window_print_page_setup_done_cb,
+ ev_window);
+ g_object_unref (print_settings);
+ g_object_unref (print_page_setup);
+ g_key_file_free (print_settings_file);
+}
+
+static void
+ev_window_print_cancel (EvWindow *ev_window)
+{
+ EvPrintOperation *op;
+
+ if (!ev_window->priv->print_queue)
+ return;
+
+ while ((op = g_queue_peek_tail (ev_window->priv->print_queue))) {
+ ev_print_operation_cancel (op);
+ }
+}
+
+static void
+ev_window_print_update_pending_jobs_message (EvWindow *ev_window,
+ gint n_jobs)
+{
+ gchar *text = NULL;
+
+ if (!EV_IS_PROGRESS_MESSAGE_AREA (ev_window->priv->message_area) ||
+ !ev_window->priv->print_queue)
+ return;
+
+ if (n_jobs == 0) {
+ ev_window_set_message_area (ev_window, NULL);
+ return;
+ }
+
+ 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_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);
+
+ return FALSE;
+}
+
+static void
+ev_window_print_operation_done (EvPrintOperation *op,
+ GtkPrintOperationResult result,
+ EvWindow *ev_window)
+{
+ gint n_jobs;
+
+ switch (result) {
+ case GTK_PRINT_OPERATION_RESULT_APPLY: {
+ GtkPrintSettings *print_settings;
+
+ print_settings = ev_print_operation_get_print_settings (op);
+ ev_window_save_print_settings (ev_window, print_settings);
+
+ if (ev_print_operation_get_embed_page_setup (op)) {
+ GtkPageSetup *page_setup;
+
+ page_setup = ev_print_operation_get_default_page_setup (op);
+ ev_window_save_print_page_setup (ev_window, page_setup);
+ }
+ }
+
+ break;
+ case GTK_PRINT_OPERATION_RESULT_ERROR: {
+ GtkWidget *dialog;
+ GError *error = NULL;
+
+
+ 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;
+ }
+
+ 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);
+
+ 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));
+ }
+}
+
+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);
+
+ 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)
+{
+ if (!ev_window->priv->print_queue)
+ ev_window->priv->print_queue = g_queue_new ();
+
+ 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));
+}
+
+void
+ev_window_print_range (EvWindow *ev_window,
+ gint first_page,
+ gint last_page)
+{
+ EvPrintOperation *op;
+ GKeyFile *print_settings_file;
+ GtkPrintSettings *print_settings;
+ GtkPageSetup *print_page_setup;
+ 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_queue)
+ ev_window->priv->print_queue = g_queue_new ();
+
+ op = ev_print_operation_new (ev_window->priv->document);
+ if (!op) {
+ g_warning ("%s", "Printing is not supported for document\n");
+ return;
+ }
+
+ 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);
+
+ current_page = ev_document_model_get_page (ev_window->priv->model);
+ document_last_page = ev_document_get_n_pages (ev_window->priv->document);
+
+ print_settings_file = get_print_settings_file ();
+
+ print_settings = get_print_settings (print_settings_file);
+ ev_window_load_print_settings_from_metadata (ev_window, print_settings);
+
+ print_page_setup = get_print_page_setup (print_settings_file);
+ ev_window_load_print_page_setup_from_metadata (ev_window, print_page_setup);
+
+ if (first_page != 1 || last_page != document_last_page) {
+ GtkPageRange range;
+
+ /* Ranges in GtkPrint are 0 - N */
+ range.start = first_page - 1;
+ range.end = last_page - 1;
+
+ gtk_print_settings_set_print_pages (print_settings,
+ GTK_PRINT_PAGES_RANGES);
+ gtk_print_settings_set_page_ranges (print_settings,
+ &range, 1);
+ }
+
+ 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, print_settings);
+ ev_print_operation_set_default_page_setup (op, print_page_setup);
+#ifdef WITH_GCONF
+ ev_print_operation_set_embed_page_setup (op, !gconf_client_get_bool (ev_window->priv->gconf_client,
+ GCONF_LOCKDOWN_PRINT_SETUP,
+ NULL));
+#else
+ ev_print_operation_set_embed_page_setup (op, TRUE);
+#endif
+
+ g_object_unref (print_settings);
+ g_object_unref (print_page_setup);
+ g_key_file_free (print_settings_file);
+
+ ev_print_operation_run (op, GTK_WINDOW (ev_window));
+}
+
+static void
+ev_window_print (EvWindow *window)
+{
+ ev_window_print_range (window, 1,
+ ev_document_get_n_pages (window->priv->document));
+}
+
+static void
+ev_window_cmd_file_print (GtkAction *action, EvWindow *ev_window)
+{
+ ev_window_print (ev_window);
+}
+
+static void
+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));
+ gtk_window_set_transient_for (GTK_WINDOW (ev_window->priv->properties),
+ GTK_WINDOW (ev_window));
+ }
+
+ ev_document_fc_mutex_lock ();
+ 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)
+{
+ 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 ("<b>%s</b>", 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_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+ GTK_RESPONSE_YES,
+ GTK_RESPONSE_NO,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (print_jobs_confirmation_dialog_response),
+ ev_window);
+ gtk_widget_show (dialog);
+}
+
+static void
+ev_window_cmd_focus_page_selector (GtkAction *act, EvWindow *window)
+{
+ GtkAction *action;
+
+ update_chrome_flag (window, EV_CHROME_RAISE_TOOLBAR, TRUE);
+ ev_window_set_action_sensitive (window, "ViewToolbar", FALSE);
+ update_chrome_visibility (window);
+
+ action = gtk_action_group_get_action (window->priv->action_group,
+ PAGE_SELECTOR_ACTION);
+ ev_page_action_grab_focus (EV_PAGE_ACTION (action));
+}
+
+static void
+ev_window_cmd_scroll_forward (GtkAction *action, EvWindow *window)
+{
+ ev_view_scroll (EV_VIEW (window->priv->view), GTK_SCROLL_PAGE_FORWARD, FALSE);
+}
+
+static void
+ev_window_cmd_scroll_backward (GtkAction *action, EvWindow *window)
+{
+ ev_view_scroll (EV_VIEW (window->priv->view), GTK_SCROLL_PAGE_BACKWARD, FALSE);
+}
+
+static void
+ev_window_cmd_continuous (GtkAction *action, EvWindow *ev_window)
+{
+ gboolean continuous;
+
+ ev_window_stop_presentation (ev_window, TRUE);
+ continuous = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+ ev_document_model_set_continuous (ev_window->priv->model, continuous);
+}
+
+static void
+ev_window_cmd_dual (GtkAction *action, EvWindow *ev_window)
+{
+ gboolean dual_page;
+
+ ev_window_stop_presentation (ev_window, TRUE);
+ dual_page = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+ ev_document_model_set_dual_page (ev_window->priv->model, dual_page);
+}
+
+static void
+ev_window_cmd_view_best_fit (GtkAction *action, EvWindow *ev_window)
+{
+ ev_window_stop_presentation (ev_window, TRUE);
+
+ if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
+ ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_BEST_FIT);
+ } else {
+ ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FREE);
+ }
+ ev_window_update_actions (ev_window);
+}
+
+static void
+ev_window_cmd_view_page_width (GtkAction *action, EvWindow *ev_window)
+{
+ ev_window_stop_presentation (ev_window, TRUE);
+
+ if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
+ ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FIT_WIDTH);
+ } else {
+ ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FREE);
+ }
+ ev_window_update_actions (ev_window);
+}
+
+
+static void
+ev_window_cmd_edit_select_all (GtkAction *action, EvWindow *ev_window)
+{
+ g_return_if_fail (EV_IS_WINDOW (ev_window));
+
+ ev_view_select_all (EV_VIEW (ev_window->priv->view));
+}
+
+static void
+ev_window_cmd_edit_find (GtkAction *action, EvWindow *ev_window)
+{
+ g_return_if_fail (EV_IS_WINDOW (ev_window));
+
+ if (ev_window->priv->document == NULL || !EV_IS_DOCUMENT_FIND (ev_window->priv->document)) {
+ g_error ("Find action should be insensitive since document doesn't support find");
+ return;
+ }
+
+ update_chrome_flag (ev_window, EV_CHROME_FINDBAR, TRUE);
+ update_chrome_visibility (ev_window);
+ gtk_widget_grab_focus (ev_window->priv->find_bar);
+}
+
+static void
+ev_window_cmd_edit_find_next (GtkAction *action, EvWindow *ev_window)
+{
+ g_return_if_fail (EV_IS_WINDOW (ev_window));
+
+ update_chrome_flag (ev_window, EV_CHROME_FINDBAR, TRUE);
+ update_chrome_visibility (ev_window);
+ gtk_widget_grab_focus (ev_window->priv->find_bar);
+ ev_view_find_next (EV_VIEW (ev_window->priv->view));
+}
+
+static void
+ev_window_cmd_edit_find_previous (GtkAction *action, EvWindow *ev_window)
+{
+ g_return_if_fail (EV_IS_WINDOW (ev_window));
+
+ update_chrome_flag (ev_window, EV_CHROME_FINDBAR, TRUE);
+ update_chrome_visibility (ev_window);
+ gtk_widget_grab_focus (ev_window->priv->find_bar);
+ ev_view_find_previous (EV_VIEW (ev_window->priv->view));
+}
+
+static void
+ev_window_cmd_edit_copy (GtkAction *action, EvWindow *ev_window)
+{
+ g_return_if_fail (EV_IS_WINDOW (ev_window));
+
+ ev_view_copy (EV_VIEW (ev_window->priv->view));
+}
+
+static void
+ev_window_sidebar_position_change_cb (GObject *object,
+ GParamSpec *pspec,
+ EvWindow *ev_window)
+{
+ if (ev_window->priv->metadata && !ev_window_is_empty (ev_window))
+ ev_metadata_set_int (ev_window->priv->metadata, "sidebar_size",
+ gtk_paned_get_position (GTK_PANED (object)));
+}
+
+static void
+ev_window_update_fullscreen_action (EvWindow *window)
+{
+ GtkAction *action;
+
+ action = gtk_action_group_get_action (window->priv->action_group, "ViewFullscreen");
+ g_signal_handlers_block_by_func
+ (action, G_CALLBACK (ev_window_cmd_view_fullscreen), window);
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
+ ev_document_model_get_fullscreen (window->priv->model));
+ g_signal_handlers_unblock_by_func
+ (action, G_CALLBACK (ev_window_cmd_view_fullscreen), window);
+}
+
+static void
+fullscreen_toolbar_setup_item_properties (GtkUIManager *ui_manager)
+{
+ GtkWidget *item;
+
+ item = gtk_ui_manager_get_widget (ui_manager, "/FullscreenToolbar/GoPreviousPage");
+ g_object_set (item, "is-important", FALSE, NULL);
+
+ item = gtk_ui_manager_get_widget (ui_manager, "/FullscreenToolbar/GoNextPage");
+ g_object_set (item, "is-important", FALSE, NULL);
+
+ item = gtk_ui_manager_get_widget (ui_manager, "/FullscreenToolbar/StartPresentation");
+ g_object_set (item, "is-important", TRUE, NULL);
+
+ item = gtk_ui_manager_get_widget (ui_manager, "/FullscreenToolbar/LeaveFullscreen");
+ g_object_set (item, "is-important", TRUE, NULL);
+}
+
+static void
+fullscreen_toolbar_remove_shadow (GtkWidget *toolbar)
+{
+ static gboolean done = FALSE;
+
+ if (!done) {
+ gtk_rc_parse_string (
+ "\n"
+ " style \"fullscreen-toolbar-style\"\n"
+ " {\n"
+ " GtkToolbar::shadow-type=GTK_SHADOW_NONE\n"
+ " }\n"
+ "\n"
+ " widget \"*.fullscreen-toolbar\" style \"fullscreen-toolbar-style\"\n"
+ "\n");
+ done = TRUE;
+ }
+
+ gtk_widget_set_name (toolbar, "fullscreen-toolbar");
+}
+
+static void
+ev_window_run_fullscreen (EvWindow *window)
+{
+ gboolean fullscreen_window = TRUE;
+
+ if (ev_document_model_get_fullscreen (window->priv->model))
+ return;
+
+ if (!window->priv->fullscreen_toolbar) {
+ window->priv->fullscreen_toolbar =
+ gtk_ui_manager_get_widget (window->priv->ui_manager,
+ "/FullscreenToolbar");
+
+ gtk_toolbar_set_style (GTK_TOOLBAR (window->priv->fullscreen_toolbar),
+ GTK_TOOLBAR_BOTH_HORIZ);
+ fullscreen_toolbar_remove_shadow (window->priv->fullscreen_toolbar);
+ fullscreen_toolbar_setup_item_properties (window->priv->ui_manager);
+
+ gtk_box_pack_start (GTK_BOX (window->priv->main_box),
+ window->priv->fullscreen_toolbar,
+ FALSE, FALSE, 0);
+ gtk_box_reorder_child (GTK_BOX (window->priv->main_box),
+ window->priv->fullscreen_toolbar, 1);
+ }
+
+ if (EV_WINDOW_IS_PRESENTATION (window)) {
+ ev_window_stop_presentation (window, FALSE);
+ fullscreen_window = FALSE;
+ }
+
+ g_object_set (G_OBJECT (window->priv->scrolled_window),
+ "shadow-type", GTK_SHADOW_NONE,
+ NULL);
+
+ ev_document_model_set_fullscreen (window->priv->model, TRUE);
+ ev_window_update_fullscreen_action (window);
+
+ /* If the user doesn't have the main toolbar he/she won't probably want
+ * the toolbar in fullscreen mode. See bug #483048
+ */
+ update_chrome_flag (window, EV_CHROME_FULLSCREEN_TOOLBAR,
+ (window->priv->chrome & EV_CHROME_TOOLBAR) != 0);
+ update_chrome_visibility (window);
+
+ if (fullscreen_window)
+ gtk_window_fullscreen (GTK_WINDOW (window));
+ gtk_widget_grab_focus (window->priv->view);
+
+ if (window->priv->metadata && !ev_window_is_empty (window))
+ ev_metadata_set_boolean (window->priv->metadata, "fullscreen", TRUE);
+}
+
+static void
+ev_window_stop_fullscreen (EvWindow *window,
+ gboolean unfullscreen_window)
+{
+ if (!ev_document_model_get_fullscreen (window->priv->model))
+ return;
+
+ g_object_set (G_OBJECT (window->priv->scrolled_window),
+ "shadow-type", GTK_SHADOW_IN,
+ NULL);
+
+ ev_document_model_set_fullscreen (window->priv->model, FALSE);
+ ev_window_update_fullscreen_action (window);
+ update_chrome_flag (window, EV_CHROME_FULLSCREEN_TOOLBAR, FALSE);
+ update_chrome_visibility (window);
+ if (unfullscreen_window)
+ gtk_window_unfullscreen (GTK_WINDOW (window));
+
+ if (window->priv->metadata && !ev_window_is_empty (window))
+ ev_metadata_set_boolean (window->priv->metadata, "fullscreen", FALSE);
+}
+
+static void
+ev_window_cmd_view_fullscreen (GtkAction *action, EvWindow *window)
+{
+ gboolean fullscreen;
+
+ fullscreen = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+ if (fullscreen) {
+ ev_window_run_fullscreen (window);
+ } else {
+ ev_window_stop_fullscreen (window, TRUE);
+ }
+}
+
+static void
+ev_window_update_presentation_action (EvWindow *window)
+{
+ GtkAction *action;
+
+ action = gtk_action_group_get_action (window->priv->action_group, "ViewPresentation");
+ g_signal_handlers_block_by_func
+ (action, G_CALLBACK (ev_window_cmd_view_presentation), window);
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
+ EV_WINDOW_IS_PRESENTATION (window));
+ g_signal_handlers_unblock_by_func
+ (action, G_CALLBACK (ev_window_cmd_view_presentation), window);
+}
+
+static void
+ev_window_view_presentation_finished (EvWindow *window)
+{
+ ev_window_stop_presentation (window, TRUE);
+}
+
+static void
+ev_window_run_presentation (EvWindow *window)
+{
+ gboolean fullscreen_window = TRUE;
+ guint current_page;
+ guint rotation;
+
+ if (EV_WINDOW_IS_PRESENTATION (window))
+ return;
+
+ if (ev_document_model_get_fullscreen (window->priv->model)) {
+ ev_window_stop_fullscreen (window, FALSE);
+ fullscreen_window = FALSE;
+ }
+
+ current_page = ev_document_model_get_page (window->priv->model);
+ rotation = ev_document_model_get_rotation (window->priv->model);
+ window->priv->presentation_view =
+ ev_view_presentation_new (window->priv->document, current_page, rotation);
+ g_signal_connect_swapped (window->priv->presentation_view, "finished",
+ G_CALLBACK (ev_window_view_presentation_finished),
+ window);
+
+ gtk_box_pack_start (GTK_BOX (window->priv->main_box),
+ window->priv->presentation_view,
+ TRUE, TRUE, 0);
+
+ gtk_widget_hide (window->priv->hpaned);
+ ev_window_update_presentation_action (window);
+ update_chrome_visibility (window);
+
+ gtk_widget_grab_focus (window->priv->presentation_view);
+ if (fullscreen_window)
+ gtk_window_fullscreen (GTK_WINDOW (window));
+
+ gtk_widget_show (window->priv->presentation_view);
+
+ ev_application_screensaver_disable (EV_APP);
+
+ if (window->priv->metadata && !ev_window_is_empty (window))
+ ev_metadata_set_boolean (window->priv->metadata, "presentation", TRUE);
+}
+
+static void
+ev_window_stop_presentation (EvWindow *window,
+ gboolean unfullscreen_window)
+{
+ guint current_page;
+
+ if (!EV_WINDOW_IS_PRESENTATION (window))
+ return;
+
+ current_page = ev_view_presentation_get_current_page (EV_VIEW_PRESENTATION (window->priv->presentation_view));
+ ev_document_model_set_page (window->priv->model, current_page);
+
+ gtk_container_remove (GTK_CONTAINER (window->priv->main_box),
+ window->priv->presentation_view);
+ window->priv->presentation_view = NULL;
+
+ gtk_widget_show (window->priv->hpaned);
+ ev_window_update_presentation_action (window);
+ update_chrome_visibility (window);
+ if (unfullscreen_window)
+ gtk_window_unfullscreen (GTK_WINDOW (window));
+
+ gtk_widget_grab_focus (window->priv->view);
+
+ ev_application_screensaver_enable (EV_APP);
+
+ if (window->priv->metadata && !ev_window_is_empty (window))
+ ev_metadata_set_boolean (window->priv->metadata, "presentation", FALSE);
+}
+
+static void
+ev_window_cmd_view_presentation (GtkAction *action, EvWindow *window)
+{
+ gboolean presentation;
+
+ presentation = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+ if (presentation) {
+ ev_window_run_presentation (window);
+ }
+}
+
+static void
+ev_window_setup_gtk_settings (EvWindow *window)
+{
+ GtkSettings *settings;
+ GdkScreen *screen;
+ gchar *menubar_accel_accel;
+
+ screen = gtk_window_get_screen (GTK_WINDOW (window));
+ settings = gtk_settings_get_for_screen (screen);
+
+ g_object_get (settings,
+ "gtk-menu-bar-accel", &menubar_accel_accel,
+ NULL);
+ if (menubar_accel_accel != NULL && menubar_accel_accel[0] != '\0') {
+ gtk_accelerator_parse (menubar_accel_accel,
+ &window->priv->menubar_accel_keyval,
+ &window->priv->menubar_accel_modifier);
+ if (window->priv->menubar_accel_keyval == 0) {
+ g_warning ("Failed to parse menu bar accelerator '%s'\n",
+ menubar_accel_accel);
+ }
+ } else {
+ window->priv->menubar_accel_keyval = 0;
+ window->priv->menubar_accel_modifier = 0;
+ }
+
+ g_free (menubar_accel_accel);
+}
+
+static void
+ev_window_screen_changed (GtkWidget *widget,
+ GdkScreen *old_screen)
+{
+ EvWindow *window = EV_WINDOW (widget);
+ EvWindowPrivate *priv = window->priv;
+ GdkScreen *screen;
+ gdouble dpi;
+
+ screen = gtk_widget_get_screen (widget);
+ if (screen == old_screen)
+ return;
+
+ ev_window_setup_gtk_settings (window);
+ dpi = get_screen_dpi (window);
+ ev_document_model_set_min_scale (priv->model, MIN_SCALE * dpi / 72.0);
+ ev_document_model_set_max_scale (priv->model, MAX_SCALE * dpi / 72.0);
+
+ if (GTK_WIDGET_CLASS (ev_window_parent_class)->screen_changed) {
+ GTK_WIDGET_CLASS (ev_window_parent_class)->screen_changed (widget, old_screen);
+ }
+}
+
+static gboolean
+ev_window_state_event (GtkWidget *widget,
+ GdkEventWindowState *event)
+{
+ EvWindow *window = EV_WINDOW (widget);
+
+ if (GTK_WIDGET_CLASS (ev_window_parent_class)->window_state_event) {
+ GTK_WIDGET_CLASS (ev_window_parent_class)->window_state_event (widget, event);
+ }
+
+ if ((event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) == 0)
+ return FALSE;
+
+ if (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) {
+ if (ev_document_model_get_fullscreen (window->priv->model) || EV_WINDOW_IS_PRESENTATION (window))
+ return FALSE;
+
+ ev_window_run_fullscreen (window);
+ } else {
+ if (ev_document_model_get_fullscreen (window->priv->model))
+ ev_window_stop_fullscreen (window, FALSE);
+ else if (EV_WINDOW_IS_PRESENTATION (window))
+ ev_window_stop_presentation (window, FALSE);
+ }
+
+ return FALSE;
+}
+
+static void
+ev_window_set_page_mode (EvWindow *window,
+ EvWindowPageMode page_mode)
+{
+ GtkWidget *child = NULL;
+ GtkWidget *real_child;
+
+ if (window->priv->page_mode == page_mode)
+ return;
+
+ window->priv->page_mode = page_mode;
+
+ switch (page_mode) {
+ case PAGE_MODE_DOCUMENT:
+ child = window->priv->view;
+ break;
+ case PAGE_MODE_PASSWORD:
+ child = window->priv->password_view;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ real_child = gtk_bin_get_child (GTK_BIN (window->priv->scrolled_window));
+ if (child != real_child) {
+ gtk_container_remove (GTK_CONTAINER (window->priv->scrolled_window),
+ real_child);
+ gtk_container_add (GTK_CONTAINER (window->priv->scrolled_window),
+ child);
+ }
+ ev_window_update_actions (window);
+}
+
+
+static void
+ev_window_cmd_edit_rotate_left (GtkAction *action, EvWindow *ev_window)
+{
+ gint rotation = ev_document_model_get_rotation (ev_window->priv->model);
+
+ ev_document_model_set_rotation (ev_window->priv->model, rotation - 90);
+}
+
+static void
+ev_window_cmd_edit_rotate_right (GtkAction *action, EvWindow *ev_window)
+{
+ gint rotation = ev_document_model_get_rotation (ev_window->priv->model);
+
+ ev_document_model_set_rotation (ev_window->priv->model, rotation + 90);
+}
+
+static void
+ev_window_cmd_view_inverted_colors (GtkAction *action, EvWindow *ev_window)
+{
+ gboolean inverted_colors = ev_document_model_get_inverted_colors (ev_window->priv->model);
+
+ ev_document_model_set_inverted_colors (ev_window->priv->model, !inverted_colors);
+}
+
+static void
+ev_window_cmd_edit_toolbar_cb (GtkDialog *dialog,
+ gint response,
+ EvWindow *ev_window)
+{
+ EggEditableToolbar *toolbar;
+ gchar *toolbars_file;
+
+ toolbar = EGG_EDITABLE_TOOLBAR (ev_window->priv->toolbar);
+ egg_editable_toolbar_set_edit_mode (toolbar, FALSE);
+
+ toolbars_file = g_build_filename (ev_application_get_dot_dir (EV_APP, TRUE),
+ "evince_toolbar.xml", NULL);
+ egg_toolbars_model_save_toolbars (egg_editable_toolbar_get_model (toolbar),
+ toolbars_file, "1.0");
+ g_free (toolbars_file);
+
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static void
+ev_window_cmd_edit_toolbar (GtkAction *action, EvWindow *ev_window)
+{
+ GtkWidget *dialog;
+ GtkWidget *editor;
+ EggEditableToolbar *toolbar;
+
+ dialog = gtk_dialog_new_with_buttons (_("Toolbar Editor"),
+ GTK_WINDOW (ev_window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_CLOSE,
+ GTK_RESPONSE_CLOSE,
+ NULL);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
+ gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)), 5);
+ gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 2);
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+ gtk_window_set_default_size (GTK_WINDOW (dialog), 500, 400);
+
+ toolbar = EGG_EDITABLE_TOOLBAR (ev_window->priv->toolbar);
+ editor = egg_toolbar_editor_new (ev_window->priv->ui_manager,
+ egg_editable_toolbar_get_model (toolbar));
+
+ gtk_container_set_border_width (GTK_CONTAINER (editor), 5);
+ gtk_box_set_spacing (GTK_BOX (EGG_TOOLBAR_EDITOR (editor)), 5);
+
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), editor);
+
+ egg_editable_toolbar_set_edit_mode (toolbar, TRUE);
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (ev_window_cmd_edit_toolbar_cb),
+ ev_window);
+ gtk_widget_show_all (dialog);
+}
+
+static void
+ev_window_cmd_view_zoom_in (GtkAction *action, EvWindow *ev_window)
+{
+ g_return_if_fail (EV_IS_WINDOW (ev_window));
+
+ ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FREE);
+ ev_view_zoom_in (EV_VIEW (ev_window->priv->view));
+}
+
+static void
+ev_window_cmd_view_zoom_out (GtkAction *action, EvWindow *ev_window)
+{
+ g_return_if_fail (EV_IS_WINDOW (ev_window));
+
+ ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FREE);
+ ev_view_zoom_out (EV_VIEW (ev_window->priv->view));
+}
+
+static void
+ev_window_cmd_go_previous_page (GtkAction *action, EvWindow *ev_window)
+{
+ g_return_if_fail (EV_IS_WINDOW (ev_window));
+
+ ev_view_previous_page (EV_VIEW (ev_window->priv->view));
+}
+
+static void
+ev_window_cmd_go_next_page (GtkAction *action, EvWindow *ev_window)
+{
+ g_return_if_fail (EV_IS_WINDOW (ev_window));
+
+ ev_view_next_page (EV_VIEW (ev_window->priv->view));
+}
+
+static void
+ev_window_cmd_go_first_page (GtkAction *action, EvWindow *ev_window)
+{
+ g_return_if_fail (EV_IS_WINDOW (ev_window));
+
+ ev_document_model_set_page (ev_window->priv->model, 0);
+}
+
+static void
+ev_window_cmd_go_last_page (GtkAction *action, EvWindow *ev_window)
+{
+ g_return_if_fail (EV_IS_WINDOW (ev_window));
+
+ ev_document_model_set_page (ev_window->priv->model,
+ ev_document_get_n_pages (ev_window->priv->document) - 1);
+}
+
+static void
+ev_window_cmd_go_forward (GtkAction *action, EvWindow *ev_window)
+{
+ int n_pages, current_page;
+
+ g_return_if_fail (EV_IS_WINDOW (ev_window));
+
+ n_pages = ev_document_get_n_pages (ev_window->priv->document);
+ current_page = ev_document_model_get_page (ev_window->priv->model);
+
+ if (current_page + 10 < n_pages) {
+ ev_document_model_set_page (ev_window->priv->model, current_page + 10);
+ }
+}
+
+static void
+ev_window_cmd_go_backward (GtkAction *action, EvWindow *ev_window)
+{
+ int current_page;
+
+ g_return_if_fail (EV_IS_WINDOW (ev_window));
+
+ current_page = ev_document_model_get_page (ev_window->priv->model);
+
+ if (current_page - 10 >= 0) {
+ ev_document_model_set_page (ev_window->priv->model, current_page - 10);
+ }
+}
+
+static void
+ev_window_cmd_view_reload (GtkAction *action, EvWindow *ev_window)
+{
+ ev_window_reload_document (ev_window, NULL);
+}
+
+static void
+ev_window_cmd_view_autoscroll (GtkAction *action, EvWindow *ev_window)
+{
+ ev_view_autoscroll_start (EV_VIEW (ev_window->priv->view));
+}
+
+static void
+ev_window_cmd_help_contents (GtkAction *action, EvWindow *ev_window)
+{
+ GError *error = NULL;
+
+ gtk_show_uri (gtk_window_get_screen (GTK_WINDOW (ev_window)),
+ "ghelp:evince",
+ gtk_get_current_event_time (),
+ &error);
+ if (error) {
+ ev_window_error_message (ev_window, error,
+ "%s", _("There was an error displaying help"));
+ g_error_free (error);
+ }
+}
+
+static void
+ev_window_cmd_leave_fullscreen (GtkAction *action, EvWindow *window)
+{
+ ev_window_stop_fullscreen (window, TRUE);
+}
+
+static void
+ev_window_cmd_start_presentation (GtkAction *action, EvWindow *window)
+{
+ ev_window_run_presentation (window);
+}
+
+static void
+ev_window_cmd_escape (GtkAction *action, EvWindow *window)
+{
+ GtkWidget *widget;
+
+ ev_view_autoscroll_stop (EV_VIEW (window->priv->view));
+
+ widget = gtk_window_get_focus (GTK_WINDOW (window));
+ if (widget && gtk_widget_get_ancestor (widget, EGG_TYPE_FIND_BAR)) {
+ update_chrome_flag (window, EV_CHROME_FINDBAR, FALSE);
+ update_chrome_visibility (window);
+ gtk_widget_grab_focus (window->priv->view);
+ } else {
+ gboolean fullscreen;
+
+ fullscreen = ev_document_model_get_fullscreen (window->priv->model);
+
+ if (fullscreen) {
+ ev_window_stop_fullscreen (window, TRUE);
+ } else if (EV_WINDOW_IS_PRESENTATION (window)) {
+ ev_window_stop_presentation (window, TRUE);
+ gtk_widget_grab_focus (window->priv->view);
+ } else {
+ gtk_widget_grab_focus (window->priv->view);
+ }
+
+ if (fullscreen && EV_WINDOW_IS_PRESENTATION (window))
+ g_warning ("Both fullscreen and presentation set somehow");
+ }
+}
+
+static void
+save_sizing_mode (EvWindow *window)
+{
+ EvSizingMode mode;
+ GEnumValue *enum_value;
+
+ if (!window->priv->metadata || ev_window_is_empty (window))
+ return;
+
+ mode = ev_document_model_get_sizing_mode (window->priv->model);
+ enum_value = g_enum_get_value (g_type_class_peek (EV_TYPE_SIZING_MODE), mode);
+ ev_metadata_set_string (window->priv->metadata, "sizing_mode",
+ enum_value->value_nick);
+}
+
+static void
+ev_window_document_changed_cb (EvDocumentModel *model,
+ GParamSpec *pspec,
+ EvWindow *ev_window)
+{
+ ev_window_set_document (ev_window,
+ ev_document_model_get_document (model));
+}
+
+static void
+ev_window_sizing_mode_changed_cb (EvDocumentModel *model,
+ GParamSpec *pspec,
+ EvWindow *ev_window)
+{
+ EvSizingMode sizing_mode = ev_document_model_get_sizing_mode (model);
+
+ g_object_set (ev_window->priv->scrolled_window,
+ "hscrollbar-policy",
+ sizing_mode == EV_SIZING_FREE ?
+ GTK_POLICY_AUTOMATIC : GTK_POLICY_NEVER,
+ "vscrollbar-policy", GTK_POLICY_AUTOMATIC,
+ NULL);
+
+ update_sizing_buttons (ev_window);
+ save_sizing_mode (ev_window);
+}
+
+static void
+ev_window_zoom_changed_cb (EvDocumentModel *model, GParamSpec *pspec, EvWindow *ev_window)
+{
+ ev_window_update_actions (ev_window);
+
+ if (!ev_window->priv->metadata)
+ return;
+
+ if (ev_document_model_get_sizing_mode (model) == EV_SIZING_FREE && !ev_window_is_empty (ev_window)) {
+ gdouble zoom;
+
+ zoom = ev_document_model_get_scale (model);
+ zoom *= 72.0 / get_screen_dpi (ev_window);
+ ev_metadata_set_double (ev_window->priv->metadata, "zoom", zoom);
+ }
+}
+
+static void
+ev_window_update_continuous_action (EvWindow *window)
+{
+ GtkAction *action;
+
+ action = gtk_action_group_get_action (window->priv->action_group, "ViewContinuous");
+ g_signal_handlers_block_by_func
+ (action, G_CALLBACK (ev_window_cmd_continuous), window);
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
+ ev_document_model_get_continuous (window->priv->model));
+ g_signal_handlers_unblock_by_func
+ (action, G_CALLBACK (ev_window_cmd_continuous), window);
+}
+
+static void
+ev_window_update_dual_page_action (EvWindow *window)
+{
+ GtkAction *action;
+
+ action = gtk_action_group_get_action (window->priv->action_group, "ViewDual");
+ g_signal_handlers_block_by_func
+ (action, G_CALLBACK (ev_window_cmd_dual), window);
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
+ ev_document_model_get_dual_page (window->priv->model));
+ g_signal_handlers_unblock_by_func
+ (action, G_CALLBACK (ev_window_cmd_dual), window);
+}
+
+static void
+ev_window_continuous_changed_cb (EvDocumentModel *model,
+ GParamSpec *pspec,
+ EvWindow *ev_window)
+{
+ ev_window_update_continuous_action (ev_window);
+
+ if (ev_window->priv->metadata && !ev_window_is_empty (ev_window))
+ ev_metadata_set_boolean (ev_window->priv->metadata, "continuous",
+ ev_document_model_get_continuous (model));
+}
+
+static void
+ev_window_rotation_changed_cb (EvDocumentModel *model,
+ GParamSpec *pspec,
+ EvWindow *window)
+{
+ gint rotation = ev_document_model_get_rotation (model);
+
+ if (window->priv->metadata && !ev_window_is_empty (window))
+ ev_metadata_set_int (window->priv->metadata, "rotation",
+ rotation);
+
+ ev_window_refresh_window_thumbnail (window);
+}
+
+static void
+ev_window_update_inverted_colors_action (EvWindow *window)
+{
+ GtkAction *action;
+
+ action = gtk_action_group_get_action (window->priv->action_group, "ViewInvertedColors");
+ g_signal_handlers_block_by_func
+ (action, G_CALLBACK (ev_window_cmd_view_inverted_colors), window);
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
+ ev_document_model_get_inverted_colors (window->priv->model));
+ g_signal_handlers_unblock_by_func
+ (action, G_CALLBACK (ev_window_cmd_view_inverted_colors), window);
+}
+
+static void
+ev_window_inverted_colors_changed_cb (EvDocumentModel *model,
+ GParamSpec *pspec,
+ EvWindow *window)
+{
+ gboolean inverted_colors = ev_document_model_get_inverted_colors (model);
+
+ ev_window_update_inverted_colors_action (window);
+
+ if (window->priv->metadata && !ev_window_is_empty (window))
+ ev_metadata_set_boolean (window->priv->metadata, "inverted-colors",
+ inverted_colors);
+
+ ev_window_refresh_window_thumbnail (window);
+}
+
+static void
+ev_window_dual_mode_changed_cb (EvDocumentModel *model,
+ GParamSpec *pspec,
+ EvWindow *ev_window)
+{
+ ev_window_update_dual_page_action (ev_window);
+
+ if (ev_window->priv->metadata && !ev_window_is_empty (ev_window))
+ ev_metadata_set_boolean (ev_window->priv->metadata, "dual-page",
+ ev_document_model_get_dual_page (model));
+}
+
+static char *
+build_comments_string (EvDocument *document)
+{
+ gchar *comments = NULL;
+ EvDocumentBackendInfo info;
+
+ if (document && ev_document_get_backend_info (document, &info)) {
+ comments = g_strdup_printf (
+ _("Document Viewer\nUsing %s (%s)"),
+ info.name, info.version);
+ } else {
+ comments = g_strdup_printf (
+ _("Document Viewer"));
+ }
+
+ return comments;
+}
+
+static void
+ev_window_cmd_help_about (GtkAction *action, EvWindow *ev_window)
+{
+ const char *authors[] = {
+ "Martin Kretzschmar <m_kretzschmar@gmx.net>",
+ "Jonathan Blandford <jrb@gnome.org>",
+ "Marco Pesenti Gritti <marco@gnome.org>",
+ "Nickolay V. Shmyrev <nshmyrev@yandex.ru>",
+ "Bryan Clark <clarkbw@gnome.org>",
+ "Carlos Garcia Campos <carlosgc@gnome.org>",
+ "Wouter Bolsterlee <wbolster@gnome.org>",
+ "Christian Persch <chpe" "\100" "gnome.org>",
+ NULL
+ };
+
+ const char *documenters[] = {
+ "Nickolay V. Shmyrev <nshmyrev@yandex.ru>",
+ NULL
+ };
+
+ const char *license[] = {
+ N_("Evince is free software; you can redistribute it and/or modify "
+ "it under the terms of the GNU General Public License as published by "
+ "the Free Software Foundation; either version 2 of the License, or "
+ "(at your option) any later version.\n"),
+ N_("Evince is distributed in the hope that it will be useful, "
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of "
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
+ "GNU General Public License for more details.\n"),
+ N_("You should have received a copy of the GNU General Public License "
+ "along with Evince; if not, write to the Free Software Foundation, Inc., "
+ "59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n")
+ };
+
+ char *license_trans;
+ char *comments;
+
+#ifdef ENABLE_NLS
+ const char **p;
+
+ for (p = authors; *p; ++p)
+ *p = _(*p);
+
+ for (p = documenters; *p; ++p)
+ *p = _(*p);
+#endif
+
+ license_trans = g_strconcat (_(license[0]), "\n", _(license[1]), "\n",
+ _(license[2]), "\n", NULL);
+
+ comments = build_comments_string (ev_window->priv->document);
+
+ gtk_show_about_dialog (
+ GTK_WINDOW (ev_window),
+ "name", _("Evince"),
+ "version", VERSION,
+ "copyright",
+ _("© 1996–2009 The Evince authors"),
+ "license", license_trans,
+ "website", "http://www.gnome.org/projects/evince",
+ "comments", comments,
+ "authors", authors,
+ "documenters", documenters,
+ "translator-credits", _("translator-credits"),
+ "logo-icon-name", "evince",
+ "wrap-license", TRUE,
+ NULL);
+
+ g_free (comments);