]> www.fi.muni.cz Git - evince.git/blobdiff - shell/ev-window.c
Fix crash when loading documents with only one page.
[evince.git] / shell / ev-window.c
index 1d36a12b911158e6de38a8dacf8d77a10c58ae00..30f2c20c4f3a7cdf2fce209bf13f9d9e296e71a6 100644 (file)
@@ -177,6 +177,7 @@ struct _EvWindowPrivate {
 #endif
 
        EvJob *load_job;
 #endif
 
        EvJob *load_job;
+       EvJob *thumbnail_job;
 #ifdef WITH_GNOME_PRINT
        GnomePrintJob *print_job;
 #endif
 #ifdef WITH_GNOME_PRINT
        GnomePrintJob *print_job;
 #endif
@@ -217,6 +218,8 @@ static void     ev_window_set_page_mode                 (EvWindow         *windo
                                                         EvWindowPageMode  page_mode);
 static void    ev_window_load_job_cb                   (EvJobLoad        *job,
                                                         gpointer          data);
                                                         EvWindowPageMode  page_mode);
 static void    ev_window_load_job_cb                   (EvJobLoad        *job,
                                                         gpointer          data);
+static void     ev_window_set_icon_from_thumbnail       (EvJobThumbnail   *job,
+                                                        EvWindow         *ev_window);
 #ifdef WITH_GTK_PRINT
 static void     ev_window_print_job_cb                  (EvJobPrint       *job,
                                                         EvWindow         *window);
 #ifdef WITH_GTK_PRINT
 static void     ev_window_print_job_cb                  (EvJobPrint       *job,
                                                         EvWindow         *window);
@@ -401,6 +404,7 @@ ev_window_update_actions (EvWindow *ev_window)
        EvView *view = EV_VIEW (ev_window->priv->view);
        int n_pages = 0, page = -1;
        gboolean has_pages = FALSE;
        EvView *view = EV_VIEW (ev_window->priv->view);
        int n_pages = 0, page = -1;
        gboolean has_pages = FALSE;
+       gboolean presentation_mode;
 
        if (ev_window->priv->document && ev_window->priv->page_cache) {
                page = ev_page_cache_get_current_page (ev_window->priv->page_cache);
 
        if (ev_window->priv->document && ev_window->priv->page_cache) {
                page = ev_page_cache_get_current_page (ev_window->priv->page_cache);
@@ -408,16 +412,31 @@ ev_window_update_actions (EvWindow *ev_window)
                has_pages = n_pages > 0;
        }
 
                has_pages = n_pages > 0;
        }
 
