+ ev_window_set_page_mode (ev_window, PAGE_MODE_DOCUMENT);
+ ev_window_title_set_document (ev_window->priv->title, document);
+ ev_window_title_set_uri (ev_window->priv->title, ev_window->priv->uri);
+
+ ev_sidebar_set_document (sidebar, document);
+
+ action = gtk_action_group_get_action (ev_window->priv->action_group, PAGE_SELECTOR_ACTION);
+ ev_page_action_set_document (EV_PAGE_ACTION (action), document);
+ ev_window_setup_action_sensitivity (ev_window);
+
+ if (ev_window->priv->history)
+ g_object_unref (ev_window->priv->history);
+ ev_window->priv->history = ev_history_new ();
+ action = gtk_action_group_get_action (ev_window->priv->action_group, NAVIGATION_ACTION);
+ ev_navigation_action_set_history (EV_NAVIGATION_ACTION (action), ev_window->priv->history);
+
+ if (ev_window->priv->properties) {
+ ev_properties_dialog_set_document (EV_PROPERTIES_DIALOG (ev_window->priv->properties),
+ ev_window->priv->document);
+ }
+
+ info = ev_page_cache_get_info (ev_window->priv->page_cache);
+ update_document_mode (ev_window, info->mode);
+
+ return FALSE;
+}
+
+static void
+ev_window_set_document (EvWindow *ev_window, EvDocument *document)
+{
+ EvView *view = EV_VIEW (ev_window->priv->view);
+
+ if (ev_window->priv->document)
+ g_object_unref (ev_window->priv->document);
+ ev_window->priv->document = g_object_ref (document);
+
+ ev_window->priv->page_cache = ev_page_cache_get (ev_window->priv->document);
+ g_signal_connect (ev_window->priv->page_cache, "page-changed",
+ G_CALLBACK (page_changed_cb), ev_window);
+ 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_page_cache_get_n_pages (ev_window->priv->page_cache) > 0) {
+ ev_view_set_document (view, document);
+ }
+
+ g_idle_add ((GSourceFunc)ev_window_setup_document, ev_window);
+}
+
+static void
+password_dialog_response (GtkWidget *password_dialog,
+ gint response_id,
+ EvWindow *ev_window)
+{
+ char *password;
+
+ if (response_id == GTK_RESPONSE_OK) {
+
+ password = ev_password_dialog_get_password (EV_PASSWORD_DIALOG (password_dialog));
+ if (password) {
+ ev_document_doc_mutex_lock ();
+ ev_document_security_set_password (EV_DOCUMENT_SECURITY (ev_window->priv->load_job->document),
+ password);
+ ev_document_doc_mutex_unlock ();
+ }
+ g_free (password);
+
+ 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_queue_add_job (ev_window->priv->load_job, EV_JOB_PRIORITY_HIGH);
+
+ 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)
+{
+ 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));
+ }
+}
+
+static void
+ev_window_clear_load_job (EvWindow *ev_window)
+{
+ if (ev_window->priv->load_job != NULL) {
+
+ if (!ev_window->priv->load_job->finished)
+ ev_job_queue_remove_job (ev_window->priv->load_job);
+
+ g_signal_handlers_disconnect_by_func (ev_window->priv->load_job, ev_window_load_job_cb, ev_window);
+ g_object_unref (ev_window->priv->load_job);
+ ev_window->priv->load_job = NULL;
+ }
+}
+
+static void
+ev_window_clear_local_uri (EvWindow *ev_window)
+{
+ char *filename;
+
+ if (ev_window->priv->local_uri) {
+ filename = g_filename_from_uri (ev_window->priv->local_uri, NULL, NULL);
+ if (filename != NULL) {
+ g_unlink (filename);
+ g_free (filename);
+ }
+ g_free (ev_window->priv->local_uri);
+ ev_window->priv->local_uri = NULL;
+ }
+}
+
+static void
+ev_window_clear_temp_file (EvWindow *ev_window)
+{
+ GnomeVFSURI *uri;
+ gchar *filename;
+ const gchar *tempdir;
+
+ if (!ev_window->priv->uri)
+ return;
+
+ uri = gnome_vfs_uri_new (ev_window->priv->uri);
+ if (!gnome_vfs_uri_is_local (uri)) {
+ gnome_vfs_uri_unref (uri);
+ return;
+ }
+ gnome_vfs_uri_unref (uri);
+
+ filename = g_filename_from_uri (ev_window->priv->uri, NULL, NULL);
+ if (!filename)
+ return;
+
+ tempdir = g_get_tmp_dir ();
+ if (g_ascii_strncasecmp (filename, tempdir, strlen (tempdir)) == 0) {
+ g_unlink (filename);
+ }
+
+ g_free (filename);
+}
+
+/* This callback will executed when load job will be finished.
+ *
+ * Since the flow of the error dialog is very confusing, we assume that both
+ * document and uri will go away after this function is called, and thus we need
+ * to ref/dup them. Additionally, it needs to clear
+ * ev_window->priv->password_{uri,document}, and thus people who call this
+ * function should _not_ necessarily expect those to exist after being
+ * called. */
+static void
+ev_window_load_job_cb (EvJobLoad *job,
+ gpointer data)
+{
+ EvWindow *ev_window = EV_WINDOW (data);
+ EvDocument *document = EV_JOB (job)->document;
+
+ g_assert (job->uri);
+
+ ev_view_set_loading (EV_VIEW (ev_window->priv->view), FALSE);
+
+ /* Success! */
+ if (job->error == NULL) {
+ ev_window_set_document (ev_window, document);
+
+ if (job->mode != EV_WINDOW_MODE_PREVIEW) {
+ setup_view_from_metadata (ev_window);
+ }
+
+ if (!ev_window->priv->unlink_temp_file) {
+ ev_window_add_recent (ev_window, ev_window->priv->uri);
+ }
+
+ if (job->dest) {
+ EvLink *link;
+ EvLinkAction *link_action;
+
+ link_action = ev_link_action_new_dest (g_object_ref (job->dest));
+ link = ev_link_new (NULL, link_action);
+ ev_view_handle_link (EV_VIEW (ev_window->priv->view), link);
+ g_object_unref (link);
+ }
+
+ switch (job->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;
+ case EV_WINDOW_MODE_PREVIEW:
+ ev_window_run_preview (ev_window);
+ break;
+ default:
+ break;
+ }
+
+ ev_window_clear_load_job (ev_window);
+ return;
+ }
+
+ if (job->error->domain == EV_DOCUMENT_ERROR &&
+ job->error->code == EV_DOCUMENT_ERROR_ENCRYPTED) {
+ gchar *base_name, *file_name;
+
+ setup_view_from_metadata (ev_window);
+
+ file_name = gnome_vfs_format_uri_for_display (job->uri);
+ base_name = g_path_get_basename (file_name);
+ ev_password_view_set_file_name (EV_PASSWORD_VIEW (ev_window->priv->password_view),
+ base_name);
+ g_free (file_name);
+ g_free (base_name);
+ ev_window_set_page_mode (ev_window, PAGE_MODE_PASSWORD);
+
+ ev_window_popup_password_dialog (ev_window);
+ } else {
+ ev_window_error_dialog (GTK_WINDOW (ev_window),
+ _("Unable to open document"),
+ job->error);
+ ev_window_clear_load_job (ev_window);
+ }
+
+ return;
+}
+
+const char *
+ev_window_get_uri (EvWindow *ev_window)
+{
+ return ev_window->priv->uri;
+}
+
+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;
+
+#ifdef WITH_PRINT
+ if (ev_window->priv->print_dialog)
+ gtk_widget_destroy (ev_window->priv->print_dialog);
+ ev_window->priv->print_dialog = NULL;
+#endif
+
+#ifdef WITH_GNOME_PRINT
+ if (ev_window->priv->print_job)
+ g_object_unref (ev_window->priv->print_job);
+ ev_window->priv->print_job = NULL;
+#endif
+
+ if (ev_window->priv->properties)
+ gtk_widget_destroy (ev_window->priv->properties);
+ ev_window->priv->properties = NULL;
+}
+
+static gint
+xfer_update_progress_callback (GnomeVFSAsyncHandle *handle,
+ GnomeVFSXferProgressInfo *info,
+ EvWindow *ev_window)
+{
+ switch (info->status) {
+ case GNOME_VFS_XFER_PROGRESS_STATUS_OK:
+ if (info->phase == GNOME_VFS_XFER_PHASE_COMPLETED) {
+ ev_job_queue_add_job (ev_window->priv->load_job, EV_JOB_PRIORITY_HIGH);
+ }
+
+ return 1;
+ case GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR:
+ case GNOME_VFS_XFER_PROGRESS_STATUS_OVERWRITE:
+ case GNOME_VFS_XFER_PROGRESS_STATUS_DUPLICATE:
+ return 1;
+ default:
+ g_assert_not_reached ();
+ }
+
+ return 0;
+}
+
+void
+ev_window_open_uri (EvWindow *ev_window,
+ const char *uri,
+ EvLinkDest *dest,
+ EvWindowRunMode mode,
+ gboolean unlink_temp_file)
+{
+ GnomeVFSURI *source_uri;
+ GnomeVFSURI *target_uri;
+
+ ev_window_close_dialogs (ev_window);
+ ev_window_clear_load_job (ev_window);
+ ev_window_clear_local_uri (ev_window);
+ ev_view_set_loading (EV_VIEW (ev_window->priv->view), TRUE);
+
+ ev_window->priv->unlink_temp_file = unlink_temp_file;
+
+ if (ev_window->priv->uri)
+ g_free (ev_window->priv->uri);
+ ev_window->priv->uri = g_strdup (uri);
+
+ setup_size_from_metadata (ev_window);
+
+ ev_window->priv->load_job = ev_job_load_new (uri, dest, mode);
+ g_signal_connect (ev_window->priv->load_job,
+ "finished",
+ G_CALLBACK (ev_window_load_job_cb),
+ ev_window);
+
+ source_uri = gnome_vfs_uri_new (uri);
+ if (!gnome_vfs_uri_is_local (source_uri) && !ev_window->priv->local_uri) {
+ GnomeVFSAsyncHandle *handle;
+ GList *slist = NULL;
+ GList *tlist = NULL;
+ char *tmp_name;
+ char *base_name;
+
+ /* We'd like to keep extension of source uri since
+ * it helps to resolve some mime types, say cbz */
+
+ tmp_name = ev_tmp_filename (NULL);
+ base_name = gnome_vfs_uri_extract_short_name (source_uri);
+ ev_window->priv->local_uri = g_strconcat ("file:", tmp_name, "-", base_name, NULL);
+ ev_job_load_set_uri (EV_JOB_LOAD (ev_window->priv->load_job),
+ ev_window->priv->local_uri);
+ g_free (base_name);
+ g_free (tmp_name);
+
+ target_uri = gnome_vfs_uri_new (ev_window->priv->local_uri);
+
+ slist = g_list_prepend (slist, source_uri);
+ tlist = g_list_prepend (tlist, target_uri);
+ gnome_vfs_async_xfer (&handle, slist, tlist,
+ GNOME_VFS_XFER_DEFAULT | GNOME_VFS_XFER_FOLLOW_LINKS,
+ GNOME_VFS_XFER_ERROR_MODE_ABORT,
+ GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE,
+ GNOME_VFS_PRIORITY_DEFAULT,
+ (GnomeVFSAsyncXferProgressCallback)xfer_update_progress_callback,
+ ev_window,
+ NULL, NULL);
+
+ g_list_free (slist);
+ g_list_free (tlist);
+ gnome_vfs_uri_unref (target_uri);
+ gnome_vfs_uri_unref (source_uri);
+
+ return;
+ }
+
+ gnome_vfs_uri_unref (source_uri);
+ ev_job_queue_add_job (ev_window->priv->load_job, EV_JOB_PRIORITY_HIGH);
+}
+
+static void
+file_open_dialog_response_cb (GtkWidget *chooser,
+ gint response_id,
+ EvWindow *ev_window)
+{
+ if (response_id == GTK_RESPONSE_OK) {
+ GSList *uris;
+
+ 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)),
+ GDK_CURRENT_TIME);
+
+ g_slist_foreach (uris, (GFunc)g_free, NULL);
+ g_slist_free (uris);
+ }
+ ev_application_set_chooser_uri (EV_APP,
+ gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (chooser)));
+
+ gtk_widget_destroy (chooser);
+}
+
+static void
+ev_window_cmd_file_open (GtkAction *action, EvWindow *window)
+{
+ GtkWidget *chooser;
+
+ 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);
+ if (ev_application_get_chooser_uri (EV_APP) != NULL) {
+ gtk_file_chooser_set_uri (GTK_FILE_CHOOSER (chooser),
+ ev_application_get_chooser_uri (EV_APP));
+ } else if (window->priv->uri != NULL) {
+ gtk_file_chooser_set_uri (GTK_FILE_CHOOSER (chooser),
+ window->priv->uri);
+ }
+ else {
+ char *folder;
+ folder = xdg_user_dir_lookup ("DOCUMENTS");
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser),
+ folder);
+ free (folder);
+ }
+
+ g_signal_connect (chooser, "response",
+ G_CALLBACK (file_open_dialog_response_cb),
+ window);
+
+ gtk_widget_show (chooser);
+}
+
+static gchar *
+ev_window_create_tmp_symlink (const gchar *filename, GError **error)
+{
+ gchar *tmp_filename = NULL;
+ gchar *name;
+ gint res;
+ guint i = 0;
+
+ name = g_path_get_basename (filename);
+
+ do {
+ gchar *basename;
+
+ if (tmp_filename)
+ g_free (tmp_filename);
+
+ basename = g_strdup_printf ("%s-%d", name, i++);
+ tmp_filename = g_build_filename (ev_tmp_dir (),
+ basename, NULL);
+
+ g_free (basename);
+ } while ((res = symlink (filename, tmp_filename)) != 0 && errno == EEXIST);
+
+ g_free (name);
+
+ if (res != 0 && errno != EEXIST) {
+ if (error) {
+ *error = g_error_new (G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ _("Couldn't create symlink “%s”: %s"),
+ tmp_filename, strerror (errno));
+ }
+
+ g_free (tmp_filename);
+
+ return NULL;
+ }
+
+ return tmp_filename;
+}
+
+static void
+ev_window_cmd_file_open_copy_at_dest (EvWindow *window, EvLinkDest *dest)
+{
+ GError *error = NULL;
+ gchar *symlink_uri;
+ gchar *old_filename;
+ gchar *new_filename;
+ const gchar *uri_unc;
+
+ uri_unc = g_object_get_data (G_OBJECT (window->priv->document),
+ "uri-uncompressed");
+ old_filename = g_filename_from_uri (uri_unc ? uri_unc : window->priv->uri,
+ NULL, NULL);
+ new_filename = ev_window_create_tmp_symlink (old_filename, &error);
+
+ if (error) {
+ ev_window_error_dialog (GTK_WINDOW (window),
+ _("Cannot open a copy."),
+ error);
+
+ g_error_free (error);
+ g_free (old_filename);
+ g_free (new_filename);
+
+ return;
+ }
+
+ g_free (old_filename);
+
+ symlink_uri = g_filename_to_uri (new_filename, NULL, NULL);
+ g_free (new_filename);
+
+ ev_application_open_uri_at_dest (EV_APP,
+ symlink_uri,
+ gtk_window_get_screen (GTK_WINDOW (window)),
+ dest,
+ 0,
+ TRUE,
+ GDK_CURRENT_TIME);
+ g_free (symlink_uri);
+}
+
+static void
+ev_window_cmd_file_open_copy (GtkAction *action, EvWindow *window)
+{
+ EvPageCache *page_cache;
+ EvLinkDest *dest;
+ gint current_page;
+
+ page_cache = ev_page_cache_get (window->priv->document);
+ current_page = ev_page_cache_get_current_page (page_cache);
+
+ dest = ev_link_dest_new_page (current_page);
+ ev_window_cmd_file_open_copy_at_dest (window, dest);
+ g_object_unref (dest);
+}
+
+#ifdef HAVE_GTK_RECENT
+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, FALSE,
+ GDK_CURRENT_TIME);
+}
+#else
+static void
+ev_window_cmd_recent_file_activate (GtkAction *action,
+ EvWindow *ev_window)
+{
+ char *uri;
+ EggRecentItem *item;
+
+ item = egg_recent_view_uimanager_get_item (ev_window->priv->recent_view,
+ action);
+
+ uri = egg_recent_item_get_uri (item);
+
+ ev_application_open_uri (EV_APP, uri, NULL,
+ GDK_CURRENT_TIME, NULL);
+
+ g_free (uri);
+}
+#endif /* HAVE_GTK_RECENT */
+
+static void
+ev_window_add_recent (EvWindow *window, const char *filename)
+{
+#ifdef HAVE_GTK_RECENT
+ gtk_recent_manager_add_item (window->priv->recent_manager, filename);
+#else
+ EggRecentItem *item;
+
+ item = egg_recent_item_new_from_uri (filename);
+ egg_recent_item_add_group (item, "Evince");
+ egg_recent_model_add_full (ev_application_get_recent_model (EV_APP), item);
+#endif /* HAVE_GTK_RECENT */
+}
+
+#ifdef HAVE_GTK_RECENT
+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;
+}
+#endif /* HAVE_GTK_RECENT */
+
+/*
+ * 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;
+
+ g_return_val_if_fail (filename != NULL, NULL);
+
+ length = strlen (filename);
+ str = g_string_sized_new (length + 10);
+ g_string_printf (str, "_%d. ", 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)
+{
+#ifdef HAVE_GTK_RECENT
+ 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 (G_OBJECT (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);
+#else /* HAVE_GTK_RECENT */
+ ev_window->priv->recent_view = egg_recent_view_uimanager_new (ev_window->priv->ui_manager,
+ "/MainMenu/FileMenu/RecentFilesMenu",
+ G_CALLBACK (ev_window_cmd_recent_file_activate),
+ ev_window);
+
+ egg_recent_view_uimanager_show_icons (EGG_RECENT_VIEW_UIMANAGER (ev_window->priv->recent_view), FALSE);
+
+ egg_recent_view_set_model (EGG_RECENT_VIEW (ev_window->priv->recent_view),
+ ev_application_get_recent_model (EV_APP));
+
+ egg_recent_view_uimanager_set_trailing_sep (ev_window->priv->recent_view, TRUE);
+
+ g_signal_connect (ev_window->priv->recent_view, "activate",
+ G_CALLBACK (ev_window_cmd_recent_file_activate), ev_window);
+#endif /* HAVE_GTK_RECENT */
+}
+
+static void
+file_save_dialog_response_cb (GtkWidget *fc,
+ gint response_id,
+ EvWindow *ev_window)
+{
+ const gchar *uri_unc;
+ gint fd;
+ gchar *filename;
+ gchar *tmp_filename;
+ GError *error = NULL;
+
+ if (response_id != GTK_RESPONSE_OK) {
+ gtk_widget_destroy (fc);
+ return;
+ }
+
+
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (fc));
+ tmp_filename = g_strdup_printf ("%s.XXXXXX", filename);
+
+ fd = g_mkstemp (tmp_filename);
+ if (fd == -1) {
+ gchar *display_name;
+ gint save_errno = errno;
+
+ display_name = g_filename_display_name (tmp_filename);
+ g_set_error (&error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (save_errno),
+ _("Failed to create file “%s”: %s"),
+ display_name, g_strerror (save_errno));
+ g_free (display_name);
+ } else {
+ gchar *uri;
+
+ uri = g_filename_to_uri (tmp_filename, NULL, NULL);
+
+ ev_document_doc_mutex_lock ();
+ ev_document_save (ev_window->priv->document, uri, &error);
+ ev_document_doc_mutex_unlock ();
+
+ g_free (uri);
+ close (fd);
+ }
+
+ if (!error) {
+ uri_unc = g_object_get_data (G_OBJECT (ev_window->priv->document),
+ "uri-uncompressed");
+ if (uri_unc) {
+ EvCompressionType ctype;
+ gchar *uri_comp;
+ gchar *uri;
+ const gchar *ext;
+
+ ctype = EV_COMPRESSION_NONE;
+
+ ext = g_strrstr (ev_window->priv->uri, ".gz");
+ if (ext && g_ascii_strcasecmp (ext, ".gz") == 0)
+ ctype = EV_COMPRESSION_GZIP;
+
+ ext = g_strrstr (ev_window->priv->uri, ".bz2");
+ if (ext && g_ascii_strcasecmp (ext, ".bz2") == 0)
+ ctype = EV_COMPRESSION_BZIP2;
+
+ uri = g_filename_to_uri (tmp_filename, NULL, NULL);
+ uri_comp = ev_file_compress (uri, ctype, &error);
+ g_free (uri);
+ g_unlink (tmp_filename);
+ g_free (tmp_filename);
+
+ if (!uri_comp || error) {
+ tmp_filename = NULL;
+ } else {
+ tmp_filename = g_filename_from_uri (uri_comp,
+ NULL, NULL);
+ }
+
+ g_free (uri_comp);
+ }
+ }
+
+ if (tmp_filename && g_rename (tmp_filename, filename) == -1) {
+ g_unlink (tmp_filename);
+ }
+
+ if (error) {
+ gchar *msg;
+ gchar *uri;
+
+ uri = g_filename_to_uri (filename, NULL, NULL);
+ msg = g_strdup_printf (_("The file could not be saved as “%s”."), uri);
+ ev_window_error_dialog (GTK_WINDOW (ev_window), msg, error);
+ g_free (msg);
+ g_free (uri);
+ g_error_free (error);
+ }
+
+ g_free (tmp_filename);
+ g_free (filename);
+
+ gtk_widget_destroy (fc);
+}
+
+static void
+ev_window_cmd_save_as (GtkAction *action, EvWindow *ev_window)
+{
+ GtkWidget *fc;
+ gchar *base_name;
+ gchar *file_name;
+ gchar *folder;
+
+ 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_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER (fc), TRUE);
+ file_name = gnome_vfs_format_uri_for_display (ev_window->priv->uri);
+ base_name = g_path_get_basename (file_name);
+ folder = xdg_user_dir_lookup ("DOCUMENTS");
+ gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (fc), base_name);
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (fc), folder);
+ g_free (file_name);
+ g_free (base_name);
+ free (folder);
+
+ g_signal_connect (fc, "response",
+ G_CALLBACK (file_save_dialog_response_cb),
+ ev_window);
+
+ gtk_widget_show (fc);
+}
+
+#ifdef WITH_GTK_PRINT
+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);
+}
+#endif /* WITH_GTK_PRINT */
+
+static void
+ev_window_cmd_file_print_setup (GtkAction *action, EvWindow *ev_window)
+{
+#ifdef WITH_GTK_PRINT
+ 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);
+#endif /* WITH_GTK_PRINT */
+}
+
+#ifdef WITH_GTK_PRINT
+static void
+ev_window_clear_print_job (EvWindow *window)
+{
+ if (window->priv->print_job) {
+ if (!window->priv->print_job->finished)
+ ev_job_queue_remove_job (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_print_finished (GtkPrintJob *print_job,
+ EvWindow *window,
+ GError *error)
+{
+ 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),
+ error->message);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ }
+}
+
+static void
+ev_window_print_send (EvWindow *window,
+ const gchar *filename)
+{
+ GtkPrintJob *job;
+ GtkPrintSettings *settings;
+ GError *error = NULL;
+
+ if (window->priv->gtk_print_job)
+ g_object_unref (window->priv->gtk_print_job);
+
+ /* 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);
+ gtk_print_settings_set_n_copies (settings, 1);
+ gtk_print_settings_set_page_ranges (settings, NULL, 0);
+ gtk_print_settings_set_page_set (settings, GTK_PAGE_SET_ALL);
+ gtk_print_settings_set_print_pages (settings, GTK_PRINT_PAGES_ALL);
+ gtk_print_settings_set_scale (settings, 1.0);
+ gtk_print_settings_set_collate (settings, FALSE);
+ gtk_print_settings_set_reverse (settings, FALSE);
+
+ job = gtk_print_job_new ("evince-print",
+ window->priv->printer,
+ settings,
+ window->priv->print_page_setup);
+
+ g_object_unref (settings);
+
+ 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 (error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+ev_window_print_job_cb (EvJobPrint *job,
+ EvWindow *window)
+{
+ if (job->error) {
+ g_warning (job->error->message);
+ ev_window_clear_print_job (window);
+ return;
+ }
+
+ g_assert (job->temp_file != NULL);
+
+ ev_window_print_send (window, job->temp_file);
+}
+
+static gboolean
+ev_window_print_dialog_response_cb (GtkDialog *dialog,
+ gint response,
+ EvWindow *window)
+{
+ EvPrintRange *ranges = NULL;
+ EvPrintPageSet page_set;
+ gint n_ranges = 0;
+ gint copies;
+ 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) {
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ window->priv->print_dialog = NULL;
+
+ return FALSE;
+ }
+
+ 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);
+
+ 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)));
+
+ file_format = gtk_print_settings_get (window->priv->print_settings,
+ GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT);
+
+ 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;
+ }
+
+ ev_window_clear_print_job (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);
+
+ switch (print_pages) {
+ case GTK_PRINT_PAGES_CURRENT:
+ ranges = g_new0 (EvPrintRange, 1);
+
+ ranges->start = current_page;
+ ranges->end = current_page;
+ n_ranges = 1;
+
+ break;
+ case GTK_PRINT_PAGES_RANGES: {
+ GtkPageRange *page_range;
+
+ 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));
+ }
+ break;
+ default:
+ break;
+ }
+
+ page_set = (EvPrintPageSet)gtk_print_settings_get_page_set (window->priv->print_settings);
+
+ 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_PIXEL);
+ height = gtk_page_setup_get_paper_height (window->priv->print_page_setup,
+ GTK_UNIT_PIXEL);
+
+ if (scale != 1.0) {
+ width *= scale;
+ height *= scale;
+ }
+
+ 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,
+ copies, collate,
+ reverse);
+
+ 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_queue_add_job (window->priv->print_job, EV_JOB_PRIORITY_LOW);
+
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ window->priv->print_dialog = NULL;
+
+ return TRUE;
+}
+
+void
+ev_window_print_range (EvWindow *ev_window, int first_page, int last_page)
+{
+ GtkWidget *dialog;
+ EvPageCache *page_cache;
+ gint current_page;
+ gint document_last_page;
+ GtkPrintCapabilities capabilities;
+
+ 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;
+ }
+
+ 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);
+
+ if (!ev_window->priv->print_settings)
+ ev_window->priv->print_settings = gtk_print_settings_new ();
+
+ 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 (ev_window->priv->print_settings,
+ GTK_PRINT_PAGES_RANGES);
+ gtk_print_settings_set_page_ranges (ev_window->priv->print_settings,
+ &range, 1);
+ }
+
+ dialog = gtk_print_unix_dialog_new (_("Print"), GTK_WINDOW (ev_window));
+ ev_window->priv->print_dialog = dialog;
+
+ capabilities = GTK_PRINT_CAPABILITY_PAGE_SET |
+ GTK_PRINT_CAPABILITY_COPIES |
+ GTK_PRINT_CAPABILITY_COLLATE |
+ GTK_PRINT_CAPABILITY_REVERSE |
+ GTK_PRINT_CAPABILITY_SCALE |
+ GTK_PRINT_CAPABILITY_GENERATE_PS;
+
+ if (EV_IS_FILE_EXPORTER (ev_window->priv->document) &&
+ ev_file_exporter_format_supported (EV_FILE_EXPORTER (ev_window->priv->document),
+ EV_FILE_FORMAT_PDF)) {
+ capabilities |= GTK_PRINT_CAPABILITY_GENERATE_PDF;
+ }
+
+ 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);
+
+ 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);
+
+ gtk_widget_show (dialog);
+}
+#endif /* WITH_GTK_PRINT */
+
+#ifdef WITH_GNOME_PRINT
+static gboolean
+ev_window_print_dialog_response_cb (GtkDialog *print_dialog,
+ gint response,
+ EvWindow *ev_window)
+{
+ EvPrintJob *print_job;
+ GnomePrintConfig *config;
+
+ if (response != GNOME_PRINT_DIALOG_RESPONSE_PRINT) {
+ gtk_widget_destroy (GTK_WIDGET (print_dialog));
+ ev_window->priv->print_dialog = NULL;
+ g_object_unref (ev_window->priv->print_job);
+ ev_window->priv->print_job = NULL;
+
+ return FALSE;
+ }
+
+ config = gnome_print_dialog_get_config (GNOME_PRINT_DIALOG (print_dialog));
+
+ /* FIXME: Change this when we have the first backend
+ * that can print more than postscript
+ */
+ if (using_pdf_printer (config)) {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (print_dialog), GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ _("Generating PDF is not supported"));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ return FALSE;
+ } else if (!using_postscript_printer (config)) {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (print_dialog), GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ _("Printing is not supported on this printer."));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("You were trying to print to a printer using the “%s” driver. "
+ "This program requires a PostScript printer driver."),
+ gnome_print_config_get (config, (guchar *)"Settings.Engine.Backend.Driver"));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ return FALSE;
+ }
+
+ save_print_config_to_file (config);
+
+ print_job = g_object_new (EV_TYPE_PRINT_JOB,
+ "gnome_print_job", ev_window->priv->print_job,
+ "document", ev_window->priv->document,
+ "print_dialog", print_dialog,
+ NULL);
+
+ if (print_job != NULL) {
+ ev_print_job_print (print_job, GTK_WINDOW (ev_window));
+ g_object_unref (print_job);
+ }
+
+ g_object_unref (config);
+
+ gtk_widget_destroy (GTK_WIDGET (print_dialog));
+ ev_window->priv->print_dialog = NULL;
+ g_object_unref (ev_window->priv->print_job);
+ ev_window->priv->print_job = NULL;
+
+ return FALSE;
+}
+
+void
+ev_window_print_range (EvWindow *ev_window, int first_page, int last_page)
+{
+ GnomePrintConfig *config;
+ gchar *pages_label;
+
+ g_return_if_fail (EV_IS_WINDOW (ev_window));
+ g_return_if_fail (ev_window->priv->document != NULL);
+
+ config = load_print_config_from_file ();
+
+ if (ev_window->priv->print_job == NULL)
+ ev_window->priv->print_job = gnome_print_job_new (config);
+
+ if (ev_window->priv->print_dialog == NULL) {
+ ev_window->priv->print_dialog =
+ gnome_print_dialog_new (ev_window->priv->print_job,
+ (guchar *) _("Print"),
+ (GNOME_PRINT_DIALOG_RANGE |
+ GNOME_PRINT_DIALOG_COPIES));
+ }
+
+ gtk_window_set_transient_for (GTK_WINDOW (ev_window->priv->print_dialog),
+ GTK_WINDOW (ev_window));
+ g_object_unref (config);
+
+ pages_label = g_strconcat (_("Pages"), " ", NULL);
+ gnome_print_dialog_construct_range_page (GNOME_PRINT_DIALOG (ev_window->priv->print_dialog),
+ GNOME_PRINT_RANGE_ALL |
+ GNOME_PRINT_RANGE_RANGE,
+ first_page, last_page,
+ NULL, (const guchar *)pages_label);
+ g_free (pages_label);
+
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (ev_window->priv->print_dialog),
+ GNOME_PRINT_DIALOG_RESPONSE_PREVIEW,
+ FALSE);
+
+ g_signal_connect (G_OBJECT (ev_window->priv->print_dialog), "response",
+ G_CALLBACK (ev_window_print_dialog_response_cb),
+ ev_window);
+ gtk_widget_show (ev_window->priv->print_dialog);
+}
+#endif /* WITH_GNOME_PRINT */
+
+static void
+ev_window_print (EvWindow *window)
+{
+ EvPageCache *page_cache;
+ gint last_page;
+
+ page_cache = ev_page_cache_get (window->priv->document);
+ last_page = ev_page_cache_get_n_pages (page_cache);
+
+#ifdef WITH_PRINT
+ ev_window_print_range (window, 1, last_page);
+#endif
+}
+
+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->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
+ev_window_cmd_file_close_window (GtkAction *action, EvWindow *ev_window)
+{
+ g_return_if_fail (EV_IS_WINDOW (ev_window));
+
+ gtk_widget_destroy (GTK_WIDGET (ev_window));
+}
+
+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);
+
+ 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), EV_SCROLL_PAGE_FORWARD, FALSE);
+}
+
+static void
+ev_window_cmd_scroll_backward (GtkAction *action, EvWindow *window)
+{
+ ev_view_scroll (EV_VIEW (window->priv->view), EV_SCROLL_PAGE_BACKWARD, FALSE);
+}
+
+static void
+ev_window_cmd_continuous (GtkAction *action, EvWindow *ev_window)
+{
+ gboolean continuous;
+
+ ev_window_stop_presentation (ev_window);
+ continuous = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+ g_object_set (G_OBJECT (ev_window->priv->view),
+ "continuous", continuous,
+ NULL);
+ ev_window_update_actions (ev_window);
+}
+
+static void
+ev_window_cmd_dual (GtkAction *action, EvWindow *ev_window)
+{
+ gboolean dual_page;
+
+ ev_window_stop_presentation (ev_window);
+ dual_page = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+ g_object_set (G_OBJECT (ev_window->priv->view),
+ "dual-page", dual_page,
+ NULL);
+ ev_window_update_actions (ev_window);
+}
+
+static void
+ev_window_cmd_view_best_fit (GtkAction *action, EvWindow *ev_window)
+{
+ ev_window_stop_presentation (ev_window);
+
+ if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
+ ev_view_set_sizing_mode (EV_VIEW (ev_window->priv->view), EV_SIZING_BEST_FIT);
+ } else {
+ ev_view_set_sizing_mode (EV_VIEW (ev_window->priv->view), 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);
+
+ if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
+ ev_view_set_sizing_mode (EV_VIEW (ev_window->priv->view), EV_SIZING_FIT_WIDTH);
+ } else {
+ ev_view_set_sizing_mode (EV_VIEW (ev_window->priv->view), 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);
+ 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));
+
+ 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));
+
+ 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_update_fullscreen_popup (EvWindow *window)
+{
+ GtkWidget *popup = window->priv->fullscreen_popup;
+ int popup_width, popup_height;
+ GdkScreen *screen;
+ GdkRectangle screen_rect;
+ gboolean toolbar;
+
+ g_return_if_fail (popup != NULL);
+
+ if (GTK_WIDGET (window)->window == NULL)
+ return;
+
+ toolbar = (window->priv->chrome & EV_CHROME_FULLSCREEN_TOOLBAR) != 0 ||
+ (window->priv->chrome & EV_CHROME_RAISE_TOOLBAR) != 0;
+ popup_width = popup->requisition.width;
+ popup_height = popup->requisition.height;
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (window));
+ gdk_screen_get_monitor_geometry (screen,
+ gdk_screen_get_monitor_at_window
+ (screen,
+ GTK_WIDGET (window)->window),
+ &screen_rect);
+ if (toolbar) {
+ gtk_widget_set_size_request (popup,
+ screen_rect.width,
+ -1);
+ gtk_window_move (GTK_WINDOW (popup),
+ screen_rect.x,
+ screen_rect.y);
+
+ } else {
+ if (gtk_widget_get_direction (popup) == GTK_TEXT_DIR_RTL)
+ {
+ gtk_window_move (GTK_WINDOW (popup),
+ screen_rect.x,
+ screen_rect.y);
+ } else {
+ gtk_window_move (GTK_WINDOW (popup),
+ screen_rect.x + screen_rect.width - popup_width,
+ screen_rect.y);
+ }
+ }
+}
+
+static void
+screen_size_changed_cb (GdkScreen *screen,
+ EvWindow *window)
+{
+ ev_window_update_fullscreen_popup (window);
+}
+
+static void
+ev_window_sidebar_position_change_cb (GObject *object, GParamSpec *pspec,
+ EvWindow *ev_window)
+{
+ if (!ev_window_is_empty (ev_window))
+ ev_metadata_manager_set_int (ev_window->priv->uri, "sidebar_size",
+ gtk_paned_get_position (GTK_PANED (object)));
+}
+
+static void
+destroy_fullscreen_popup (EvWindow *window)
+{
+ if (window->priv->fullscreen_popup != NULL)
+ {
+ gtk_widget_destroy (window->priv->fullscreen_popup);
+ window->priv->fullscreen_popup = NULL;
+ }
+}
+
+static void
+exit_fullscreen_button_clicked_cb (GtkWidget *button, EvWindow *window)
+{
+ GtkAction *action;
+
+ action = gtk_action_group_get_action (window->priv->action_group, "ViewFullscreen");
+ g_return_if_fail (action != NULL);
+
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
+}
+
+static void
+fullscreen_popup_size_request_cb (GtkWidget *popup, GtkRequisition *req, EvWindow *window)
+{
+ ev_window_update_fullscreen_popup (window);
+}
+
+static gboolean
+fullscreen_timeout_cb (EvWindow *window)
+{
+ EvView *view = EV_VIEW (window->priv->view);
+
+ if (!view ||
+ (!ev_view_get_fullscreen (EV_VIEW (view)) &&
+ !ev_view_get_presentation (EV_VIEW (view))))
+ return FALSE;
+
+ update_chrome_flag (window, EV_CHROME_FULLSCREEN_TOOLBAR, FALSE);
+ ev_view_hide_cursor (EV_VIEW (window->priv->view));
+ window->priv->fullscreen_timeout_id = 0;
+
+ return FALSE;
+}
+
+static void
+fullscreen_set_timeout (EvWindow *window)
+{
+ if (window->priv->fullscreen_timeout_id != 0) {
+ g_source_remove (window->priv->fullscreen_timeout_id);
+ }
+
+ window->priv->fullscreen_timeout_id =
+ g_timeout_add (FULLSCREEN_TIMEOUT, (GSourceFunc)fullscreen_timeout_cb, window);
+
+ update_chrome_flag (window, EV_CHROME_FULLSCREEN_TOOLBAR, TRUE);
+ update_chrome_visibility (window);
+ ev_view_show_cursor (EV_VIEW (window->priv->view));
+}
+
+static void
+fullscreen_clear_timeout (EvWindow *window)
+{
+ if (window->priv->fullscreen_timeout_id != 0) {
+ g_source_remove (window->priv->fullscreen_timeout_id);
+ }
+
+ window->priv->fullscreen_timeout_id = 0;
+ update_chrome_visibility (window);
+ ev_view_show_cursor (EV_VIEW (window->priv->view));
+}
+
+
+static gboolean
+fullscreen_motion_notify_cb (GtkWidget *widget,
+ GdkEventMotion *event,
+ gpointer user_data)
+{
+ EvWindow *window = EV_WINDOW (user_data);
+
+ fullscreen_set_timeout (window);
+
+ return FALSE;
+}
+
+static gboolean
+fullscreen_leave_notify_cb (GtkWidget *widget,
+ GdkEventCrossing *event,
+ gpointer user_data)
+{
+ EvWindow *window = EV_WINDOW (user_data);
+
+ fullscreen_clear_timeout (window);
+
+ return FALSE;
+}
+
+static GtkWidget *
+ev_window_get_exit_fullscreen_button (EvWindow *window)
+{
+ GtkWidget *button, *icon, *label, *hbox;
+
+ button = gtk_button_new ();
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (exit_fullscreen_button_clicked_cb),
+ window);
+ gtk_widget_show (button);
+
+ hbox = gtk_hbox_new (FALSE, 2);
+ gtk_widget_show (hbox);
+ gtk_container_add (GTK_CONTAINER (button), hbox);
+
+ icon = gtk_image_new_from_stock (EV_STOCK_LEAVE_FULLSCREEN, GTK_ICON_SIZE_BUTTON);
+ gtk_widget_show (icon);
+ gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 0);
+
+ label = gtk_label_new (_("Leave Fullscreen"));
+ gtk_widget_show (label);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ return button;
+}
+
+static GtkWidget *
+ev_window_create_fullscreen_popup (EvWindow *window)
+{
+ GtkWidget *popup;
+ GtkWidget *hbox;
+ GtkWidget *button;
+ GdkScreen *screen;
+
+ window->priv->fullscreen_toolbar = egg_editable_toolbar_new_with_model
+ (window->priv->ui_manager, ev_application_get_toolbars_model (EV_APP, FALSE), NULL);
+
+ popup = gtk_window_new (GTK_WINDOW_POPUP);
+ hbox = gtk_hbox_new (FALSE, 0);
+ button = ev_window_get_exit_fullscreen_button (window);
+
+ gtk_container_add (GTK_CONTAINER (popup), hbox);
+ gtk_box_pack_start (GTK_BOX (hbox), window->priv->fullscreen_toolbar,
+ TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+
+ gtk_widget_show (button);
+ gtk_widget_show (hbox);
+
+ gtk_window_set_resizable (GTK_WINDOW (popup), FALSE);
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (window));
+ g_signal_connect_object (screen, "size-changed",
+ G_CALLBACK (screen_size_changed_cb),
+ window, 0);
+ g_signal_connect_object (popup, "size_request",
+ G_CALLBACK (fullscreen_popup_size_request_cb),
+ window, 0);
+
+ gtk_window_set_screen (GTK_WINDOW (popup),
+ gtk_widget_get_screen (GTK_WIDGET (window)));
+
+ return popup;
+}
+
+
+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_view_get_fullscreen (EV_VIEW (window->priv->view)));
+ g_signal_handlers_unblock_by_func
+ (action, G_CALLBACK (ev_window_cmd_view_fullscreen), window);
+}
+
+static void
+ev_window_run_fullscreen (EvWindow *window)
+{
+ if (window->priv->fullscreen_popup == NULL)
+ window->priv->fullscreen_popup
+ = ev_window_create_fullscreen_popup (window);
+
+ g_object_set (G_OBJECT (window->priv->scrolled_window),
+ "shadow-type", GTK_SHADOW_NONE,
+ NULL);
+
+ ev_view_set_fullscreen (EV_VIEW (window->priv->view), TRUE);
+ ev_window_update_fullscreen_action (window);
+
+ gtk_window_fullscreen (GTK_WINDOW (window));
+ gtk_widget_grab_focus (window->priv->view);
+ ev_window_update_fullscreen_popup (window);
+
+ g_signal_connect (window->priv->view,
+ "motion-notify-event",
+ G_CALLBACK (fullscreen_motion_notify_cb),
+ window);
+ g_signal_connect (window->priv->view,
+ "leave-notify-event",
+ G_CALLBACK (fullscreen_leave_notify_cb),
+ window);
+ fullscreen_set_timeout (window);
+
+ if (!ev_window_is_empty (window))
+ ev_metadata_manager_set_boolean (window->priv->uri, "fullscreen", TRUE);
+}
+
+static void
+ev_window_stop_fullscreen (EvWindow *window)
+{
+ EvView *view = EV_VIEW (window->priv->view);
+
+ if (!ev_view_get_fullscreen (EV_VIEW (view)))
+ return;
+
+ g_object_set (G_OBJECT (window->priv->scrolled_window),
+ "shadow-type", GTK_SHADOW_IN,
+ NULL);
+
+ ev_view_set_fullscreen (view, FALSE);
+ ev_window_update_fullscreen_action (window);
+ gtk_window_unfullscreen (GTK_WINDOW (window));
+
+ g_signal_handlers_disconnect_by_func (window->priv->view,
+ (gpointer) fullscreen_motion_notify_cb,
+ window);
+ g_signal_handlers_disconnect_by_func (window->priv->view,
+ (gpointer) fullscreen_leave_notify_cb,
+ window);
+ fullscreen_clear_timeout (window);
+
+ if (!ev_window_is_empty (window))
+ ev_metadata_manager_set_boolean (window->priv->uri, "fullscreen", FALSE);
+}
+
+static void
+ev_window_cmd_view_fullscreen (GtkAction *action, EvWindow *window)
+{
+ gboolean fullscreen;
+
+ g_return_if_fail (EV_IS_WINDOW (window));
+ ev_window_stop_presentation (window);
+
+ fullscreen = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+ if (fullscreen) {
+ ev_window_run_fullscreen (window);
+ } else {
+ ev_window_stop_fullscreen (window);
+ }
+}
+
+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_view_get_presentation (EV_VIEW (window->priv->view)));
+ g_signal_handlers_unblock_by_func
+ (action, G_CALLBACK (ev_window_cmd_view_presentation), window);
+}
+
+static void
+ev_window_run_presentation (EvWindow *window)
+{
+ g_object_set (G_OBJECT (window->priv->scrolled_window),
+ "shadow-type", GTK_SHADOW_NONE,
+ NULL);
+
+ ev_view_set_presentation (EV_VIEW (window->priv->view), TRUE);
+ ev_window_update_presentation_action (window);
+
+ gtk_widget_grab_focus (window->priv->view);
+ gtk_window_fullscreen (GTK_WINDOW (window));
+
+ g_signal_connect (window->priv->view,
+ "motion-notify-event",
+ G_CALLBACK (fullscreen_motion_notify_cb),
+ window);
+ g_signal_connect (window->priv->view,
+ "leave-notify-event",
+ G_CALLBACK (fullscreen_leave_notify_cb),
+ window);
+ fullscreen_set_timeout (window);
+
+ ev_application_screensaver_disable (EV_APP);
+
+ if (!ev_window_is_empty (window))
+ ev_metadata_manager_set_boolean (window->priv->uri, "presentation", TRUE);
+}
+
+static void
+ev_window_stop_presentation (EvWindow *window)
+{
+ if (!ev_view_get_presentation (EV_VIEW (window->priv->view)))
+ return;
+
+ g_object_set (G_OBJECT (window->priv->scrolled_window),
+ "shadow-type", GTK_SHADOW_IN,
+ NULL);
+
+ ev_view_set_presentation (EV_VIEW (window->priv->view), FALSE);
+ ev_window_update_presentation_action (window);
+ gtk_window_unfullscreen (GTK_WINDOW (window));
+
+ g_signal_handlers_disconnect_by_func (window->priv->view,
+ (gpointer) fullscreen_motion_notify_cb,
+ window);
+ g_signal_handlers_disconnect_by_func (window->priv->view,
+ (gpointer) fullscreen_leave_notify_cb,
+ window);
+ fullscreen_clear_timeout (window);
+
+ ev_application_screensaver_enable (EV_APP);
+
+ if (!ev_window_is_empty (window))
+ ev_metadata_manager_set_boolean (window->priv->uri, "presentation", FALSE);
+}
+
+static void
+ev_window_cmd_view_presentation (GtkAction *action, EvWindow *window)
+{
+ gboolean presentation;
+
+ g_return_if_fail (EV_IS_WINDOW (window));
+ ev_window_stop_fullscreen (window);
+
+ presentation = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+ if (presentation) {
+ ev_window_run_presentation (window);
+ } else {
+ ev_window_stop_presentation (window);
+ }
+}
+
+static void
+ev_window_run_preview (EvWindow *window)
+{
+ ev_view_set_continuous (EV_VIEW (window->priv->view), FALSE);
+
+ update_chrome_flag (window, EV_CHROME_TOOLBAR, FALSE);
+ update_chrome_flag (window, EV_CHROME_MENUBAR, FALSE);
+ update_chrome_flag (window, EV_CHROME_SIDEBAR, FALSE);
+
+ update_chrome_flag (window, EV_CHROME_PREVIEW_TOOLBAR, TRUE);
+
+ update_chrome_visibility (window);
+}
+
+static gboolean
+ev_window_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
+{
+ EvWindow *window = EV_WINDOW (widget);
+ EvWindowPrivate *priv = window->priv;
+
+ if (ev_view_get_fullscreen (EV_VIEW (priv->view)))
+ fullscreen_set_timeout (window);
+
+ return GTK_WIDGET_CLASS (ev_window_parent_class)->focus_in_event (widget, event);
+}
+
+static gboolean
+ev_window_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
+{
+ EvWindow *window = EV_WINDOW (widget);
+ EvWindowPrivate *priv = window->priv;
+
+ if (ev_view_get_fullscreen (EV_VIEW (priv->view))) {
+ fullscreen_set_timeout (window);
+ gtk_widget_hide (priv->fullscreen_popup);
+ }
+
+ return GTK_WIDGET_CLASS (ev_window_parent_class)->focus_out_event (widget, event);
+}
+
+static void
+ev_window_screen_changed (GtkWidget *widget,
+ GdkScreen *old_screen)
+{
+ EvWindow *window = EV_WINDOW (widget);
+ EvWindowPrivate *priv = window->priv;
+ GdkScreen *screen;
+
+ screen = gtk_widget_get_screen (widget);
+ if (screen == old_screen)
+ return;
+
+#ifdef HAVE_GTK_RECENT
+ if (old_screen) {
+ g_signal_handlers_disconnect_by_func (
+ gtk_recent_manager_get_for_screen (old_screen),
+ G_CALLBACK (ev_window_setup_recent), window);
+ }
+
+ priv->recent_manager = gtk_recent_manager_get_for_screen (screen);
+ g_signal_connect_swapped (priv->recent_manager,
+ "changed",
+ G_CALLBACK (ev_window_setup_recent),
+ window);
+#endif
+
+ ev_view_set_screen_dpi (EV_VIEW (window->priv->view),
+ ev_window_get_screen_dpi (window));
+
+ if (GTK_WIDGET_CLASS (ev_window_parent_class)->screen_changed) {
+ GTK_WIDGET_CLASS (ev_window_parent_class)->screen_changed (widget, old_screen);
+ }
+
+ if (priv->fullscreen_popup != NULL) {