]> www.fi.muni.cz Git - evince.git/blobdiff - shell/ev-sidebar-thumbnails.c
Cr 31 13:27:50 2005 Jonathan Blandford <jrb@redhat.com>
[evince.git] / shell / ev-sidebar-thumbnails.c
index c727abff04f08ecc16bdc0230ed70bcc188807da..b439e4bf7f78337cb6bed7c5c27cd4f12c9c2eb3 100644 (file)
@@ -1,7 +1,7 @@
 /* this file is part of evince, a gnome document viewer
  *
  *  Copyright (C) 2004 Red Hat, Inc.
- *  Copyright (C) 2004 Anders Carlsson <andersca@gnome.org>
+ *  Copyright (C) 2004, 2005 Anders Carlsson <andersca@gnome.org>
  *
  *  Authors:
  *    Jonathan Blandford <jrb@alum.mit.edu>
 
 #include "ev-sidebar-thumbnails.h"
 #include "ev-document-thumbnails.h"
+#include "ev-document-misc.h"
+#include "ev-job-queue.h"
+#include "ev-window.h"
 #include "ev-utils.h"
 
-#define THUMBNAIL_WIDTH 96
+#define THUMBNAIL_WIDTH 100
+
+/* Amount of time we devote to each iteration of the idle, in microseconds */
+#define IDLE_WORK_LENGTH 5000
 
 struct _EvSidebarThumbnailsPrivate {
        GtkWidget *tree_view;
+       GtkAdjustment *vadjustment;
        GtkListStore *list_store;
        EvDocument *document;
-       
-       guint idle_id;
-       gint current_page, n_pages;
+
+       gint n_pages, pages_done;
 };
 
 enum {
        COLUMN_PAGE_STRING,
        COLUMN_PIXBUF,
+       COLUMN_THUMBNAIL_SET,
+       COLUMN_JOB,
        NUM_COLUMNS
 };
 
-static GtkVBoxClass *parent_class;
-
 G_DEFINE_TYPE (EvSidebarThumbnails, ev_sidebar_thumbnails, GTK_TYPE_VBOX);
 
 #define EV_SIDEBAR_THUMBNAILS_GET_PRIVATE(object) \
        (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_SIDEBAR_THUMBNAILS, EvSidebarThumbnailsPrivate));
 
-static void
-ev_sidebar_thumbnails_destroy (GtkObject *object)
-{
-       EvSidebarThumbnails *ev_sidebar_thumbnails = EV_SIDEBAR_THUMBNAILS (object);
-       EvSidebarThumbnailsPrivate *priv = ev_sidebar_thumbnails->priv;
-       
-       if (priv->idle_id != 0) {
-               g_source_remove (priv->idle_id);
-
-               priv->idle_id = 0;
-       }
-       
-       GTK_OBJECT_CLASS (parent_class)->destroy (object);
-}
-
 static void
 ev_sidebar_thumbnails_class_init (EvSidebarThumbnailsClass *ev_sidebar_thumbnails_class)
 {
        GObjectClass *g_object_class;
        GtkObjectClass *gtk_object_class;
-       
+
        g_object_class = G_OBJECT_CLASS (ev_sidebar_thumbnails_class);
        gtk_object_class = GTK_OBJECT_CLASS (ev_sidebar_thumbnails_class);
 
-       parent_class = g_type_class_peek_parent (ev_sidebar_thumbnails_class);
-       
-       gtk_object_class->destroy = ev_sidebar_thumbnails_destroy;
-       
        g_type_class_add_private (g_object_class, sizeof (EvSidebarThumbnailsPrivate));
+}
 
+static void
+adjustment_changed_cb (GtkAdjustment       *adjustment,
+                      EvSidebarThumbnails *ev_sidebar_thumbnails)
+{
+       EvSidebarThumbnailsPrivate *priv;
+       GtkTreePath *path;
+       GtkTreeIter iter;
+       int page;
+       gboolean thumbnail_set;
+
+       priv = ev_sidebar_thumbnails->priv = EV_SIDEBAR_THUMBNAILS_GET_PRIVATE (ev_sidebar_thumbnails);
+
+       gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (priv->tree_view),
+                                      1, 1, &path,
+                                      NULL, NULL, NULL);
+       if (!path)
+               return;
+
+       page = gtk_tree_path_get_indices (path)[0];
+       gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->list_store),
+                                &iter, path);
+       gtk_tree_model_get (GTK_TREE_MODEL (priv->list_store), &iter,
+                           COLUMN_THUMBNAIL_SET, &thumbnail_set,
+                           -1);
+}
+
+static void
+ev_sidebar_tree_selection_changed (GtkTreeSelection *selection,
+                                  EvSidebarThumbnails *ev_sidebar_thumbnails)
+{
+       EvSidebarThumbnailsPrivate *priv;
+       EvPageCache *page_cache;
+       GtkTreePath *path;
+       GtkTreeIter iter;
+       int page;
+
+       priv = ev_sidebar_thumbnails->priv = EV_SIDEBAR_THUMBNAILS_GET_PRIVATE (ev_sidebar_thumbnails);
+
+       if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
+               return;
+
+       path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->list_store),
+                                       &iter);
+       page = gtk_tree_path_get_indices (path)[0];
+       gtk_tree_path_free (path);
+
+       page_cache = ev_document_get_page_cache (priv->document);
+       ev_page_cache_set_current_page (page_cache, page);
 }
 
 static void