-       ev_window_set_action_sensitive (ev_window, "EditCopy", has_pages && ev_view_get_has_selection (view));
+       ev_window_set_action_sensitive (ev_window, "EditCopy",
+                                       has_pages &&
+                                       ev_view_get_has_selection (view));
        ev_window_set_action_sensitive (ev_window, "EditFindNext",
        ev_window_set_action_sensitive (ev_window, "EditFindNext",
-                             ev_view_can_find_next (view));
+                                       ev_view_can_find_next (view));
        ev_window_set_action_sensitive (ev_window, "EditFindPrevious",
        ev_window_set_action_sensitive (ev_window, "EditFindPrevious",
-                             ev_view_can_find_previous (view));
+                                       ev_view_can_find_previous (view));
 
 
+       presentation_mode = ev_view_get_presentation (view);
+       
        ev_window_set_action_sensitive (ev_window, "ViewZoomIn",
        ev_window_set_action_sensitive (ev_window, "ViewZoomIn",
-                             has_pages && ev_view_can_zoom_in (view));
+                                       has_pages &&
+                                       ev_view_can_zoom_in (view) &&
+                                       !presentation_mode);
        ev_window_set_action_sensitive (ev_window, "ViewZoomOut",
        ev_window_set_action_sensitive (ev_window, "ViewZoomOut",
-                             has_pages && ev_view_can_zoom_out (view));
+                                       has_pages &&
+                                       ev_view_can_zoom_out (view) &&
+                                       !presentation_mode);
+       
+       ev_window_set_action_sensitive (ev_window, "Plus", !presentation_mode);
+       ev_window_set_action_sensitive (ev_window, "Minus", !presentation_mode);
+       ev_window_set_action_sensitive (ev_window, "KpPlus", !presentation_mode);
+       ev_window_set_action_sensitive (ev_window, "KpMinus", !presentation_mode);
+       ev_window_set_action_sensitive (ev_window, "CtrlKpPlus", !presentation_mode);
+       ev_window_set_action_sensitive (ev_window, "CtrlKpMinus", !presentation_mode);
 
         /* Go menu */
        if (has_pages) {
 
         /* Go menu */
        if (has_pages) {
@@ -454,7 +473,7 @@ static void
 ev_window_set_view_accels_sensitivity (EvWindow *window, gboolean sensitive)
 {
        gboolean can_find;
 ev_window_set_view_accels_sensitivity (EvWindow *window, gboolean sensitive)
 {
        gboolean can_find;
-       
+
        can_find = window->priv->document && 
            EV_IS_DOCUMENT_FIND (window->priv->document);
 
        can_find = window->priv->document && 
            EV_IS_DOCUMENT_FIND (window->priv->document);
 
@@ -643,13 +662,116 @@ page_changed_cb (EvPageCache *page_cache,
        if (!ev_window_is_empty (ev_window))
                ev_metadata_manager_set_int (ev_window->priv->uri, "page", page);
 }
        if (!ev_window_is_empty (ev_window))
                ev_metadata_manager_set_int (ev_window->priv->uri, "page", page);
 }
+
+typedef struct _FindTask {
+       const gchar *page_label;
+       gchar *chapter;
+} FindTask;
+
+static gboolean
+ev_window_find_chapter (GtkTreeModel *tree_model,
+                       GtkTreePath  *path,
+                       GtkTreeIter  *iter,
+                       gpointer      data)
+{
+       FindTask *task = (FindTask *)data;
+       gchar *page_string;
+       
+       gtk_tree_model_get (tree_model, iter,
+                           EV_DOCUMENT_LINKS_COLUMN_PAGE_LABEL, &page_string, 
+                           -1);
+       
+       if (!page_string)
+               return FALSE;
+       
+       if (!strcmp (page_string, task->page_label)) {
+               gtk_tree_model_get (tree_model, iter,
+                                   EV_DOCUMENT_LINKS_COLUMN_MARKUP, &task->chapter, 
+                                   -1);
+               g_free (page_string);
+               return TRUE;
+       }
+       
+       g_free (page_string);
+       return FALSE;
+}
+
+static void
+ev_window_add_history (EvWindow *window, gint page, EvLink *link)
+{
+       gchar *page_label = NULL;
+       gchar *link_title;
+       FindTask find_task;
+       EvLink *real_link;
+       EvLinkAction *action;
+       EvLinkDest *dest;
+       
+       if (link) {
+               action = g_object_ref (ev_link_get_action (link));
+               dest = ev_link_action_get_dest (action);
+               page = ev_link_dest_get_page (dest);
+               page_label = ev_view_page_label_from_dest (EV_VIEW (window->priv->view), dest);
+       } else {
+               dest = ev_link_dest_new_page (page);
+               action = ev_link_action_new_dest (dest);
+               page_label = ev_page_cache_get_page_label (window->priv->page_cache, page);
+       }
+
+       if (!page_label)
+               return;
+       
+       find_task.page_label = page_label;
+       find_task.chapter = NULL;
+       
+       if (EV_IS_DOCUMENT_LINKS (window->priv->document) && 
+           ev_document_links_has_document_links (EV_DOCUMENT_LINKS (window->priv->document))) {
+               GtkTreeModel *model;
+       
+               g_object_get (G_OBJECT (window->priv->sidebar_links), "model", &model, NULL);
+               
+               if (model) {
+                       gtk_tree_model_foreach (model,
+                                               ev_window_find_chapter,
+                                               &find_task);
+       
+                       g_object_unref (model);
+               }
+       }
+
+       if (find_task.chapter)
+               link_title = g_strdup_printf (_("Page %s - %s"), page_label, find_task.chapter);
+       else
+               link_title = g_strdup_printf (_("Page %s"), page_label);
+       
+       real_link = ev_link_new (link_title, action);
+       
+       ev_history_add_link (window->priv->history, real_link);
+
+       g_free (find_task.chapter);
+       g_free (link_title);
+       g_free (page_label);
+       g_object_unref (real_link);
+}
+
+static void
+view_handle_link_cb (EvView *view, EvLink *link, EvWindow *window)
+{
+       int current_page = ev_page_cache_get_current_page (window->priv->page_cache);
+       
+       ev_window_add_history (window, 0, link);
+       ev_window_add_history (window, current_page, NULL);
+}
+
 static void
 history_changed_cb (EvPageCache *page_cache,
                    gint         page,
 static void
 history_changed_cb (EvPageCache *page_cache,
                    gint         page,
-                   EvWindow    *ev_window)
+                   EvWindow    *window)
 {
 {
-       ev_history_add_page (ev_window->priv->history, page, 
-                            ev_page_cache_get_page_label (ev_window->priv->page_cache, page));
+       int current_page = ev_page_cache_get_current_page (window->priv->page_cache);
+
+       ev_window_add_history (window, page, NULL);
+       ev_window_add_history (window, current_page, NULL);
+
        return;
 }
 
        return;
 }
 
@@ -799,7 +921,6 @@ setup_size_from_metadata (EvWindow *window)
                g_value_unset (&width_ratio);
                g_value_unset (&height_ratio);
        }
                g_value_unset (&width_ratio);
                g_value_unset (&height_ratio);
        }
-
 }
 
 static void
 }
 
 static void
