X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;f=shell%2Fev-sidebar-thumbnails.c;h=a313854c420f8449f3cff31273567858055eb93f;hb=d395ea58afa6744be92e33193881a1d4e6aeefed;hp=c548e297fbc6b77fe9631076562830246e7d375e;hpb=1c0d19bd22598eca159c3febdcdaf4168891cb8f;p=evince.git diff --git a/shell/ev-sidebar-thumbnails.c b/shell/ev-sidebar-thumbnails.c index c548e297..a313854c 100644 --- a/shell/ev-sidebar-thumbnails.c +++ b/shell/ev-sidebar-thumbnails.c @@ -28,7 +28,9 @@ #include #include +#include +#include "ev-sidebar-page.h" #include "ev-sidebar-thumbnails.h" #include "ev-document-thumbnails.h" #include "ev-document-misc.h" @@ -45,9 +47,13 @@ struct _EvSidebarThumbnailsPrivate { GtkWidget *tree_view; GtkAdjustment *vadjustment; GtkListStore *list_store; + GdkPixbuf *loading_icon; EvDocument *document; gint n_pages, pages_done; + + /* Visible pages */ + gint start_page, end_page; }; enum { @@ -58,11 +64,38 @@ enum { NUM_COLUMNS }; -G_DEFINE_TYPE (EvSidebarThumbnails, ev_sidebar_thumbnails, GTK_TYPE_VBOX); +static void ev_sidebar_thumbnails_clear_model (EvSidebarThumbnails *sidebar); +static gboolean ev_sidebar_thumbnails_support_document (EvSidebarPage *sidebar_page, + EvDocument *document); +static void ev_sidebar_thumbnails_page_iface_init (EvSidebarPageIface *iface); +static void ev_sidebar_thumbnails_set_document (EvSidebarPage *sidebar_page, + EvDocument *document); +static const gchar* ev_sidebar_thumbnails_get_label (EvSidebarPage *sidebar_page); +static void thumbnail_job_completed_callback (EvJobThumbnail *job, + EvSidebarThumbnails *sidebar_thumbnails); + +G_DEFINE_TYPE_EXTENDED (EvSidebarThumbnails, + ev_sidebar_thumbnails, + GTK_TYPE_VBOX, + 0, + G_IMPLEMENT_INTERFACE (EV_TYPE_SIDEBAR_PAGE, + ev_sidebar_thumbnails_page_iface_init)) #define EV_SIDEBAR_THUMBNAILS_GET_PRIVATE(object) \ (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_SIDEBAR_THUMBNAILS, EvSidebarThumbnailsPrivate)); + +static void +ev_sidebar_thumbnails_dispose (GObject *object) +{ + EvSidebarThumbnails *sidebar_thumbnails = EV_SIDEBAR_THUMBNAILS (object); + + ev_sidebar_thumbnails_clear_model (sidebar_thumbnails); + g_object_unref (sidebar_thumbnails->priv->loading_icon); + + G_OBJECT_CLASS (ev_sidebar_thumbnails_parent_class)->dispose (object); +} + static void ev_sidebar_thumbnails_class_init (EvSidebarThumbnailsClass *ev_sidebar_thumbnails_class) { @@ -72,33 +105,177 @@ ev_sidebar_thumbnails_class_init (EvSidebarThumbnailsClass *ev_sidebar_thumbnail g_object_class = G_OBJECT_CLASS (ev_sidebar_thumbnails_class); gtk_object_class = GTK_OBJECT_CLASS (ev_sidebar_thumbnails_class); + g_object_class->dispose = ev_sidebar_thumbnails_dispose; + g_type_class_add_private (g_object_class, sizeof (EvSidebarThumbnailsPrivate)); } +GtkWidget * +ev_sidebar_thumbnails_new (void) +{ + GtkWidget *ev_sidebar_thumbnails; + + ev_sidebar_thumbnails = g_object_new (EV_TYPE_SIDEBAR_THUMBNAILS, NULL); + + return ev_sidebar_thumbnails; +} + static void -adjustment_changed_cb (GtkAdjustment *adjustment, - EvSidebarThumbnails *ev_sidebar_thumbnails) +clear_range (EvSidebarThumbnails *sidebar_thumbnails, + gint start_page, + gint end_page) { EvSidebarThumbnailsPrivate *priv; GtkTreePath *path; GtkTreeIter iter; - int page; - gboolean thumbnail_set; + gboolean result; - priv = ev_sidebar_thumbnails->priv = EV_SIDEBAR_THUMBNAILS_GET_PRIVATE (ev_sidebar_thumbnails); + priv = sidebar_thumbnails->priv = EV_SIDEBAR_THUMBNAILS_GET_PRIVATE (sidebar_thumbnails); + + g_assert (start_page <= end_page); + + path = gtk_tree_path_new_from_indices (start_page, -1); + for (result = gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->list_store), &iter, path); + result && start_page <= end_page; + result = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->list_store), &iter), start_page ++) { + EvJobThumbnail *job; + + gtk_tree_model_get (GTK_TREE_MODEL (priv->list_store), + &iter, + COLUMN_JOB, &job, + -1); + + if (job) { + g_signal_handlers_disconnect_by_func (job, thumbnail_job_completed_callback, sidebar_thumbnails); + ev_job_queue_remove_job (EV_JOB (job)); + g_object_unref (job); + } + + gtk_list_store_set (priv->list_store, &iter, + COLUMN_JOB, NULL, + COLUMN_THUMBNAIL_SET, FALSE, + COLUMN_PIXBUF, priv->loading_icon, + -1); + } + gtk_tree_path_free (path); +} + +static void +add_range (EvSidebarThumbnails *sidebar_thumbnails, + gint start_page, + gint end_page) +{ + EvSidebarThumbnailsPrivate *priv; + GtkTreePath *path; + GtkTreeIter iter; + gboolean result; + gint page = start_page; + + priv = sidebar_thumbnails->priv = EV_SIDEBAR_THUMBNAILS_GET_PRIVATE (sidebar_thumbnails); + + g_assert (start_page <= end_page); + + path = gtk_tree_path_new_from_indices (start_page, -1); + for (result = gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->list_store), &iter, path); + result && page <= end_page; + result = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->list_store), &iter), page ++) { + EvJobThumbnail *job; + gboolean thumbnail_set; + + gtk_tree_model_get (GTK_TREE_MODEL (priv->list_store), &iter, + COLUMN_JOB, &job, + COLUMN_THUMBNAIL_SET, &thumbnail_set, + -1); + + if (job == NULL && !thumbnail_set) { + job = (EvJobThumbnail *)ev_job_thumbnail_new (priv->document, page, THUMBNAIL_WIDTH); + ev_job_queue_add_job (EV_JOB (job), EV_JOB_PRIORITY_HIGH); + 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); + gtk_list_store_set (priv->list_store, &iter, + COLUMN_JOB, job, + -1); + /* The queue and the list own a ref to the job now */ + g_object_unref (job); + } else if (job) { + g_object_unref (job); + } + } + gtk_tree_path_free (path); +} + +/* This modifies start */ +static void +update_visible_range (EvSidebarThumbnails *sidebar_thumbnails, + gint start_page, + gint end_page) +{ + EvSidebarThumbnailsPrivate *priv; + int old_start_page, old_end_page; + + priv = sidebar_thumbnails->priv = EV_SIDEBAR_THUMBNAILS_GET_PRIVATE (sidebar_thumbnails); + + old_start_page = priv->start_page; + old_end_page = priv->end_page; + + if (start_page == old_start_page && + end_page == old_end_page) + return; + /* Clear the areas we no longer display */ + if (old_start_page < start_page) + clear_range (sidebar_thumbnails, old_start_page, MIN (start_page - 1, old_end_page)); + + if (old_end_page > end_page) + clear_range (sidebar_thumbnails, MAX (end_page + 1, old_start_page), old_end_page); + + add_range (sidebar_thumbnails, start_page, end_page); + + priv->start_page = start_page; + priv->end_page = end_page; +} + +static void +adjustment_changed_cb (EvSidebarThumbnails *sidebar_thumbnails) +{ + EvSidebarThumbnailsPrivate *priv; + GtkTreePath *path; + GtkTreePath *path2; + gint wy1; + gint wy2; + + priv = sidebar_thumbnails->priv = EV_SIDEBAR_THUMBNAILS_GET_PRIVATE (sidebar_thumbnails); + + if (! GTK_WIDGET_REALIZED (priv->tree_view)) + return; + + gtk_tree_view_tree_to_widget_coords (GTK_TREE_VIEW (priv->tree_view), + 0, (int) priv->vadjustment->value, + NULL, &wy1); + gtk_tree_view_tree_to_widget_coords (GTK_TREE_VIEW (priv->tree_view), + 0, (int) (priv->vadjustment->value + priv->vadjustment->page_size), + NULL, &wy2); gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (priv->tree_view), - 1, 1, &path, + 1, wy1 + 1, &path, NULL, NULL, NULL); - if (!path) - return; + gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (priv->tree_view), + 1, wy2 -1, &path2, + NULL, NULL, NULL); + if (path == NULL) + path = gtk_tree_path_new_first (); + if (path2 == NULL) + path2 = gtk_tree_path_new_from_indices (priv->n_pages, + -1); + update_visible_range (sidebar_thumbnails, + gtk_tree_path_get_indices (path)[0], + gtk_tree_path_get_indices (path2)[0]); - 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); + gtk_tree_path_free (path); + gtk_tree_path_free (path2); } static void @@ -118,13 +295,19 @@ ev_sidebar_tree_selection_changed (GtkTreeSelection *selection, path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->list_store), &iter); - page = gtk_tree_path_get_indices (path)[0] + 1; + 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); } +GtkWidget * +ev_sidebar_thumbnails_get_treeview (EvSidebarThumbnails *sidebar) +{ + return sidebar->priv->tree_view; +} + static void ev_sidebar_thumbnails_init (EvSidebarThumbnails *ev_sidebar_thumbnails) { @@ -162,40 +345,30 @@ ev_sidebar_thumbnails_init (EvSidebarThumbnails *ev_sidebar_thumbnails) 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); + g_signal_connect_data (G_OBJECT (priv->vadjustment), "value-changed", + G_CALLBACK (adjustment_changed_cb), + ev_sidebar_thumbnails, NULL, + G_CONNECT_SWAPPED | G_CONNECT_AFTER); + g_signal_connect_swapped (G_OBJECT (swindow), "size-allocate", + 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); } -GtkWidget * -ev_sidebar_thumbnails_new (void) -{ - GtkWidget *ev_sidebar_thumbnails; - - ev_sidebar_thumbnails = g_object_new (EV_TYPE_SIDEBAR_THUMBNAILS, NULL); - - return ev_sidebar_thumbnails; -} - static void page_changed_cb (EvPageCache *page_cache, int page, EvSidebarThumbnails *sidebar) { + GtkTreeView *tree_view = GTK_TREE_VIEW (sidebar->priv->tree_view); GtkTreePath *path; - GtkTreeSelection *selection; - - path = gtk_tree_path_new_from_indices (page - 1, -1); - selection = gtk_tree_view_get_selection - (GTK_TREE_VIEW (sidebar->priv->tree_view)); - 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); + path = gtk_tree_path_new_from_indices (page, -1); + gtk_tree_view_set_cursor (tree_view, path, NULL, FALSE); + gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0); gtk_tree_path_free (path); } @@ -215,14 +388,13 @@ thumbnail_job_completed_callback (EvJobThumbnail *job, -1); } -void -ev_sidebar_thumbnails_set_document (EvSidebarThumbnails *sidebar_thumbnails, +static void +ev_sidebar_thumbnails_set_document (EvSidebarPage *sidebar_page, EvDocument *document) { - GdkPixbuf *loading_icon; + EvSidebarThumbnails *sidebar_thumbnails = EV_SIDEBAR_THUMBNAILS (sidebar_page); gint i, n_pages; GtkTreeIter iter; - gchar *page; gint width = THUMBNAIL_WIDTH; gint height = THUMBNAIL_WIDTH; EvPageCache *page_cache; @@ -239,42 +411,86 @@ ev_sidebar_thumbnails_set_document (EvSidebarThumbnails *sidebar_thumbnails, /* We get the dimensions of the first doc so that we can make a blank * icon. */ - g_mutex_lock (EV_DOC_MUTEX); + ev_document_doc_mutex_lock (); ev_document_thumbnails_get_dimensions (EV_DOCUMENT_THUMBNAILS (priv->document), - 1, THUMBNAIL_WIDTH, &width, &height); - g_mutex_unlock (EV_DOC_MUTEX); + 0, THUMBNAIL_WIDTH, &width, &height); + ev_document_doc_mutex_unlock (); - loading_icon = ev_document_misc_get_thumbnail_frame (width, height, NULL); + if (priv->loading_icon) + g_object_unref (priv->loading_icon); + priv->loading_icon = ev_document_misc_get_thumbnail_frame (width, height, NULL); - gtk_list_store_clear (priv->list_store); - for (i = 1; i <= n_pages; i++) { - EvJob *job; + ev_sidebar_thumbnails_clear_model (sidebar_thumbnails); + for (i = 0; i < n_pages; i++) { + gchar *page_label; + gchar *page_string; + + page_label = ev_page_cache_get_page_label (page_cache, i); + page_string = g_markup_printf_escaped ("%s", page_label); - /* FIXME: Bah. This is still -1 for some reason. Need to track it down.. */ - job = ev_job_thumbnail_new (priv->document, i - 1, THUMBNAIL_WIDTH); - page = g_strdup_printf ("%d", i); gtk_list_store_append (priv->list_store, &iter); gtk_list_store_set (priv->list_store, &iter, - COLUMN_PAGE_STRING, page, - COLUMN_PIXBUF, loading_icon, + COLUMN_PAGE_STRING, page_string, + COLUMN_PIXBUF, priv->loading_icon, COLUMN_THUMBNAIL_SET, FALSE, - COLUMN_JOB, job, -1); - g_free (page); - 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); + g_free (page_label); + g_free (page_string); } - 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); } +static gboolean +ev_sidebar_thumbnails_clear_job (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + EvJob *job; + + gtk_tree_model_get (model, iter, COLUMN_JOB, &job, -1); + + if (job != NULL) { + ev_job_queue_remove_job (job); + g_signal_handlers_disconnect_by_func (job, thumbnail_job_completed_callback, data); + g_object_unref (job); + } + + return FALSE; +} + +static void +ev_sidebar_thumbnails_clear_model (EvSidebarThumbnails *sidebar_thumbnails) +{ + EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv; + + gtk_tree_model_foreach (GTK_TREE_MODEL (priv->list_store), ev_sidebar_thumbnails_clear_job, sidebar_thumbnails); + gtk_list_store_clear (priv->list_store); +} + +static gboolean +ev_sidebar_thumbnails_support_document (EvSidebarPage *sidebar_page, + EvDocument *document) +{ + return (EV_IS_DOCUMENT_THUMBNAILS (document) && + (ev_document_get_n_pages (document) > 1)); +} + +static const gchar* +ev_sidebar_thumbnails_get_label (EvSidebarPage *sidebar_page) +{ + return _("Thumbnails"); +} + +static void +ev_sidebar_thumbnails_page_iface_init (EvSidebarPageIface *iface) +{ + iface->support_document = ev_sidebar_thumbnails_support_document; + iface->set_document = ev_sidebar_thumbnails_set_document; + iface->get_label = ev_sidebar_thumbnails_get_label; +} +