@@ -94,20 +130,30 @@ ev_sidebar_thumbnails_init (EvSidebarThumbnails *ev_sidebar_thumbnails)
 {
        GtkWidget *swindow;
        EvSidebarThumbnailsPrivate *priv;
+       GtkCellRenderer *renderer;
+       GtkTreeSelection *selection;
 
        priv = ev_sidebar_thumbnails->priv = EV_SIDEBAR_THUMBNAILS_GET_PRIVATE (ev_sidebar_thumbnails);
 
-       priv->list_store = gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING, GDK_TYPE_PIXBUF);
+       priv->list_store = gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN, EV_TYPE_JOB_THUMBNAIL);
        priv->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (priv->list_store));
 
+       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view));
+       g_signal_connect (selection, "changed",
+                         G_CALLBACK (ev_sidebar_tree_selection_changed), ev_sidebar_thumbnails);
        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->tree_view), FALSE);
+       renderer = g_object_new (GTK_TYPE_CELL_RENDERER_PIXBUF,
+                                "xpad", 2,
+                                "ypad", 2,
+                                NULL);
        gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->tree_view), -1,
-                                                    NULL, gtk_cell_renderer_pixbuf_new (),
-                                                    "pixbuf", 1, NULL);
+                                                    NULL, renderer,
+                                                    "pixbuf", 1,
+                                                    NULL);
        gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->tree_view), -1,
                                                     NULL, gtk_cell_renderer_text_new (),
-                                                    "text", 0, NULL);
-       
+                                                    "markup", 0, NULL);
+
        g_object_unref (priv->list_store);
 
        swindow = gtk_scrolled_window_new (NULL, NULL);
@@ -115,10 +161,13 @@ ev_sidebar_thumbnails_init (EvSidebarThumbnails *ev_sidebar_thumbnails)
                                        GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow),
                                             GTK_SHADOW_IN);
-
+       priv->vadjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (swindow));
+       g_signal_connect (G_OBJECT (priv->vadjustment), "value-changed",
+                         G_CALLBACK (adjustment_changed_cb),
+                         ev_sidebar_thumbnails);
        gtk_container_add (GTK_CONTAINER (swindow), priv->tree_view);
        gtk_box_pack_start (GTK_BOX (ev_sidebar_thumbnails), swindow, TRUE, TRUE, 0);
-       
+
        gtk_widget_show_all (swindow);
 }
 
@@ -132,81 +181,103 @@ ev_sidebar_thumbnails_new (void)
        return ev_sidebar_thumbnails;
 }
 
-static gboolean
-populate_thumbnails (gpointer data)
+static void
+page_changed_cb (EvPageCache         *page_cache,
+                int                  page,
+                EvSidebarThumbnails *sidebar)
 {
-       EvSidebarThumbnails *ev_sidebar_thumbnails = EV_SIDEBAR_THUMBNAILS (data);
-       EvSidebarThumbnailsPrivate *priv = ev_sidebar_thumbnails->priv;
-       GdkPixbuf *tmp, *pixbuf;
        GtkTreePath *path;
-       GtkTreeIter iter;
-       
-       tmp = ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (priv->document),
-                                                      priv->current_page, THUMBNAIL_WIDTH);
+       GtkTreeSelection *selection;
 
+       path = gtk_tree_path_new_from_indices (page, -1);
+       selection = gtk_tree_view_get_selection
+                       (GTK_TREE_VIEW (sidebar->priv->tree_view));
 
-       /* Add shadow */
-       pixbuf = ev_pixbuf_add_shadow (tmp, 5, 0, 0, 0.5);
-       
-       path = gtk_tree_path_new_from_indices (priv->current_page, -1);
-       gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->list_store), &iter, path);
+       gtk_tree_selection_select_path (selection, path);
+       gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (sidebar->priv->tree_view),
+                                     path, NULL, FALSE, 0.0, 0.0);
        gtk_tree_path_free (path);
+}
 