@@ -895,6 +1016,32 @@ setup_view_from_metadata (EvWindow *window)
        }
 }
 
        }
 }
 
+static void
+ev_window_clear_thumbnail_job (EvWindow *ev_window)
+{
+       if (ev_window->priv->thumbnail_job != NULL) {
+               ev_job_queue_remove_job (ev_window->priv->thumbnail_job);
+
+               g_signal_handlers_disconnect_by_func (ev_window->priv->thumbnail_job,
+                                                     ev_window_set_icon_from_thumbnail,
+                                                     ev_window);
+               g_object_unref (ev_window->priv->thumbnail_job);
+               ev_window->priv->thumbnail_job = NULL;
+       }
+}
+
+static void
+ev_window_set_icon_from_thumbnail (EvJobThumbnail *job,
+                                  EvWindow       *ev_window)
+{
+       if (job->thumbnail) {
+               gtk_window_set_icon (GTK_WINDOW (ev_window),
+                                    job->thumbnail);
+       }
+
+       ev_window_clear_thumbnail_job (ev_window);
+}
+
 static void
 ev_window_setup_document (EvWindow *ev_window)
 {
 static void
 ev_window_setup_document (EvWindow *ev_window)
 {
@@ -906,8 +1053,10 @@ ev_window_setup_document (EvWindow *ev_window)
 
        document = ev_window->priv->document;
        ev_window->priv->page_cache = ev_page_cache_get (ev_window->priv->document);
 
        document = ev_window->priv->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);
+       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);
 
        if (EV_IS_DOCUMENT_FIND (document)) {
                g_signal_connect_object (G_OBJECT (document),
 
        if (EV_IS_DOCUMENT_FIND (document)) {
                g_signal_connect_object (G_OBJECT (document),
@@ -916,6 +1065,27 @@ ev_window_setup_document (EvWindow *ev_window)
                                         ev_window, 0);
        }
 
                                         ev_window, 0);
        }
 
