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 {
NUM_COLUMNS
};
-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 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,
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
-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
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);
EvDocument *document)
{
EvSidebarThumbnails *sidebar_thumbnails = EV_SIDEBAR_THUMBNAILS (sidebar_page);
- GdkPixbuf *loading_icon;
gint i, n_pages;
GtkTreeIter iter;
gint width = THUMBNAIL_WIDTH;
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);
ev_sidebar_thumbnails_clear_model (sidebar_thumbnails);
for (i = 0; i < n_pages; i++) {
- 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_PIXBUF, priv->loading_icon,
COLUMN_THUMBNAIL_SET, FALSE,
- COLUMN_JOB, job,
-1);
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);
}
- 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);