From 1c0d19bd22598eca159c3febdcdaf4168891cb8f Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Wed, 23 Mar 2005 11:07:32 +0000 Subject: merge evince-threads branch --- (limited to 'shell') diff --git a/shell/Makefile.am b/shell/Makefile.am index 0ae0958..a14f2a0 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -29,6 +29,8 @@ evince_SOURCES= \ ev-password.c \ ev-password-view.h \ ev-password-view.c \ + ev-pixbuf-cache.c \ + ev-pixbuf-cache.h \ ev-print-job.c \ ev-print-job.h \ ev-utils.c \ diff --git a/shell/ev-pixbuf-cache.c b/shell/ev-pixbuf-cache.c new file mode 100644 index 0000000..7d076db --- /dev/null +++ b/shell/ev-pixbuf-cache.c @@ -0,0 +1,525 @@ +#include "ev-pixbuf-cache.h" +#include "ev-job-queue.h" + + +typedef struct _CacheJobInfo +{ + EvJob *job; + GdkPixbuf *pixbuf; +} CacheJobInfo; + +struct _EvPixbufCache +{ + GObject parent; + + EvDocument *document; + int start_page; + int end_page; + + /* preload_cache_size is the number of pages prior to the current + * visible area that we cache. It's normally 1, but could be 2 in the + * case of twin pages. + */ + int preload_cache_size; + CacheJobInfo *prev_job; + CacheJobInfo *job_list; + CacheJobInfo *next_job; +}; + +struct _EvPixbufCacheClass +{ + GObjectClass parent_class; + + void (* job_finished) (EvPixbufCache *pixbuf_cache); +}; + + +enum +{ + JOB_FINISHED, + N_SIGNALS, +}; + +static guint signals[N_SIGNALS] = {0, }; + +static void ev_pixbuf_cache_init (EvPixbufCache *pixbuf_cache); +static void ev_pixbuf_cache_class_init (EvPixbufCacheClass *pixbuf_cache); +static void ev_pixbuf_cache_finalize (GObject *object); +static void ev_pixbuf_cache_dispose (GObject *object); +static void job_finished_cb (EvJob *job, + EvPixbufCache *pixbuf_cache); +static CacheJobInfo *find_job_cache (EvPixbufCache *pixbuf_cache, + int page); + + + +/* These are used for iterating through the prev and next arrays */ +#define FIRST_VISABLE_PREV(pixbuf_cache) \ + (MAX (0, pixbuf_cache->preload_cache_size + 1 - pixbuf_cache->start_page)) +#define VISIBLE_NEXT_LEN(pixbuf_cache, page_cache) \ + (MIN(pixbuf_cache->preload_cache_size, ev_page_cache_get_n_pages (page_cache) - pixbuf_cache->end_page)) +#define PAGE_CACHE_LEN(pixbuf_cache) \ + ((pixbuf_cache->end_page - pixbuf_cache->start_page) + 1) + +G_DEFINE_TYPE (EvPixbufCache, ev_pixbuf_cache, G_TYPE_OBJECT) + +static void +ev_pixbuf_cache_init (EvPixbufCache *pixbuf_cache) +{ + pixbuf_cache->start_page = 1; + pixbuf_cache->end_page = 1; + pixbuf_cache->job_list = g_new0 (CacheJobInfo, PAGE_CACHE_LEN (pixbuf_cache)); + + pixbuf_cache->preload_cache_size = 1; + pixbuf_cache->prev_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size); + pixbuf_cache->next_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size); +} + +static void +ev_pixbuf_cache_class_init (EvPixbufCacheClass *class) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (class); + + object_class->finalize = ev_pixbuf_cache_finalize; + object_class->dispose = ev_pixbuf_cache_dispose; + + signals[JOB_FINISHED] = g_signal_new ("job-finished", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EvPixbufCacheClass, job_finished), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +ev_pixbuf_cache_finalize (GObject *object) +{ + EvPixbufCache *pixbuf_cache; + + pixbuf_cache = EV_PIXBUF_CACHE (object); + + g_free (pixbuf_cache->prev_job); + g_free (pixbuf_cache->job_list); + g_free (pixbuf_cache->next_job); +} + +static void +dispose_cache_job_info (CacheJobInfo *job_info, + gpointer data) +{ + if (job_info == NULL) + return; + if (job_info->job) { + g_signal_handlers_disconnect_by_func (job_info->job, + G_CALLBACK (job_finished_cb), + data); + g_object_unref (G_OBJECT (job_info->job)); + job_info->job = NULL; + } + if (job_info->pixbuf) { + g_object_unref (G_OBJECT (job_info->pixbuf)); + job_info->pixbuf = NULL; + } +} + +static void +ev_pixbuf_cache_dispose (GObject *object) +{ + EvPixbufCache *pixbuf_cache; + int i; + + pixbuf_cache = EV_PIXBUF_CACHE (object); + + for (i = 0; i < pixbuf_cache->preload_cache_size; i++) { + dispose_cache_job_info (pixbuf_cache->prev_job + i, pixbuf_cache); + dispose_cache_job_info (pixbuf_cache->next_job + i, pixbuf_cache); + } + + for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) { + dispose_cache_job_info (pixbuf_cache->job_list + i, pixbuf_cache); + } +} + + +EvPixbufCache * +ev_pixbuf_cache_new (EvDocument *document) +{ + EvPixbufCache *pixbuf_cache; + + pixbuf_cache = (EvPixbufCache *) g_object_new (EV_TYPE_PIXBUF_CACHE, NULL); + pixbuf_cache->document = document; + + return pixbuf_cache; +} + +static void +job_finished_cb (EvJob *job, + EvPixbufCache *pixbuf_cache) +{ + CacheJobInfo *job_info; + EvJobRender *job_render = EV_JOB_RENDER (job); + GdkPixbuf *pixbuf; + + /* If the job is outside of our interest, we silently discard it */ + if ((job_render->page < (pixbuf_cache->start_page - pixbuf_cache->preload_cache_size)) || + (job_render->page > (pixbuf_cache->end_page + pixbuf_cache->preload_cache_size))) { + g_object_unref (job); + return; + } + + job_info = find_job_cache (pixbuf_cache, job_render->page); + + pixbuf = g_object_ref (job_render->pixbuf); + if (job_info->pixbuf) + g_object_unref (job_info->pixbuf); + job_info->pixbuf = pixbuf; + + if (job_info->job == job) + job_info->job = NULL; + g_object_unref (job); + + g_signal_emit (pixbuf_cache, signals[JOB_FINISHED], 0); +} + +/* This checks a job to see if the job would generate the right sized pixbuf + * given a scale. If it won't, it removes the job and clears it to NULL. + */ +static void +check_job_size_and_unref (CacheJobInfo *job_info, + EvPageCache *page_cache, + gfloat scale) +{ + gint width; + gint height; + + g_assert (job_info); + + if (job_info->job == NULL) + return; + + ev_page_cache_get_size (page_cache, + EV_JOB_RENDER (job_info->job)->page, + scale, + &width, &height); + + if (width == EV_JOB_RENDER (job_info->job)->target_width && + height == EV_JOB_RENDER (job_info->job)->target_height) + return; + + /* Try to remove the job. If we can't, then the thread has already + * picked it up and we are going get a signal when it's done. If we + * can, then the job is fully dead and will never rnu.. */ + if (ev_job_queue_remove_job (job_info->job)) + g_object_unref (job_info->job); + + job_info->job = NULL; +} + +/* Do all function that copies a job from an older cache to it's position in the + * new cache. It clears the old job if it doesn't have a place. + */ +static void +move_one_job (CacheJobInfo *job_info, + EvPixbufCache *pixbuf_cache, + int page, + CacheJobInfo *new_job_list, + CacheJobInfo *new_prev_job, + CacheJobInfo *new_next_job, + int start_page, + int end_page, + EvJobPriority priority) +{ + CacheJobInfo *target_page = NULL; + int page_offset; + EvJobPriority new_priority; + + if (page < (start_page - pixbuf_cache->preload_cache_size) || + page > (end_page + pixbuf_cache->preload_cache_size)) { + dispose_cache_job_info (job_info, pixbuf_cache); + return; + } + + /* find the target page to copy it over to. */ + if (page < start_page) { + page_offset = (page - (start_page - pixbuf_cache->preload_cache_size)); + + g_assert (page_offset >= 0 && + page_offset < pixbuf_cache->preload_cache_size); + target_page = new_prev_job + page_offset; + new_priority = EV_JOB_PRIORITY_LOW; + } else if (page > end_page) { + page_offset = (page - (end_page + 1)); + + g_assert (page_offset >= 0 && + page_offset < pixbuf_cache->preload_cache_size); + target_page = new_next_job + page_offset; + new_priority = EV_JOB_PRIORITY_LOW; + } else { + page_offset = page - start_page; + g_assert (page_offset >= 0 && + page_offset <= ((end_page - start_page) + 1)); + new_priority = EV_JOB_PRIORITY_HIGH; + target_page = new_job_list + page_offset; + } + + *target_page = *job_info; + job_info->job = NULL; + job_info->pixbuf = NULL; + + if (new_priority != priority && target_page->job) { + g_print ("FIXME: update priority \n"); + } +} + + + +static void +ev_pixbuf_cache_update_range (EvPixbufCache *pixbuf_cache, + gint start_page, + gint end_page) +{ + CacheJobInfo *new_job_list; + CacheJobInfo *new_prev_job; + CacheJobInfo *new_next_job; + EvPageCache *page_cache; + int i, page; + + if (pixbuf_cache->start_page == start_page && + pixbuf_cache->end_page == end_page) + return; + + page_cache = ev_document_get_page_cache (pixbuf_cache->document); + + new_job_list = g_new0 (CacheJobInfo, (end_page - start_page) + 1); + new_prev_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size); + new_next_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size); + + /* We go through each job in the old cache and either clear it or move + * it to a new location. */ + + /* Start with the prev cache. */ + page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size; + for (i = 0; i < pixbuf_cache->preload_cache_size; i++) { + if (page < 1) { + dispose_cache_job_info (pixbuf_cache->prev_job + i, pixbuf_cache); + } else { + move_one_job (pixbuf_cache->prev_job + i, + pixbuf_cache, page, + new_job_list, new_prev_job, new_next_job, + start_page, end_page, EV_JOB_PRIORITY_LOW); + } + page ++; + } + + page = pixbuf_cache->start_page; + for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) { + move_one_job (pixbuf_cache->job_list + i, + pixbuf_cache, page, + new_job_list, new_prev_job, new_next_job, + start_page, end_page, EV_JOB_PRIORITY_HIGH); + page++; + } + + for (i = 0; i < pixbuf_cache->preload_cache_size; i++) { + if (page > ev_page_cache_get_n_pages (page_cache)) { + dispose_cache_job_info (pixbuf_cache->next_job + i, pixbuf_cache); + } else { + move_one_job (pixbuf_cache->next_job + i, + pixbuf_cache, page, + new_job_list, new_prev_job, new_next_job, + start_page, end_page, EV_JOB_PRIORITY_LOW); + } + page ++; + } + + g_free (pixbuf_cache->job_list); + g_free (pixbuf_cache->prev_job); + g_free (pixbuf_cache->next_job); + + pixbuf_cache->job_list = new_job_list; + pixbuf_cache->prev_job = new_prev_job; + pixbuf_cache->next_job = new_next_job; + + pixbuf_cache->start_page = start_page; + pixbuf_cache->end_page = end_page; +} + +static CacheJobInfo * +find_job_cache (EvPixbufCache *pixbuf_cache, + int page) +{ + int page_offset; + + if (page < (pixbuf_cache->start_page - pixbuf_cache->preload_cache_size) || + page > (pixbuf_cache->end_page + pixbuf_cache->preload_cache_size)) + return NULL; + + if (page < pixbuf_cache->start_page) { + page_offset = (page - (pixbuf_cache->start_page - pixbuf_cache->preload_cache_size)); + + g_assert (page_offset >= 0 && + page_offset < pixbuf_cache->preload_cache_size); + return pixbuf_cache->prev_job + page_offset; + } + + if (page > pixbuf_cache->end_page) { + page_offset = (page - (pixbuf_cache->end_page + 1)); + + g_assert (page_offset >= 0 && + page_offset < pixbuf_cache->preload_cache_size); + return pixbuf_cache->next_job + page_offset; + } + + page_offset = page - pixbuf_cache->start_page; + g_assert (page_offset >= 0 && + page_offset <= PAGE_CACHE_LEN(pixbuf_cache)); + return pixbuf_cache->job_list + page_offset; +} + +static void +ev_pixbuf_cache_clear_job_sizes (EvPixbufCache *pixbuf_cache, + gfloat scale) +{ + EvPageCache *page_cache; + int i; + + page_cache = ev_document_get_page_cache (pixbuf_cache->document); + + for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) { + check_job_size_and_unref (pixbuf_cache->job_list + i, page_cache, scale); + } + + for (i = 0; i < pixbuf_cache->preload_cache_size; i++) { + check_job_size_and_unref (pixbuf_cache->prev_job + i, page_cache, scale); + check_job_size_and_unref (pixbuf_cache->next_job + i, page_cache, scale); + } +} + +#define FIRST_VISABLE_PREV(pixbuf_cache) \ + (MAX (0, pixbuf_cache->preload_cache_size + 1 - pixbuf_cache->start_page)) + +static void +add_job_if_needed (EvPixbufCache *pixbuf_cache, + CacheJobInfo *job_info, + EvPageCache *page_cache, + gint page, + gfloat scale, + EvJobPriority priority) +{ + int width, height; + + if (job_info->job) + return; + + ev_page_cache_get_size (page_cache, + page, scale, + &width, &height); + + if (job_info->pixbuf && + gdk_pixbuf_get_width (job_info->pixbuf) == width && + gdk_pixbuf_get_height (job_info->pixbuf) == height) + return; + + /* make a new job now */ + job_info->job = ev_job_render_new (pixbuf_cache->document, + page, scale, + width, height); + ev_job_queue_add_job (job_info->job, priority); + g_signal_connect (job_info->job, "finished", G_CALLBACK (job_finished_cb), pixbuf_cache); +} + + +static void +ev_pixbuf_cache_add_jobs_if_needed (EvPixbufCache *pixbuf_cache, + gfloat scale) +{ + EvPageCache *page_cache; + CacheJobInfo *job_info; + int page; + int i; + + page_cache = ev_document_get_page_cache (pixbuf_cache->document); + + for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) { + job_info = (pixbuf_cache->job_list + i); + page = pixbuf_cache->start_page + i; + + add_job_if_needed (pixbuf_cache, job_info, + page_cache, page, scale, + EV_JOB_PRIORITY_HIGH); + } + + for (i = FIRST_VISABLE_PREV(pixbuf_cache); i < pixbuf_cache->preload_cache_size; i++) { + job_info = (pixbuf_cache->prev_job + i); + page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size + i; + + add_job_if_needed (pixbuf_cache, job_info, + page_cache, page, scale, + EV_JOB_PRIORITY_LOW); + } + + for (i = 0; i < VISIBLE_NEXT_LEN(pixbuf_cache, page_cache); i++) { + job_info = (pixbuf_cache->next_job + i); + page = pixbuf_cache->end_page + 1 + i; + + add_job_if_needed (pixbuf_cache, job_info, + page_cache, page, scale, + EV_JOB_PRIORITY_LOW); + } + +} + +void +ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache, + gint start_page, + gint end_page, + gfloat scale) +{ + EvPageCache *page_cache; + + g_return_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache)); + + page_cache = ev_document_get_page_cache (pixbuf_cache->document); + + g_return_if_fail (start_page > 0 && start_page <= ev_page_cache_get_n_pages (page_cache)); + g_return_if_fail (end_page > 0 && end_page <= ev_page_cache_get_n_pages (page_cache)); + g_return_if_fail (end_page >= start_page); + + /* First, resize the page_range as needed. We cull old pages + * mercilessly. */ + ev_pixbuf_cache_update_range (pixbuf_cache, start_page, end_page); + + /* Then, we update the current jobs to see if any of them are the wrong + * size, we remove them if we need to. */ + ev_pixbuf_cache_clear_job_sizes (pixbuf_cache, scale); + + /* Finally, we add the new jobs for all the sizes that don't have a + * pixbuf */ + ev_pixbuf_cache_add_jobs_if_needed (pixbuf_cache, scale); +} + +GdkPixbuf * +ev_pixbuf_cache_get_pixbuf (EvPixbufCache *pixbuf_cache, + gint page) +{ + CacheJobInfo *job_info; + + job_info = find_job_cache (pixbuf_cache, page); + if (job_info == NULL) + return NULL; + + /* We don't need to wait for the idle to handle the callback */ + if (job_info->job && + EV_JOB (job_info->job)->finished) { + GdkPixbuf *pixbuf; + + pixbuf = g_object_ref (EV_JOB_RENDER (job_info->job)->pixbuf); + dispose_cache_job_info (job_info, pixbuf_cache); + job_info->pixbuf = pixbuf; + } + + return job_info->pixbuf; +} diff --git a/shell/ev-pixbuf-cache.h b/shell/ev-pixbuf-cache.h new file mode 100644 index 0000000..e49faa0 --- /dev/null +++ b/shell/ev-pixbuf-cache.h @@ -0,0 +1,51 @@ +/* this file is part of evince, a gnome document viewer + * + * Copyright (C) 2005 Red Hat, Inc + * + * Evince is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Evince is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __EV_PIXBUF_CACHE_H__ +#define __EV_PIXBUF_CACHE_H__ + +#include +#include "ev-document.h" +#include "ev-job-queue.h" + +G_BEGIN_DECLS + +#define EV_TYPE_PIXBUF_CACHE (ev_pixbuf_cache_get_type ()) +#define EV_PIXBUF_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_PIXBUF_CACHE, EvPixbufCache)) +#define EV_IS_PIXBUF_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_PIXBUF_CACHE)) + +/* This is basically an extention of ev-view.c, and is out here just to keep + * ev-view.c from exploding. + */ + +typedef struct _EvPixbufCache EvPixbufCache; +typedef struct _EvPixbufCacheClass EvPixbufCacheClass; + +GType ev_pixbuf_cache_get_type (void) G_GNUC_CONST; +EvPixbufCache *ev_pixbuf_cache_new (EvDocument *document); +void ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache, + gint start_page, + gint end_page, + gfloat scale); +GdkPixbuf *ev_pixbuf_cache_get_pixbuf (EvPixbufCache *pixbuf_cache, + gint page); + +G_END_DECLS + +#endif /* __EV_PIXBUF_CACHE_H__ */ diff --git a/shell/ev-print-job.c b/shell/ev-print-job.c index 0c66b81..ba283ff 100644 --- a/shell/ev-print-job.c +++ b/shell/ev-print-job.c @@ -224,31 +224,40 @@ ev_print_job_use_print_dialog_settings (EvPrintJob *job, GnomePrintDialog *dialo gnome_print_config_get_page_size (print_config, &job->width, &job->height); gnome_print_config_get_boolean (print_config, - GNOME_PRINT_KEY_DUPLEX, &job->duplex); + (guchar *)GNOME_PRINT_KEY_DUPLEX, &job->duplex); gnome_print_config_unref (print_config); } static gboolean idle_print_handler (EvPrintJob *job) { + EvPageCache *page_cache; + if (!job->printing) { + g_mutex_lock (EV_DOC_MUTEX); ev_ps_exporter_begin (EV_PS_EXPORTER (job->document), job->temp_file); + g_mutex_unlock (EV_DOC_MUTEX); job->next_page = 1; /* FIXME use 0-based page numbering? */ job->printing = TRUE; return TRUE; } - if (job->next_page <= ev_document_get_n_pages (job->document)) { + page_cache = ev_document_get_page_cache (job->document); + if (job->next_page <= ev_page_cache_get_n_pages (page_cache)) { #if 0 g_printerr ("Printing page %d\n", job->next_page); #endif + g_mutex_lock (EV_DOC_MUTEX); ev_ps_exporter_do_page (EV_PS_EXPORTER (job->document), job->next_page); + g_mutex_unlock (EV_DOC_MUTEX); job->next_page++; return TRUE; } else { /* no more pages */ + g_mutex_lock (EV_DOC_MUTEX); ev_ps_exporter_end (EV_PS_EXPORTER (job->document)); + g_mutex_unlock (EV_DOC_MUTEX); close (job->fd); job->fd = 0; diff --git a/shell/ev-sidebar-links.c b/shell/ev-sidebar-links.c index 18f9e8f..03ea9e9 100644 --- a/shell/ev-sidebar-links.c +++ b/shell/ev-sidebar-links.c @@ -25,41 +25,37 @@ #endif #include +#include #include #include "ev-sidebar-links.h" +#include "ev-job-queue.h" #include "ev-document-links.h" #include "ev-window.h" -/* Amount of time we devote to each iteration of the idle, in microseconds */ -#define IDLE_WORK_LENGTH 5000 - -typedef struct { - EvDocumentLinksIter *links_iter; - GtkTreeIter *tree_iter; -} IdleStackData; - struct _EvSidebarLinksPrivate { GtkWidget *tree_view; + + /* Keep these ids around for blocking */ + guint selection_id; + guint page_changed_id; + + EvJob *job; GtkTreeModel *model; - EvDocument *current_document; - GList *idle_stack; - guint idle_id; + EvDocument *document; + EvPageCache *page_cache; }; -enum { - LINKS_COLUMN_MARKUP, - LINKS_COLUMN_PAGE_NUM, - LINKS_COLUMN_PAGE_VALID, - LINKS_COLUMN_LINK, - LINKS_COLUMN_NUM_COLUMNS -}; -static void links_page_num_func (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell, - GtkTreeModel *tree_model, - GtkTreeIter *iter, - gpointer data); +static void links_page_num_func (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + gpointer data); +static void update_page_callback (EvPageCache *page_cache, + gint current_page, + EvSidebarLinks *sidebar_links); + G_DEFINE_TYPE (EvSidebarLinks, ev_sidebar_links, GTK_TYPE_VBOX) @@ -72,7 +68,6 @@ ev_sidebar_links_destroy (GtkObject *object) { EvSidebarLinks *ev_sidebar_links = (EvSidebarLinks *) object; - g_print ("ev_sidebar_links_destroy!\n"); ev_sidebar_links_clear_document (ev_sidebar_links); } @@ -100,26 +95,48 @@ selection_changed_cb (GtkTreeSelection *selection, g_return_if_fail (EV_IS_SIDEBAR_LINKS (ev_sidebar_links)); - document = EV_DOCUMENT (ev_sidebar_links->priv->current_document); - g_return_if_fail (ev_sidebar_links->priv->current_document != NULL); + document = EV_DOCUMENT (ev_sidebar_links->priv->document); + g_return_if_fail (ev_sidebar_links->priv->document != NULL); if (gtk_tree_selection_get_selected (selection, &model, &iter)) { EvLink *link; - GtkWidget *window; - GValue value = {0, }; - gtk_tree_model_get_value (model, &iter, - LINKS_COLUMN_LINK, &value); + gtk_tree_model_get (model, &iter, + EV_DOCUMENT_LINKS_COLUMN_LINK, &link, + -1); + + if (link == NULL) + return; + + g_signal_handler_block (ev_sidebar_links->priv->page_cache, + ev_sidebar_links->priv->page_changed_id); + ev_page_cache_set_link (ev_sidebar_links->priv->page_cache, link); + g_signal_handler_unblock (ev_sidebar_links->priv->page_cache, + ev_sidebar_links->priv->page_changed_id); + } +} - link = EV_LINK (g_value_get_object (&value)); - g_return_if_fail (link != NULL); +static GtkTreeModel * +create_loading_model (void) +{ + GtkTreeModel *retval; + GtkTreeIter iter; + gchar *markup; + + /* Creates a fake model to indicate that we're loading */ + retval = (GtkTreeModel *)gtk_list_store_new (EV_DOCUMENT_LINKS_COLUMN_NUM_COLUMNS, + G_TYPE_STRING, + G_TYPE_BOOLEAN, + G_TYPE_OBJECT); + + gtk_list_store_append (GTK_LIST_STORE (retval), &iter); + markup = g_strdup_printf ("%s", _("Loading...")); + gtk_list_store_set (GTK_LIST_STORE (retval), &iter, + EV_DOCUMENT_LINKS_COLUMN_MARKUP, markup, + -1); + g_free (markup); - window = gtk_widget_get_ancestor (GTK_WIDGET (ev_sidebar_links), - EV_TYPE_WINDOW); - if (window) { - ev_window_open_link (EV_WINDOW (window), link); - } - } + return retval; } static void @@ -130,13 +147,9 @@ ev_sidebar_links_construct (EvSidebarLinks *ev_sidebar_links) GtkTreeViewColumn *column; GtkCellRenderer *renderer; GtkTreeSelection *selection; + GtkTreeModel *loading_model; priv = ev_sidebar_links->priv; - priv->model = (GtkTreeModel *) gtk_tree_store_new (LINKS_COLUMN_NUM_COLUMNS, - G_TYPE_STRING, - G_TYPE_INT, - G_TYPE_BOOLEAN, - G_TYPE_OBJECT); swindow = gtk_scrolled_window_new (NULL, NULL); @@ -146,11 +159,14 @@ ev_sidebar_links_construct (EvSidebarLinks *ev_sidebar_links) GTK_SHADOW_IN); /* Create tree view */ - priv->tree_view = gtk_tree_view_new_with_model (priv->model); - g_object_unref (priv->model); + loading_model = create_loading_model (); + priv->tree_view = gtk_tree_view_new_with_model (loading_model); + g_object_unref (loading_model); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->tree_view), FALSE); gtk_container_add (GTK_CONTAINER (swindow), priv->tree_view); - gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (priv->tree_view), TRUE); gtk_box_pack_start (GTK_BOX (ev_sidebar_links), swindow, TRUE, TRUE, 0); gtk_widget_show_all (GTK_WIDGET (ev_sidebar_links)); @@ -165,20 +181,17 @@ ev_sidebar_links_construct (EvSidebarLinks *ev_sidebar_links) NULL); gtk_tree_view_column_pack_start (GTK_TREE_VIEW_COLUMN (column), renderer, TRUE); gtk_tree_view_column_set_attributes (GTK_TREE_VIEW_COLUMN (column), renderer, - "markup", LINKS_COLUMN_MARKUP, + "markup", EV_DOCUMENT_LINKS_COLUMN_MARKUP, NULL); + renderer = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_end (GTK_TREE_VIEW_COLUMN (column), renderer, FALSE); gtk_tree_view_column_set_cell_data_func (GTK_TREE_VIEW_COLUMN (column), renderer, (GtkTreeCellDataFunc) links_page_num_func, NULL, NULL); - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view)); - g_signal_connect (selection, "changed", - G_CALLBACK (selection_changed_cb), - ev_sidebar_links); + } static void @@ -196,16 +209,15 @@ links_page_num_func (GtkTreeViewColumn *tree_column, GtkTreeIter *iter, gpointer data) { - int page_num; - gboolean page_valid; + EvLink *link; gtk_tree_model_get (tree_model, iter, - LINKS_COLUMN_PAGE_NUM, &page_num, - LINKS_COLUMN_PAGE_VALID, &page_valid, + EV_DOCUMENT_LINKS_COLUMN_LINK, &link, -1); - - if (page_valid) { - gchar *markup = g_strdup_printf ("%d", page_num); + + if (link != NULL && + ev_link_get_link_type (link) == EV_LINK_TYPE_PAGE) { + gchar *markup = g_strdup_printf ("%d", ev_link_get_page (link)); g_object_set (cell, "markup", markup, "visible", TRUE, @@ -230,139 +242,117 @@ ev_sidebar_links_new (void) return ev_sidebar_links; } -static void -stack_data_free (IdleStackData *stack_data, - EvDocumentLinks *document_links) +void +ev_sidebar_links_clear_document (EvSidebarLinks *sidebar_links) { - g_assert (stack_data); + EvSidebarLinksPrivate *priv; - if (stack_data->tree_iter) - gtk_tree_iter_free (stack_data->tree_iter); - if (stack_data->links_iter) - ev_document_links_free_iter (document_links, stack_data->links_iter); - g_free (stack_data); + g_return_if_fail (EV_IS_SIDEBAR_LINKS (sidebar_links)); + + priv = sidebar_links->priv; + + if (priv->document) { + g_object_unref (priv->document); + priv->document = NULL; + priv->page_cache = NULL; + } + + gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), NULL); } static gboolean -do_one_iteration (EvSidebarLinks *ev_sidebar_links) +update_page_callback_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) { - EvSidebarLinksPrivate *priv = ev_sidebar_links->priv; + EvSidebarLinks *sidebar_links = (data); EvLink *link; - IdleStackData *stack_data; - GtkTreeIter tree_iter; - EvDocumentLinksIter *child_iter; - EvLinkType link_type; - gint page; - - g_assert (priv->idle_stack); - - stack_data = (IdleStackData *) priv->idle_stack->data; - - link = ev_document_links_get_link - (EV_DOCUMENT_LINKS (priv->current_document), - stack_data->links_iter); - if (link == NULL) { - g_warning ("mismatch in model. No values available at current level.\n"); - return FALSE; - } - page = ev_link_get_page (link); - link_type = ev_link_get_link_type (link); - gtk_tree_store_append (GTK_TREE_STORE (priv->model), &tree_iter, stack_data->tree_iter); - gtk_tree_store_set (GTK_TREE_STORE (priv->model), &tree_iter, - LINKS_COLUMN_MARKUP, ev_link_get_title (link), - LINKS_COLUMN_PAGE_NUM, page, - LINKS_COLUMN_PAGE_VALID, (link_type == EV_LINK_TYPE_PAGE), - LINKS_COLUMN_LINK, link, + gtk_tree_model_get (model, iter, + EV_DOCUMENT_LINKS_COLUMN_LINK, &link, -1); - g_object_unref (link); - - child_iter = ev_document_links_get_child (EV_DOCUMENT_LINKS (priv->current_document), - stack_data->links_iter); - if (child_iter) { - IdleStackData *child_stack_data; - child_stack_data = g_new0 (IdleStackData, 1); - child_stack_data->tree_iter = gtk_tree_iter_copy (&tree_iter); - child_stack_data->links_iter = child_iter; - priv->idle_stack = g_list_prepend (priv->idle_stack, child_stack_data); + if (link && ev_link_get_link_type (link) == EV_LINK_TYPE_PAGE) { + int current_page; - return TRUE; - } + current_page = ev_page_cache_get_current_page (sidebar_links->priv->page_cache); + if (ev_link_get_page (link) == current_page) { + GtkTreeSelection *selection; - /* We don't have children, so we need to walk to the next node */ - while (TRUE) { - if (ev_document_links_next (EV_DOCUMENT_LINKS (priv->current_document), - stack_data->links_iter)) - return TRUE; + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (sidebar_links->priv->tree_view)); + + gtk_tree_selection_select_path (selection, path); - /* We're done with this level. Pop it off the idle stack and go - * to the next level */ - stack_data_free (stack_data, EV_DOCUMENT_LINKS (priv->current_document)); - priv->idle_stack = g_list_delete_link (priv->idle_stack, priv->idle_stack); - if (priv->idle_stack == NULL) - return FALSE; - stack_data = priv->idle_stack->data; + return TRUE; + } } + + return FALSE; } -static gboolean -populate_links_idle (gpointer data) +static void +update_page_callback (EvPageCache *page_cache, + gint current_page, + EvSidebarLinks *sidebar_links) { - GTimer *timer; - gint i; - gulong microseconds = 0; + GtkTreeSelection *selection; + /* We go through the tree linearly looking for the first page that + * matches. This is pretty inefficient. We can do something neat with + * a GtkTreeModelSort here to make it faster, if it turns out to be + * slow. + */ - EvSidebarLinks *ev_sidebar_links = (EvSidebarLinks *)data; - EvSidebarLinksPrivate *priv = ev_sidebar_links->priv; + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (sidebar_links->priv->tree_view)); - if (priv->idle_stack == NULL) { - priv->idle_id = 0; - return FALSE; - } + g_signal_handler_block (selection, sidebar_links->priv->selection_id); - /* The amount of time that reading the next bookmark takes is wildly - * inconsistent, so we constrain it to IDLE_WORK_LENGTH microseconds per - * idle iteration. */ - timer = g_timer_new (); - i = 0; - g_timer_start (timer); - while (do_one_iteration (ev_sidebar_links)) { - i++; - g_timer_elapsed (timer, µseconds); - if (microseconds > IDLE_WORK_LENGTH) - break; - } - g_timer_destroy (timer); -#if 0 - g_print ("%d rows done this idle in %d\n", i, (int)microseconds); -#endif - return TRUE; + gtk_tree_selection_unselect_all (selection); + gtk_tree_model_foreach (sidebar_links->priv->model, + update_page_callback_foreach, + sidebar_links); + + g_signal_handler_unblock (selection, sidebar_links->priv->selection_id); } -void -ev_sidebar_links_clear_document (EvSidebarLinks *sidebar_links) +static void +job_finished_cb (EvJobLinks *job, + EvSidebarLinks *sidebar_links) { EvSidebarLinksPrivate *priv; - - g_return_if_fail (EV_IS_SIDEBAR_LINKS (sidebar_links)); + GtkTreeSelection *selection; + GtkTreeIter iter; + GtkTreePath *path; + gboolean result; priv = sidebar_links->priv; - /* Clear the idle */ - if (priv->idle_id != 0) { - g_source_remove (priv->idle_id); - priv->idle_id = 0; + priv->model = g_object_ref (job->model); + gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), job->model); + g_object_unref (job); + + /* Expand one level of the tree */ + path = gtk_tree_path_new_first (); + for (result = gtk_tree_model_get_iter_first (priv->model, &iter); + result; + result = gtk_tree_model_iter_next (priv->model, &iter)) { + gtk_tree_view_expand_row (GTK_TREE_VIEW (priv->tree_view), path, FALSE); + gtk_tree_path_next (path); } - g_list_foreach (priv->idle_stack, (GFunc) stack_data_free, priv->current_document); - g_list_free (priv->idle_stack); - priv->idle_stack = NULL; + gtk_tree_path_free (path); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + priv->selection_id = g_signal_connect (selection, "changed", + G_CALLBACK (selection_changed_cb), + sidebar_links); + priv->page_changed_id = g_signal_connect (priv->page_cache, "page-changed", + G_CALLBACK (update_page_callback), + sidebar_links); + update_page_callback (priv->page_cache, + ev_page_cache_get_current_page (priv->page_cache), + sidebar_links); - if (priv->current_document) { - g_object_unref (priv->current_document); - priv->current_document = NULL; - } - gtk_tree_store_clear (GTK_TREE_STORE (priv->model)); } void @@ -370,7 +360,6 @@ ev_sidebar_links_set_document (EvSidebarLinks *sidebar_links, EvDocument *document) { EvSidebarLinksPrivate *priv; - EvDocumentLinksIter *links_iter; g_return_if_fail (EV_IS_SIDEBAR_LINKS (sidebar_links)); g_return_if_fail (EV_IS_DOCUMENT (document)); @@ -378,19 +367,17 @@ ev_sidebar_links_set_document (EvSidebarLinks *sidebar_links, priv = sidebar_links->priv; g_object_ref (document); - ev_sidebar_links_clear_document (sidebar_links); - priv->current_document = document; - links_iter = ev_document_links_begin_read (EV_DOCUMENT_LINKS (document)); - if (links_iter) { - IdleStackData *stack_data; + priv->document = document; + priv->page_cache = ev_document_get_page_cache (document); - stack_data = g_new0 (IdleStackData, 1); - stack_data->links_iter = links_iter; - stack_data->tree_iter = NULL; + priv->job = ev_job_links_new (document); + g_signal_connect (priv->job, + "finished", + G_CALLBACK (job_finished_cb), + sidebar_links); + /* The priority doesn't matter for this job */ + ev_job_queue_add_job (priv->job, EV_JOB_PRIORITY_LOW); - priv->idle_stack = g_list_prepend (priv->idle_stack, stack_data); - priv->idle_id = g_idle_add (populate_links_idle, sidebar_links); - } } diff --git a/shell/ev-sidebar-thumbnails.c b/shell/ev-sidebar-thumbnails.c index b4622f6..c548e29 100644 --- a/shell/ev-sidebar-thumbnails.c +++ b/shell/ev-sidebar-thumbnails.c @@ -32,6 +32,7 @@ #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" @@ -46,15 +47,14 @@ struct _EvSidebarThumbnailsPrivate { GtkListStore *list_store; EvDocument *document; - guint idle_id; - gint current_page, n_pages, pages_done; - GtkTreeIter current_page_iter; + gint n_pages, pages_done; }; enum { COLUMN_PAGE_STRING, COLUMN_PIXBUF, COLUMN_THUMBNAIL_SET, + COLUMN_JOB, NUM_COLUMNS }; @@ -64,21 +64,6 @@ G_DEFINE_TYPE (EvSidebarThumbnails, ev_sidebar_thumbnails, GTK_TYPE_VBOX); (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 (ev_sidebar_thumbnails_parent_class)->destroy (object); -} - -static void ev_sidebar_thumbnails_class_init (EvSidebarThumbnailsClass *ev_sidebar_thumbnails_class) { GObjectClass *g_object_class; @@ -87,10 +72,7 @@ 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); - gtk_object_class->destroy = ev_sidebar_thumbnails_destroy; - g_type_class_add_private (g_object_class, sizeof (EvSidebarThumbnailsPrivate)); - } static void @@ -111,19 +93,12 @@ adjustment_changed_cb (GtkAdjustment *adjustment, if (!path) return; - page = gtk_tree_path_get_indices (path)[0] + 1; - if (page == priv->current_page) - 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); - if (!thumbnail_set) { - priv->current_page = page; - priv->current_page_iter = iter; - - } } static void @@ -131,28 +106,23 @@ ev_sidebar_tree_selection_changed (GtkTreeSelection *selection, EvSidebarThumbnails *ev_sidebar_thumbnails) { EvSidebarThumbnailsPrivate *priv; - GtkWidget *window; + 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] + 1; - gtk_tree_path_free (path); - window = gtk_widget_get_ancestor (GTK_WIDGET (ev_sidebar_thumbnails), - EV_TYPE_WINDOW); - if (window && ev_document_get_page (priv->document) != page) { - ev_window_open_page (EV_WINDOW (window), page); - } + page_cache = ev_document_get_page_cache (priv->document); + ev_page_cache_set_current_page (page_cache, page); } static void @@ -164,10 +134,10 @@ ev_sidebar_thumbnails_init (EvSidebarThumbnails *ev_sidebar_thumbnails) 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, G_TYPE_BOOLEAN); + + 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); @@ -211,126 +181,39 @@ ev_sidebar_thumbnails_new (void) return ev_sidebar_thumbnails; } -static gboolean -do_one_iteration (EvSidebarThumbnails *ev_sidebar_thumbnails) -{ - EvSidebarThumbnailsPrivate *priv = ev_sidebar_thumbnails->priv; - GdkPixbuf *pixbuf; - gboolean thumbnail_set; - - gtk_tree_model_get (GTK_TREE_MODEL (priv->list_store), - &(priv->current_page_iter), - COLUMN_THUMBNAIL_SET, &thumbnail_set, - -1); - if (!thumbnail_set) { - pixbuf = ev_document_thumbnails_get_thumbnail - (EV_DOCUMENT_THUMBNAILS (priv->document), - priv->current_page, THUMBNAIL_WIDTH, TRUE); - - gtk_list_store_set (priv->list_store, - &(priv->current_page_iter), - COLUMN_PIXBUF, pixbuf, - COLUMN_THUMBNAIL_SET, TRUE, - -1); - - g_object_unref (pixbuf); - priv->pages_done ++; - } - - priv->current_page++; - - if (priv->current_page > priv->n_pages) { - priv->current_page = 1; - gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->list_store), - &(priv->current_page_iter)); - } else { - gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->list_store), - &(priv->current_page_iter)); - } - - if (priv->pages_done == priv->n_pages) - return FALSE; - else - return TRUE; -} - -static gboolean -populate_thumbnails_idle (gpointer data) -{ - GTimer *timer; - int i; - gdouble time_elapsed = 0; - - EvSidebarThumbnails *ev_sidebar_thumbnails = EV_SIDEBAR_THUMBNAILS (data); - EvSidebarThumbnailsPrivate *priv = ev_sidebar_thumbnails->priv; - -#if PROFILE_THUMB == 1 - static GTimer *total_timer; - static gboolean first_time = TRUE; - - if (first_time) { - total_timer = g_timer_new (); - first_time = FALSE; - g_timer_start (total_timer); - } -#endif - - /* undo the thumbnailing idle and handler */ - if (priv->pages_done == priv->n_pages) { - priv->idle_id = 0; - g_signal_handlers_disconnect_by_func (priv->vadjustment, - adjustment_changed_cb, - ev_sidebar_thumbnails); -#if PROFILE_THUMB == 1 - time_elapsed = g_timer_elapsed (total_timer, NULL); - g_timer_destroy (total_timer); - g_print ("%d rows done in %f seconds\n", - gtk_tree_model_iter_n_children (GTK_TREE_MODEL (priv->list_store), NULL), - time_elapsed); -#endif - return FALSE; - } - - timer = g_timer_new (); - i = 0; - g_timer_start (timer); - while (do_one_iteration (ev_sidebar_thumbnails)) { - i++; - time_elapsed = g_timer_elapsed (timer, NULL); - if (time_elapsed > IDLE_WORK_LENGTH/1000000) - break; - } - g_timer_destroy (timer); -#if PROFILE_THUMB == 2 - g_print ("%d rows done this idle in %f seconds\n", i, time_elapsed); -#endif - - return TRUE; -} - -void -ev_sidebar_thumbnails_select_page (EvSidebarThumbnails *sidebar, - int page) +static void +page_changed_cb (EvPageCache *page_cache, + int page, + EvSidebarThumbnails *sidebar) { GtkTreePath *path; GtkTreeSelection *selection; - /* if the EvSidebar's document can't provide thumbnails */ - if (sidebar->priv->document == NULL) - return; - path = gtk_tree_path_new_from_indices (page - 1, -1); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (sidebar->priv->tree_view)); - if (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_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); } +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); +} void ev_sidebar_thumbnails_set_document (EvSidebarThumbnails *sidebar_thumbnails, @@ -342,43 +225,56 @@ ev_sidebar_thumbnails_set_document (EvSidebarThumbnails *sidebar_thumbnails, gchar *page; 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); - } - n_pages = ev_document_get_n_pages (document); + page_cache = ev_document_get_page_cache (document); + n_pages = ev_page_cache_get_n_pages (page_cache); priv->document = document; - priv->idle_id = g_idle_add (populate_thumbnails_idle, sidebar_thumbnails); priv->n_pages = n_pages; /* 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); + 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; + + /* 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_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_object_unref (loading_icon); - gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->list_store), - &(priv->current_page_iter)); - priv->current_page = 1; - priv->pages_done = 0; + + /* 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); + } diff --git a/shell/ev-sidebar-thumbnails.h b/shell/ev-sidebar-thumbnails.h index 0d7a470..45f68fc 100644 --- a/shell/ev-sidebar-thumbnails.h +++ b/shell/ev-sidebar-thumbnails.h @@ -56,8 +56,6 @@ GtkWidget *ev_sidebar_thumbnails_new (void); void ev_sidebar_thumbnails_set_document (EvSidebarThumbnails *sidebar_thumbnails, EvDocument *document); -void ev_sidebar_thumbnails_select_page (EvSidebarThumbnails *sidebar_thumbnails, - int page); G_END_DECLS diff --git a/shell/ev-sidebar.c b/shell/ev-sidebar.c index 202c249..f28b514 100644 --- a/shell/ev-sidebar.c +++ b/shell/ev-sidebar.c @@ -402,8 +402,7 @@ ev_sidebar_set_document (EvSidebar *sidebar, if (EV_IS_SIDEBAR_LINKS (widget) && EV_IS_DOCUMENT_LINKS (document) && ev_document_links_has_document_links (EV_DOCUMENT_LINKS (document))) { - ev_sidebar_links_set_document - (EV_SIDEBAR_LINKS (widget), document); + ev_sidebar_links_set_document (EV_SIDEBAR_LINKS (widget), document); } else if (EV_IS_SIDEBAR_THUMBNAILS (widget) && EV_IS_DOCUMENT_THUMBNAILS (document)) { ev_sidebar_thumbnails_set_document diff --git a/shell/ev-view.c b/shell/ev-view.c index 372d4a3..9921ed4 100644 --- a/shell/ev-view.c +++ b/shell/ev-view.c @@ -31,6 +31,9 @@ #include "ev-document-find.h" #include "ev-document-misc.h" #include "ev-debug.h" +#include "ev-job-queue.h" +#include "ev-page-cache.h" +#include "ev-pixbuf-cache.h" #define EV_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_VIEW, EvViewClass)) #define EV_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_VIEW)) @@ -92,6 +95,12 @@ struct _EvView { GtkAdjustment *hadjustment; GtkAdjustment *vadjustment; + EvPageCache *page_cache; + EvPixbufCache *pixbuf_cache; + + gint current_page; + EvJobRender *current_job; + int find_page; int find_result; int spacing; @@ -111,11 +120,8 @@ struct _EvViewClass { GtkScrollType scroll, gboolean horizontal); - /* Should this be notify::page? */ - void (*page_changed) (EvView *view); }; -static guint page_changed_signal = 0; static void ev_view_set_scroll_adjustments (EvView *view, GtkAdjustment *hadjustment, @@ -196,8 +202,6 @@ ev_view_finalize (GObject *object) LOG ("Finalize"); - if (view->document) - g_object_unref (view->document); ev_view_set_scroll_adjustments (view, NULL, NULL); @@ -209,6 +213,14 @@ ev_view_destroy (GtkObject *object) { EvView *view = EV_VIEW (object); + if (view->document) { + g_object_unref (view->document); + view->document = NULL; + } + if (view->pixbuf_cache) { + g_object_unref (view->pixbuf_cache); + view->pixbuf_cache = NULL; + } ev_view_set_scroll_adjustments (view, NULL, NULL); GTK_OBJECT_CLASS (ev_view_parent_class)->destroy (object); @@ -224,7 +236,11 @@ ev_view_get_offsets (EvView *view, int *x_offset, int *y_offset) g_return_if_fail (EV_IS_DOCUMENT (document)); - ev_document_get_page_size (document, -1, &width, &height); + ev_page_cache_get_size (view->page_cache, + view->current_page, + view->scale, + &width, &height); + ev_document_misc_get_page_border_size (width, height, &border); *x_offset = view->spacing; @@ -259,6 +275,9 @@ doc_rect_to_view_rect (EvView *view, GdkRectangle *doc_rect, GdkRectangle *view_ view_rect->height = doc_rect->height * view->scale; } + +/* Called by size_request to make sure we have appropriate jobs running. + */ static void ev_view_size_request (GtkWidget *widget, GtkRequisition *requisition) @@ -276,8 +295,15 @@ ev_view_size_request (GtkWidget *widget, return; } - ev_document_get_page_size (view->document, -1, - &width, &height); + ev_page_cache_get_size (view->page_cache, + view->current_page, + view->scale, + &width, &height); + + ev_pixbuf_cache_set_page_range (view->pixbuf_cache, + view->current_page, + view->current_page, + view->scale); ev_document_misc_get_page_border_size (width, height, &border); if (view->width >= 0) { @@ -366,8 +392,6 @@ ev_view_realize (GtkWidget *widget) gdk_window_set_background (view->bin_window, &widget->style->mid[widget->state]); if (view->document) { - ev_document_set_target (view->document, view->bin_window); - /* We can't get page size without a target, so we have to * queue a size request at realization. Could be fixed * with EvDocument changes to allow setting a GdkScreen @@ -382,9 +406,6 @@ ev_view_unrealize (GtkWidget *widget) { EvView *view = EV_VIEW (widget); - if (view->document) - ev_document_set_target (view->document, NULL); - gdk_window_set_user_data (view->bin_window, NULL); gdk_window_destroy (view->bin_window); view->bin_window = NULL; @@ -442,20 +463,26 @@ static void highlight_find_results (EvView *view) { EvDocumentFind *find; - int i, results; + int i, results = 0; g_return_if_fail (EV_IS_DOCUMENT_FIND (view->document)); find = EV_DOCUMENT_FIND (view->document); +#if 0 + g_mutex_lock (EV_DOC_MUTEX); results = ev_document_find_get_n_results (find); - + g_mutex_unlock (EV_DOC_MUTEX); +#endif + for (i = 0; i < results; i++) { GdkRectangle rectangle; guchar alpha; alpha = (i == view->find_result) ? 0x90 : 0x20; + g_mutex_lock (EV_DOC_MUTEX); ev_document_find_get_result (find, i, &rectangle); + g_mutex_unlock (EV_DOC_MUTEX); draw_rubberband (GTK_WIDGET (view), view->bin_window, &rectangle, alpha); } @@ -471,13 +498,18 @@ expose_bin_window (GtkWidget *widget, gint width, height; GdkRectangle area; int x_offset, y_offset; + GdkPixbuf *scaled_image; + GdkPixbuf *current_pixbuf; if (view->document == NULL) return; ev_view_get_offsets (view, &x_offset, &y_offset); - ev_document_get_page_size (view->document, -1, - &width, &height); + ev_page_cache_get_size (view->page_cache, + view->current_page, + view->scale, + &width, &height); + ev_document_misc_get_page_border_size (width, height, &border); /* Paint the frame */ @@ -488,18 +520,34 @@ expose_bin_window (GtkWidget *widget, ev_document_misc_paint_one_page (view->bin_window, widget, &area, &border); /* Render the document itself */ - ev_document_set_page_offset (view->document, - x_offset + border.left, - y_offset + border.top); - LOG ("Render area %d %d %d %d - Offset %d %d", event->area.x, event->area.y, event->area.width, event->area.height, x_offset, y_offset); - ev_document_render (view->document, - event->area.x, event->area.y, - event->area.width, event->area.height); + current_pixbuf = ev_pixbuf_cache_get_pixbuf (view->pixbuf_cache, view->current_page); + + if (current_pixbuf == NULL) + scaled_image = NULL; + else if (width == gdk_pixbuf_get_width (current_pixbuf) && + height == gdk_pixbuf_get_height (current_pixbuf)) + scaled_image = g_object_ref (current_pixbuf); + else + scaled_image = gdk_pixbuf_scale_simple (current_pixbuf, + width, height, + GDK_INTERP_NEAREST); + if (scaled_image) { + gdk_draw_pixbuf (view->bin_window, + GTK_WIDGET (view)->style->fg_gc[GTK_STATE_NORMAL], + scaled_image, + 0, 0, + area.x + border.left, + area.y + border.top, + width, height, + GDK_RGB_DITHER_NORMAL, + 0, 0); + g_object_unref (scaled_image); + } if (EV_IS_DOCUMENT_FIND (view->document)) { highlight_find_results (view); @@ -541,8 +589,12 @@ ev_view_select_all (EvView *ev_view) g_return_if_fail (EV_IS_VIEW (ev_view)); + ev_view_get_offsets (ev_view, &x_offset, &y_offset); - ev_document_get_page_size (ev_view->document, -1, &width, &height); + ev_page_cache_get_size (ev_view->page_cache, + ev_view->current_page, + ev_view->scale, + &width, &height); ev_document_misc_get_page_border_size (width, height, &border); ev_view->has_selection = TRUE; @@ -563,7 +615,10 @@ ev_view_copy (EvView *ev_view) char *text; doc_rect_to_view_rect (ev_view, &ev_view->selection, &selection); + g_mutex_lock (EV_DOC_MUTEX); text = ev_document_get_text (ev_view->document, &selection); + g_mutex_unlock (EV_DOC_MUTEX); + clipboard = gtk_widget_get_clipboard (GTK_WIDGET (ev_view), GDK_SELECTION_CLIPBOARD); gtk_clipboard_set_text (clipboard, text, -1); @@ -581,7 +636,9 @@ ev_view_primary_get_cb (GtkClipboard *clipboard, char *text; doc_rect_to_view_rect (ev_view, &ev_view->selection, &selection); + g_mutex_lock (EV_DOC_MUTEX); text = ev_document_get_text (ev_view->document, &selection); + g_mutex_unlock (EV_DOC_MUTEX); gtk_selection_data_set_text (selection_data, text, -1); } @@ -697,7 +754,7 @@ ev_view_create_invisible_cursor(void) { GdkBitmap *empty; GdkColor black = { 0, 0, 0, 0 }; - static unsigned char bits[] = { 0x00 }; + static char bits[] = { 0x00 }; empty = gdk_bitmap_create_from_data (NULL, bits, 1, 1); @@ -759,10 +816,13 @@ ev_view_motion_notify_event (GtkWidget *widget, view_rect_to_doc_rect (view, &selection, &view->selection); gtk_widget_queue_draw (widget); - } else if (view->document) { + } else if (FALSE && view->document) { EvLink *link; + g_mutex_lock (EV_DOC_MUTEX); link = ev_document_get_link (view->document, event->x, event->y); + g_mutex_unlock (EV_DOC_MUTEX); + if (link) { char *msg; @@ -796,9 +856,11 @@ ev_view_button_release_event (GtkWidget *widget, } else if (view->document) { EvLink *link; + g_mutex_lock (EV_DOC_MUTEX); link = ev_document_get_link (view->document, event->x, event->y); + g_mutex_unlock (EV_DOC_MUTEX); if (link) { ev_view_go_to_link (view, link); g_object_unref (link); @@ -881,9 +943,9 @@ ev_view_scroll_view (EvView *view, gboolean horizontal) { if (scroll == GTK_SCROLL_PAGE_BACKWARD) { - ev_view_set_page (view, ev_view_get_page (view) - 1); + ev_page_cache_prev_page (view->page_cache); } else if (scroll == GTK_SCROLL_PAGE_FORWARD) { - ev_view_set_page (view, ev_view_get_page (view) + 1); + ev_page_cache_next_page (view->page_cache); } else { GtkAdjustment *adjustment; double value; @@ -982,13 +1044,6 @@ ev_view_class_init (EvViewClass *class) G_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT); - page_changed_signal = g_signal_new ("page-changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (EvViewClass, page_changed), - NULL, NULL, - ev_marshal_VOID__NONE, - G_TYPE_NONE, 0); g_signal_new ("scroll_view", G_TYPE_FROM_CLASS (object_class), @@ -1034,6 +1089,7 @@ ev_view_init (EvView *view) view->spacing = 10; view->scale = 1.0; + view->current_page = 1; view->pressed_button = -1; view->cursor = EV_VIEW_CURSOR_NORMAL; } @@ -1043,12 +1099,14 @@ update_find_status_message (EvView *view) { char *message; +// g_mutex_lock (EV_DOC_MUTEX); if (ev_document_get_page (view->document) == view->find_page) { int results; +// g_mutex_lock (EV_DOC_MUTEX); results = ev_document_find_get_n_results (EV_DOCUMENT_FIND (view->document)); - +// g_mutex_unlock (EV_DOC_MUTEX); /* TRANS: Sometimes this could be better translated as "%d hit(s) on this page". Therefore this string contains plural cases. */ @@ -1058,10 +1116,11 @@ update_find_status_message (EvView *view) results); } else { double percent; - + + g_mutex_lock (EV_DOC_MUTEX); percent = ev_document_find_get_progress (EV_DOCUMENT_FIND (view->document)); - + g_mutex_unlock (EV_DOC_MUTEX); if (percent >= (1.0 - 1e-10)) { message = g_strdup (_("Not found")); } else { @@ -1070,57 +1129,10 @@ update_find_status_message (EvView *view) } } +// g_mutex_unlock (EV_DOC_MUTEX); ev_view_set_find_status (view, message); - g_free (message); -} - -static void -set_document_page (EvView *view, int new_page) -{ - int page; - int pages; - - pages = ev_document_get_n_pages (view->document); - page = CLAMP (new_page, 1, pages); - - if (view->document) { - int old_page = ev_document_get_page (view->document); - int old_width, old_height; - - ev_document_get_page_size (view->document, - -1, - &old_width, &old_height); - - if (old_page != page) { - if (view->cursor != EV_VIEW_CURSOR_HIDDEN) { - ev_view_set_cursor (view, EV_VIEW_CURSOR_WAIT); - } - ev_document_set_page (view->document, page); - } - - if (old_page != ev_document_get_page (view->document)) { - int width, height; - - g_signal_emit (view, page_changed_signal, 0); - - view->has_selection = FALSE; - ev_document_get_page_size (view->document, - -1, - &width, &height); - if (width != old_width || height != old_height) - gtk_widget_queue_resize (GTK_WIDGET (view)); - - gtk_adjustment_set_value (view->vadjustment, - view->vadjustment->lower); - } - - if (EV_IS_DOCUMENT_FIND (view->document)) { - view->find_page = page; - view->find_result = 0; - update_find_status_message (view); - } - } +// g_free (message); } #define MARGIN 5 @@ -1164,11 +1176,16 @@ jump_to_find_result (EvView *view) GdkRectangle rect; int n_results; + g_mutex_lock (EV_DOC_MUTEX); n_results = ev_document_find_get_n_results (find); + g_mutex_unlock (EV_DOC_MUTEX); if (n_results > view->find_result) { + g_mutex_lock (EV_DOC_MUTEX); ev_document_find_get_result (find, view->find_result, &rect); + g_mutex_unlock (EV_DOC_MUTEX); + ensure_rectangle_is_visible (view, &rect); } } @@ -1178,7 +1195,7 @@ jump_to_find_page (EvView *view) { int n_pages, i; - n_pages = ev_document_get_n_pages (view->document); + n_pages = ev_page_cache_get_n_pages (view->page_cache); for (i = 0; i <= n_pages; i++) { int has_results; @@ -1189,13 +1206,14 @@ jump_to_find_page (EvView *view) page = page - n_pages; } + g_mutex_lock (EV_DOC_MUTEX); has_results = ev_document_find_page_has_results (EV_DOCUMENT_FIND (view->document), page); if (has_results == -1) { view->find_page = page; break; } else if (has_results == 1) { - set_document_page (view, page); + ev_page_cache_set_current_page (view->page_cache, page); jump_to_find_result (view); break; } @@ -1209,39 +1227,75 @@ find_changed_cb (EvDocument *document, int page, EvView *view) jump_to_find_result (view); update_find_status_message (view); +#if 0 + /* FIXME: */ if (ev_document_get_page (document) == page) { gtk_widget_queue_draw (GTK_WIDGET (view)); } +#endif +} +/*** Public API ***/ + +GtkWidget* +ev_view_new (void) +{ + return g_object_new (EV_TYPE_VIEW, NULL); } static void -page_changed_callback (EvDocument *document, - EvView *view) +job_finished_cb (EvPixbufCache *pixbuf_cache, + EvView *view) { - LOG ("Page changed callback"); - gtk_widget_queue_draw (GTK_WIDGET (view)); - - if (view->cursor != EV_VIEW_CURSOR_HIDDEN) { - ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL); - } } + static void -scale_changed_callback (EvDocument *document, - EvView *view) +page_changed_cb (EvPageCache *page_cache, + int new_page, + EvView *view) { - LOG ("Scale changed callback"); + int old_page = view->current_page; + int old_width, old_height; + int new_width, new_height; - gtk_widget_queue_resize (GTK_WIDGET (view)); -} + if (old_page == new_page) + return; -/*** Public API ***/ - -GtkWidget* -ev_view_new (void) -{ - return g_object_new (EV_TYPE_VIEW, NULL); + ev_page_cache_get_size (page_cache, + old_page, + view->scale, + &old_width, &old_height); + ev_page_cache_get_size (page_cache, + new_page, + view->scale, + &new_width, &new_height); + + if (view->cursor != EV_VIEW_CURSOR_HIDDEN) { + //ev_view_set_cursor (view, EV_VIEW_CURSOR_WAIT); + } + + view->current_page = new_page; + view->has_selection = FALSE; + + ev_pixbuf_cache_set_page_range (view->pixbuf_cache, + view->current_page, + view->current_page, + view->scale); + + if (new_width != old_width || new_height != old_height) + gtk_widget_queue_resize (GTK_WIDGET (view)); + else + gtk_widget_queue_draw (GTK_WIDGET (view)); + + gtk_adjustment_set_value (view->vadjustment, + view->vadjustment->lower); + + if (EV_IS_DOCUMENT_FIND (view->document)) { + view->find_page = new_page; + view->find_result = 0; + update_find_status_message (view); + } } void @@ -1256,6 +1310,8 @@ ev_view_set_document (EvView *view, find_changed_cb, view); g_object_unref (view->document); + view->page_cache = NULL; + } view->document = document; @@ -1270,22 +1326,13 @@ ev_view_set_document (EvView *view, G_CALLBACK (find_changed_cb), view); } - g_signal_connect (view->document, - "page_changed", - G_CALLBACK (page_changed_callback), - view); - g_signal_connect (view->document, - "scale_changed", - G_CALLBACK (scale_changed_callback), - view); + view->page_cache = ev_document_get_page_cache (view->document); + g_signal_connect (view->page_cache, "page-changed", G_CALLBACK (page_changed_cb), view); + view->pixbuf_cache = ev_pixbuf_cache_new (view->document); + g_signal_connect (view->pixbuf_cache, "job-finished", G_CALLBACK (job_finished_cb), view); } - - if (GTK_WIDGET_REALIZED (view)) - ev_document_set_target (view->document, view->bin_window); gtk_widget_queue_resize (GTK_WIDGET (view)); - - g_signal_emit (view, page_changed_signal, 0); } } @@ -1303,7 +1350,7 @@ go_to_link (EvView *view, EvLink *link) break; case EV_LINK_TYPE_PAGE: page = ev_link_get_page (link); - set_document_page (view, page); + ev_page_cache_set_current_page (view->page_cache, page); break; case EV_LINK_TYPE_EXTERNAL_URI: uri = ev_link_get_uri (link); @@ -1318,24 +1365,6 @@ ev_view_go_to_link (EvView *view, EvLink *link) go_to_link (view, link); } -void -ev_view_set_page (EvView *view, - int page) -{ - g_return_if_fail (EV_IS_VIEW (view)); - - set_document_page (view, page); -} - -int -ev_view_get_page (EvView *view) -{ - if (view->document) - return ev_document_get_page (view->document); - else - return 1; -} - static void ev_view_zoom (EvView *view, double factor, @@ -1351,8 +1380,7 @@ ev_view_zoom (EvView *view, scale = CLAMP (scale, MIN_SCALE, MAX_SCALE); view->scale = scale; - - ev_document_set_scale (view->document, view->scale); + gtk_widget_queue_resize (GTK_WIDGET (view)); } void @@ -1378,7 +1406,12 @@ size_to_zoom_factor (EvView *view, int width, int height) doc_width = doc_height = 0; scale = scale_w = scale_h = 1.0; - ev_document_get_page_size (view->document, -1, &doc_width, &doc_height); + ev_page_cache_get_size (view->page_cache, + view->current_page, + view->scale, + &doc_width, + &doc_height); + /* FIXME: The border size isn't constant. Ugh. Still, if we have extra * space, we just cut it from the border */ ev_document_misc_get_page_border_size (doc_width, doc_height, &border); @@ -1415,16 +1448,16 @@ ev_view_set_size (EvView *view, { double factor; - if (!view->document) { + if (!view->document) return; - } if (view->width != width || view->height != height) { view->width = width; view->height = height; factor = size_to_zoom_factor (view, width, height); - ev_view_zoom (view, factor, FALSE); + ev_view_zoom (view, factor, FALSE); + gtk_widget_queue_resize (GTK_WIDGET (view)); } } @@ -1447,11 +1480,16 @@ ev_view_get_find_status (EvView *view) void ev_view_find_next (EvView *view) { + EvPageCache *page_cache; int n_results, n_pages; EvDocumentFind *find = EV_DOCUMENT_FIND (view->document); + page_cache = ev_document_get_page_cache (view->document); + g_mutex_lock (EV_DOC_MUTEX); n_results = ev_document_find_get_n_results (find); - n_pages = ev_document_get_n_pages (view->document); + g_mutex_unlock (EV_DOC_MUTEX); + + n_pages = ev_page_cache_get_n_pages (page_cache); view->find_result++; @@ -1475,9 +1513,15 @@ ev_view_find_previous (EvView *view) { int n_results, n_pages; EvDocumentFind *find = EV_DOCUMENT_FIND (view->document); + EvPageCache *page_cache; + + page_cache = ev_document_get_page_cache (view->document); + g_mutex_lock (EV_DOC_MUTEX); n_results = ev_document_find_get_n_results (find); - n_pages = ev_document_get_n_pages (view->document); + g_mutex_unlock (EV_DOC_MUTEX); + + n_pages = ev_page_cache_get_n_pages (page_cache); view->find_result--; diff --git a/shell/ev-view.h b/shell/ev-view.h index cc90fb8..00b92ea 100644 --- a/shell/ev-view.h +++ b/shell/ev-view.h @@ -44,15 +44,8 @@ void ev_view_copy (EvView *view); void ev_view_select_all (EvView *view); /* Navigation */ -gboolean ev_view_can_go_back (EvView *view); -void ev_view_go_back (EvView *view); -gboolean ev_view_can_go_forward (EvView *view); -void ev_view_go_forward (EvView *view); void ev_view_go_to_link (EvView *view, EvLink *link); -void ev_view_set_page (EvView *view, - int page); -int ev_view_get_page (EvView *view); /* Page size */ void ev_view_zoom_in (EvView *view); diff --git a/shell/ev-window.c b/shell/ev-window.c index f1c41bb..849adaf 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -41,6 +41,7 @@ #include "ev-document-links.h" #include "ev-document-find.h" #include "ev-document-security.h" +#include "ev-job-queue.h" #include "eggfindbar.h" #include "pdf-document.h" @@ -106,6 +107,7 @@ struct _EvWindowPrivate { char *uri; EvDocument *document; + EvPageCache *page_cache; EvWindowPageMode page_mode; /* These members are used temporarily when in PAGE_MODE_PASSWORD */ @@ -168,7 +170,6 @@ update_action_sensitivity (EvWindow *ev_window) document = ev_window->priv->document; page_mode = ev_window->priv->page_mode; - view = EV_VIEW (ev_window->priv->view); /* File menu */ @@ -198,9 +199,8 @@ update_action_sensitivity (EvWindow *ev_window) if (document) { int n_pages; int page; - - page = ev_view_get_page (EV_VIEW (ev_window->priv->view)); - n_pages = ev_document_get_n_pages (document); + page = ev_page_cache_get_current_page (ev_window->priv->page_cache); + n_pages = ev_page_cache_get_n_pages (ev_window->priv->page_cache); set_action_sensitive (ev_window, "GoPreviousPage", page > 1); set_action_sensitive (ev_window, "GoNextPage", page < n_pages); @@ -347,7 +347,8 @@ update_sizing_buttons (EvWindow *window) void ev_window_open_page (EvWindow *ev_window, int page) { - ev_view_set_page (EV_VIEW (ev_window->priv->view), page); + if (ev_window->priv->page_cache) + ev_page_cache_set_current_page (ev_window->priv->page_cache, page); } void @@ -427,9 +428,8 @@ update_window_title (EvDocument *document, GParamSpec *pspec, EvWindow *ev_windo gboolean password_needed; password_needed = (ev_window->priv->password_document != NULL); - if (document) { - doc_title = ev_document_get_title (document); + doc_title = ev_page_cache_get_title (ev_window->priv->page_cache); /* Make sure we get a valid title back */ if (doc_title) { @@ -485,9 +485,8 @@ update_total_pages (EvWindow *ev_window) GtkAction *action; int pages; - pages = ev_document_get_n_pages (ev_window->priv->document); - action = gtk_action_group_get_action - (ev_window->priv->action_group, PAGE_SELECTOR_ACTION); + pages = ev_page_cache_get_n_pages (ev_window->priv->page_cache); + action = gtk_action_group_get_action (ev_window->priv->action_group, PAGE_SELECTOR_ACTION); ev_page_action_set_total_pages (EV_PAGE_ACTION (action), pages); } @@ -515,6 +514,21 @@ hide_sidebar_and_actions (EvWindow *ev_window) } static void +page_changed_cb (EvPageCache *page_cache, + gint page, + EvWindow *ev_window) +{ + GtkAction *action; + + action = gtk_action_group_get_action + (ev_window->priv->action_group, PAGE_SELECTOR_ACTION); + + ev_page_action_set_current_page (EV_PAGE_ACTION (action), page); + update_action_sensitivity (ev_window); +} + + +static void ev_window_setup_document (EvWindow *ev_window) { EvDocument *document; @@ -522,6 +536,8 @@ ev_window_setup_document (EvWindow *ev_window) EvSidebar *sidebar = EV_SIDEBAR (ev_window->priv->sidebar); document = ev_window->priv->document; + ev_window->priv->page_cache = ev_document_get_page_cache (ev_window->priv->document); + g_signal_connect (ev_window->priv->page_cache, "page-changed", G_CALLBACK (page_changed_cb), ev_window); g_signal_connect_object (G_OBJECT (document), "notify::title", @@ -534,6 +550,7 @@ ev_window_setup_document (EvWindow *ev_window) ev_sidebar_set_document (sidebar, document); else hide_sidebar_and_actions (ev_window); + ev_view_set_document (view, document); update_window_title (document, NULL, ev_window); @@ -553,9 +570,12 @@ password_dialog_response (GtkWidget *password_dialog, gchar *uri; password = ev_password_dialog_get_password (password_dialog); - if (password) + if (password) { + g_mutex_lock (EV_DOC_MUTEX); ev_document_security_set_password (EV_DOCUMENT_SECURITY (ev_window->priv->password_document), password); + g_mutex_unlock (EV_DOC_MUTEX); + } g_free (password); document = ev_window->priv->password_document; @@ -856,6 +876,7 @@ ev_window_cmd_save_as (GtkAction *action, EvWindow *ev_window) GtkWidget *fc; GtkFileFilter *pdf_filter, *all_filter; gchar *uri = NULL; + gboolean success; fc = gtk_file_chooser_dialog_new ( _("Save a Copy"), @@ -888,8 +909,12 @@ ev_window_cmd_save_as (GtkAction *action, EvWindow *ev_window) !overwrite_existing_file (GTK_WINDOW (fc), uri)) continue; */ + + g_mutex_lock (EV_DOC_MUTEX); + success = ev_document_save (ev_window->priv->document, uri, NULL); + g_mutex_unlock (EV_DOC_MUTEX); - if (ev_document_save (ev_window->priv->document, uri, NULL)) + if (success) break; else save_error_dialog (GTK_WINDOW (fc), uri); @@ -936,7 +961,7 @@ ev_window_print (EvWindow *ev_window) config = gnome_print_config_default (); job = gnome_print_job_new (config); - print_dialog = gnome_print_dialog_new (job, _("Print"), + print_dialog = gnome_print_dialog_new (job, (guchar *) _("Print"), (GNOME_PRINT_DIALOG_RANGE | GNOME_PRINT_DIALOG_COPIES)); gtk_dialog_set_response_sensitive (GTK_DIALOG (print_dialog), @@ -964,7 +989,7 @@ ev_window_print (EvWindow *ev_window) 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, "Settings.Engine.Backend.Driver")); + config, (guchar *)"Settings.Engine.Backend.Driver")); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); @@ -1465,8 +1490,7 @@ ev_window_cmd_go_previous_page (GtkAction *action, EvWindow *ev_window) { g_return_if_fail (EV_IS_WINDOW (ev_window)); - ev_view_set_page (EV_VIEW (ev_window->priv->view), - ev_view_get_page (EV_VIEW (ev_window->priv->view)) - 1); + ev_page_cache_prev_page (ev_window->priv->page_cache); } static void @@ -1474,8 +1498,7 @@ ev_window_cmd_go_next_page (GtkAction *action, EvWindow *ev_window) { g_return_if_fail (EV_IS_WINDOW (ev_window)); - ev_view_set_page (EV_VIEW (ev_window->priv->view), - ev_view_get_page (EV_VIEW (ev_window->priv->view)) + 1); + ev_page_cache_next_page (ev_window->priv->page_cache); } static void @@ -1483,15 +1506,18 @@ ev_window_cmd_go_first_page (GtkAction *action, EvWindow *ev_window) { g_return_if_fail (EV_IS_WINDOW (ev_window)); - ev_view_set_page (EV_VIEW (ev_window->priv->view), 1); + ev_page_cache_set_current_page (ev_window->priv->page_cache, 1); } static void ev_window_cmd_go_last_page (GtkAction *action, EvWindow *ev_window) { + int n_pages; + g_return_if_fail (EV_IS_WINDOW (ev_window)); - ev_view_set_page (EV_VIEW (ev_window->priv->view), G_MAXINT); + n_pages = ev_page_cache_get_n_pages (ev_window->priv->page_cache); + ev_page_cache_set_current_page (ev_window->priv->page_cache, n_pages); } static void @@ -1502,7 +1528,12 @@ ev_window_cmd_view_reload (GtkAction *action, EvWindow *ev_window) g_return_if_fail (EV_IS_WINDOW (ev_window)); - page = ev_document_get_page (ev_window->priv->document); +#if 0 + /* FIXME: uncomment when this is written.*/ + page = ev_page_cache_get_page (ev_window->priv->page_cache); +#else + page = 1; +#endif uri = g_strdup (ev_window->priv->uri); ev_window_open (ev_window, uri); @@ -1767,32 +1798,6 @@ disconnect_proxy_cb (GtkUIManager *ui_manager, GtkAction *action, } static void -update_current_page (EvWindow *ev_window, - EvView *view) -{ - int page; - GtkAction *action; - EvSidebarThumbnails *thumbs; - - thumbs = EV_SIDEBAR_THUMBNAILS (ev_window->priv->thumbs_sidebar); - ev_sidebar_thumbnails_select_page (thumbs, ev_view_get_page (view)); - - action = gtk_action_group_get_action - (ev_window->priv->action_group, PAGE_SELECTOR_ACTION); - - page = ev_view_get_page (EV_VIEW (ev_window->priv->view)); - ev_page_action_set_current_page (EV_PAGE_ACTION (action), page); -} - -static void -view_page_changed_cb (EvView *view, - EvWindow *ev_window) -{ - update_current_page (ev_window, view); - update_action_sensitivity (ev_window); -} - -static void view_status_changed_cb (EvView *view, GParamSpec *pspec, EvWindow *ev_window) @@ -1885,9 +1890,14 @@ find_bar_search_changed_cb (EggFindBar *find_bar, if (ev_window->priv->document && EV_IS_DOCUMENT_FIND (ev_window->priv->document)) { if (visible && search_string) { + g_mutex_lock (EV_DOC_MUTEX); ev_document_find_begin (EV_DOCUMENT_FIND (ev_window->priv->document), search_string, case_sensitive); + g_mutex_unlock (EV_DOC_MUTEX); } else { + g_mutex_lock (EV_DOC_MUTEX); ev_document_find_cancel (EV_DOCUMENT_FIND (ev_window->priv->document)); + g_mutex_unlock (EV_DOC_MUTEX); + egg_find_bar_set_status_text (EGG_FIND_BAR (ev_window->priv->find_bar), NULL); gtk_widget_queue_draw (GTK_WIDGET (ev_window->priv->view)); @@ -2066,11 +2076,8 @@ static GtkRadioActionEntry page_view_entries[] = { static void goto_page_cb (GtkAction *action, int page_number, EvWindow *ev_window) { - EvView *view = EV_VIEW (ev_window->priv->view); - - if (ev_view_get_page (view) != page_number) { - ev_view_set_page (view, page_number); - } + ev_page_cache_set_current_page (ev_window->priv->page_cache, + page_number); } static void @@ -2353,10 +2360,6 @@ ev_window_init (EvWindow *ev_window) gtk_container_add (GTK_CONTAINER (ev_window->priv->scrolled_window), ev_window->priv->view); g_signal_connect (ev_window->priv->view, - "page-changed", - G_CALLBACK (view_page_changed_cb), - ev_window); - g_signal_connect (ev_window->priv->view, "notify::find-status", G_CALLBACK (view_find_status_changed_cb), ev_window); diff --git a/shell/main.c b/shell/main.c index 86450d4..6cd14e8 100644 --- a/shell/main.c +++ b/shell/main.c @@ -30,6 +30,7 @@ #include "ev-stock-icons.h" #include "ev-debug.h" +#include "ev-job-queue.h" static struct poptOption popt_options[] = { @@ -82,6 +83,7 @@ main (int argc, char *argv[]) GNOME_PARAM_APP_DATADIR, DATADIR, NULL); + ev_job_queue_init (); g_set_application_name (_("Evince Document Viewer")); ev_debug_init (); -- cgit v0.9.1