+       if (EV_IS_DOCUMENT_THUMBNAILS (document)) {
+               EvRenderContext *rc;
+               gint page_width, page_height;
+               gdouble scale;
+
+               ev_window_clear_thumbnail_job (ev_window);
+               
+               ev_page_cache_get_size (ev_window->priv->page_cache,
+                                       0, 0, 1.0,
+                                       &page_width, &page_height);
+               scale = (gdouble)128 / (gdouble)page_width;
+               
+               rc = ev_render_context_new (0, 0, scale);
+               ev_window->priv->thumbnail_job = ev_job_thumbnail_new (document, rc);
+               g_signal_connect (ev_window->priv->thumbnail_job, "finished",
+                                 G_CALLBACK (ev_window_set_icon_from_thumbnail),
+                                 ev_window);
+               ev_job_queue_add_job (EV_JOB (ev_window->priv->thumbnail_job), EV_JOB_PRIORITY_LOW);
+               g_object_unref (rc);
+       }
+
        ev_sidebar_set_document (sidebar, document);
 
        if (ev_page_cache_get_n_pages (ev_window->priv->page_cache) > 0) {
        ev_sidebar_set_document (sidebar, document);
 
        if (ev_page_cache_get_n_pages (ev_window->priv->page_cache) > 0) {
@@ -1001,7 +1171,7 @@ ev_window_popup_password_dialog (EvWindow *ev_window)
                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),
                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));
+                                          (gpointer) &(ev_window->priv->password_dialog));
                g_signal_connect (ev_window->priv->password_dialog,
                                  "response",
                                  G_CALLBACK (password_dialog_response),
                g_signal_connect (ev_window->priv->password_dialog,
                                  "response",
                                  G_CALLBACK (password_dialog_response),
@@ -1229,6 +1399,8 @@ ev_window_open_uri (EvWindow       *ev_window,
        if (ev_window->priv->uri)
                g_free (ev_window->priv->uri);
        ev_window->priv->uri = g_strdup (uri);
        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,
        
        ev_window->priv->load_job = ev_job_load_new (uri, dest, mode);
        g_signal_connect (ev_window->priv->load_job,
@@ -1382,8 +1554,12 @@ ev_window_cmd_file_open_copy_at_dest (EvWindow *window, EvLinkDest *dest)
        gchar *symlink_uri;
        gchar *old_filename;
        gchar *new_filename;
        gchar *symlink_uri;
        gchar *old_filename;
        gchar *new_filename;
+       gchar *uri_unc;
 
 
-       old_filename = g_filename_from_uri (window->priv->uri, NULL, NULL);
+       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) {
        new_filename = ev_window_create_tmp_symlink (old_filename, &error);
 
        if (error) {
@@ -2210,7 +2386,7 @@ ev_window_cmd_file_properties (GtkAction *action, EvWindow *ev_window)
                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),
                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));
+                                          (gpointer) &(ev_window->priv->properties));
                gtk_window_set_transient_for (GTK_WINDOW (ev_window->priv->properties),
                                              GTK_WINDOW (ev_window));
        }
                gtk_window_set_transient_for (GTK_WINDOW (ev_window->priv->properties),
                                              GTK_WINDOW (ev_window));
        }
@@ -3013,14 +3189,10 @@ ev_window_cmd_go_backward (GtkAction *action, EvWindow *ev_window)
 static void
 ev_window_cmd_view_reload (GtkAction *action, EvWindow *ev_window)
 {
 static void
 ev_window_cmd_view_reload (GtkAction *action, EvWindow *ev_window)
 {
-       char *uri;
-
-       g_return_if_fail (EV_IS_WINDOW (ev_window));
+       gchar *uri;
 
        uri = g_strdup (ev_window->priv->uri);
 
        uri = g_strdup (ev_window->priv->uri);
-
        ev_window_open_uri (ev_window, uri, NULL, 0, FALSE);
        ev_window_open_uri (ev_window, uri, NULL, 0, FALSE);
-
        g_free (uri);
 }
 
        g_free (uri);
 }
 
@@ -3742,9 +3914,14 @@ ev_window_dispose (GObject *object)
        if (priv->load_job) {
                ev_window_clear_load_job (window);
        }
        if (priv->load_job) {
                ev_window_clear_load_job (window);
        }