-       gtk_list_store_set (priv->list_store, &iter,
-                           COLUMN_PIXBUF, pixbuf,
+static void
+thumbnail_job_completed_callback (EvJobThumbnail      *job,
+                                 EvSidebarThumbnails *sidebar_thumbnails)
+{
+       EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
+       GtkTreeIter *iter;
+
+       iter = (GtkTreeIter *) g_object_get_data (G_OBJECT (job), "tree_iter");
+       gtk_list_store_set (priv->list_store,
+                           iter,
+                           COLUMN_PIXBUF, job->thumbnail,
+                           COLUMN_THUMBNAIL_SET, TRUE,
+                           COLUMN_JOB, NULL,
                            -1);
-
-       g_object_unref (tmp);
-       g_object_unref (pixbuf);
-       
-       priv->current_page++;
-       
-       if (priv->current_page == priv->n_pages)
-               return FALSE;
-       else
-               return TRUE;
 }
 
 void
 ev_sidebar_thumbnails_set_document (EvSidebarThumbnails *sidebar_thumbnails,
                                    EvDocument          *document)
 {
-       GtkIconTheme *theme;
        GdkPixbuf *loading_icon;
        gint i, n_pages;
+       GtkTreeIter iter;
+       gint width = THUMBNAIL_WIDTH;
+       gint height = THUMBNAIL_WIDTH;
+       EvPageCache *page_cache;
+
        EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
-       
+
        g_return_if_fail (EV_IS_DOCUMENT_THUMBNAILS (document));
 
-       if (priv->idle_id != 0) {
-               g_source_remove (priv->idle_id);
-       }
-       
-       theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (sidebar_thumbnails)));
+       page_cache = ev_document_get_page_cache (document);
+       n_pages = ev_page_cache_get_n_pages (page_cache);
+
+       priv->document = document;
+       priv->n_pages = n_pages;
 
-       loading_icon = gtk_icon_theme_load_icon (theme, "gnome-fs-loading-icon",
-                                                THUMBNAIL_WIDTH, 0, NULL);
+       /* We get the dimensions of the first doc so that we can make a blank
+        * icon.  */
+       g_mutex_lock (EV_DOC_MUTEX);
+       ev_document_thumbnails_get_dimensions (EV_DOCUMENT_THUMBNAILS (priv->document),
+                                              1, THUMBNAIL_WIDTH, &width, &height);
+       g_mutex_unlock (EV_DOC_MUTEX);
 
-       n_pages = ev_document_get_n_pages (document);
-       
+       loading_icon = ev_document_misc_get_thumbnail_frame (width, height, NULL);
+
+       gtk_list_store_clear (priv->list_store);
        for (i = 0; i < n_pages; i++) {
-               GtkTreeIter iter;
-               gchar *page;
-
-               page = g_strdup_printf ("Page %d", i + 1);
-               gtk_list_store_append (sidebar_thumbnails->priv->list_store,
-                                      &iter);
-               gtk_list_store_set (sidebar_thumbnails->priv->list_store,
-                                   &iter,
-                                   COLUMN_PAGE_STRING, page,
+               EvJob *job;
+               gchar *page_label;
+               gchar *page_string;
+
+               job = ev_job_thumbnail_new (priv->document, i, THUMBNAIL_WIDTH);
+               page_label = ev_page_cache_get_page_label (page_cache, i);
+               page_string = g_markup_printf_escaped ("<i>%s</i>", page_label);
+
+               gtk_list_store_append (priv->list_store, &iter);
+               gtk_list_store_set (priv->list_store, &iter,
+                                   COLUMN_PAGE_STRING, page_string,
                                    COLUMN_PIXBUF, loading_icon,
+                                   COLUMN_THUMBNAIL_SET, FALSE,
+                                   COLUMN_JOB, job,
                                    -1);
-               g_free (page);
+               g_free (page_label);
+               g_free (page_string);
+               ev_job_queue_add_job (job, EV_JOB_PRIORITY_LOW);
+               g_object_set_data_full (G_OBJECT (job), "tree_iter",
+                                       gtk_tree_iter_copy (&iter),
+                                       (GDestroyNotify) gtk_tree_iter_free);
+               g_signal_connect (job, "finished",
+                                 G_CALLBACK (thumbnail_job_completed_callback),
+                                 sidebar_thumbnails);
        }
 
-       priv->document = document;
-       priv->idle_id = g_idle_add (populate_thumbnails, sidebar_thumbnails);
-       priv->n_pages = n_pages;
-       priv->current_page = 0;
+       g_object_unref (loading_icon);
+
+       /* Connect to the signal and trigger a fake callback */
+       g_signal_connect (page_cache, "page-changed", G_CALLBACK (page_changed_cb), sidebar_thumbnails);
+       page_changed_cb (page_cache, ev_page_cache_get_current_page (page_cache), sidebar_thumbnails);
+
 }