Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/shell
diff options
context:
space:
mode:
authorMarco Pesenti Gritti <marco@src.gnome.org>2005-03-23 11:07:32 (GMT)
committer Marco Pesenti Gritti <marco@src.gnome.org>2005-03-23 11:07:32 (GMT)
commit1c0d19bd22598eca159c3febdcdaf4168891cb8f (patch)
tree76cc5403e6c20380228ab3f7718130162fbf864d /shell
parent730f128d1fb4feb815c8111c9956d1598c655408 (diff)
merge evince-threads branch
Diffstat (limited to 'shell')
-rw-r--r--shell/Makefile.am2
-rw-r--r--shell/ev-pixbuf-cache.c525
-rw-r--r--shell/ev-pixbuf-cache.h51
-rw-r--r--shell/ev-print-job.c13
-rw-r--r--shell/ev-sidebar-links.c337
-rw-r--r--shell/ev-sidebar-thumbnails.c220
-rw-r--r--shell/ev-sidebar-thumbnails.h2
-rw-r--r--shell/ev-sidebar.c3
-rw-r--r--shell/ev-view.c342
-rw-r--r--shell/ev-view.h7
-rw-r--r--shell/ev-window.c115
-rw-r--r--shell/main.c2
12 files changed, 1064 insertions, 555 deletions
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 <gtk/gtkwidget.h>
+#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 <string.h>
+#include <glib/gi18n.h>
#include <gtk/gtk.h>
#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 ("<span size=\"larger\" style=\"italic\">%s</span>", _("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 ("<i>%d</i>", page_num);
+
+ if (link != NULL &&
+ ev_link_get_link_type (link) == EV_LINK_TYPE_PAGE) {
+ gchar *markup = g_strdup_printf ("<i>%d</i>", 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, &microseconds);
- 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 ("<i>%d</i>", 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 ();