+
+       if (priv->thumbnail_job) {
+               ev_window_clear_thumbnail_job (window);
+       }
        
        if (priv->local_uri) {
                ev_window_clear_local_uri (window);
        
        if (priv->local_uri) {
                ev_window_clear_local_uri (window);
+               priv->local_uri = NULL;
        }
        
        ev_window_close_dialogs (window);
        }
        
        ev_window_close_dialogs (window);
@@ -4045,11 +4222,7 @@ static void
 navigation_action_activate_link_cb (EvNavigationAction *action, EvLink *link, EvWindow *window)
 {
        
 navigation_action_activate_link_cb (EvNavigationAction *action, EvLink *link, EvWindow *window)
 {
        
-       g_signal_handlers_block_by_func
-               (window->priv->view, G_CALLBACK (view_handle_link_cb), window);
        ev_view_handle_link (EV_VIEW (window->priv->view), link);
        ev_view_handle_link (EV_VIEW (window->priv->view), link);
-       g_signal_handlers_unblock_by_func
-               (window->priv->view, G_CALLBACK (view_handle_link_cb), window);
        gtk_widget_grab_focus (window->priv->view);
 }
 
        gtk_widget_grab_focus (window->priv->view);
 }
 
@@ -4236,12 +4409,15 @@ window_configure_event_cb (EvWindow *window, GdkEventConfigure *event, gpointer
                        ev_page_cache_get_max_height (window->priv->page_cache, 
                                                      0, 1.0,
                                                      &document_height);                        
                        ev_page_cache_get_max_height (window->priv->page_cache, 
                                                      0, 1.0,
                                                      &document_height);                        
-                       ev_metadata_manager_set_int (uri, "window_x", x);
-                       ev_metadata_manager_set_int (uri, "window_y", y);
                        ev_metadata_manager_set_double (uri, "window_width_ratio", 
                        ev_metadata_manager_set_double (uri, "window_width_ratio", 
-                                                       (double)width/document_width);
+                                                       (double)width / document_width);
                        ev_metadata_manager_set_double (uri, "window_height_ratio", 
                        ev_metadata_manager_set_double (uri, "window_height_ratio", 
-                                                       (double)height/document_height);
+                                                       (double)height / document_height);
+                       
+                       ev_metadata_manager_set_int (uri, "window_x", x);
+                       ev_metadata_manager_set_int (uri, "window_y", y);
+                       ev_metadata_manager_set_int (uri, "window_width", width);
+                       ev_metadata_manager_set_int (uri, "window_height", height);
                }
        }
 
                }
        }
 
@@ -4337,19 +4513,20 @@ do_action_named (EvWindow *window, EvLinkAction *action)
        }
 }
 
        }
 }
 
-static void
-view_handle_link_cb (EvView *view, EvLink *link, EvWindow *window)
-{
-       int current_page = ev_page_cache_get_current_page (window->priv->page_cache);
-       ev_history_add_page (window->priv->history, 
-                            current_page,
-                            ev_page_cache_get_page_label (window->priv->page_cache, current_page));
-}
-
 static void
 view_external_link_cb (EvView *view, EvLinkAction *action, EvWindow *window)
 {
        switch (ev_link_action_get_action_type (action)) {
 static void
 view_external_link_cb (EvView *view, EvLinkAction *action, EvWindow *window)
 {
        switch (ev_link_action_get_action_type (action)) {
+               case EV_LINK_ACTION_TYPE_GOTO_DEST: {
+                       EvLinkDest *dest;
+                       
+                       dest = ev_link_action_get_dest (action);
+                       if (!dest)
+                               return;
+
+                       ev_window_cmd_file_open_copy_at_dest (window, dest);
+               }
+                       break;
                case EV_LINK_ACTION_TYPE_EXTERNAL_URI:
                        launch_external_uri (window, action);
                        break;
                case EV_LINK_ACTION_TYPE_EXTERNAL_URI:
                        launch_external_uri (window, action);
                        break;