Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/backend
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 /backend
parent730f128d1fb4feb815c8111c9956d1598c655408 (diff)
merge evince-threads branch
Diffstat (limited to 'backend')
-rw-r--r--backend/Makefile.am6
-rw-r--r--backend/ev-document-links.c48
-rw-r--r--backend/ev-document-links.h36
-rw-r--r--backend/ev-document.c106
-rw-r--r--backend/ev-document.h21
-rw-r--r--backend/ev-job-queue.c211
-rw-r--r--backend/ev-job-queue.h37
-rw-r--r--backend/ev-jobs.c246
-rw-r--r--backend/ev-jobs.h150
-rw-r--r--backend/ev-link.c10
-rw-r--r--backend/ev-link.h13
-rw-r--r--backend/ev-page-cache.c256
-rw-r--r--backend/ev-page-cache.h54
13 files changed, 1110 insertions, 84 deletions
diff --git a/backend/Makefile.am b/backend/Makefile.am
index 9030333..be84458 100644
--- a/backend/Makefile.am
+++ b/backend/Makefile.am
@@ -23,6 +23,12 @@ libevbackend_la_SOURCES= \
ev-document-security.h \
ev-document-find.c \
ev-document-find.h \
+ ev-job-queue.h \
+ ev-job-queue.c \
+ ev-jobs.h \
+ ev-jobs.c \
+ ev-page-cache.h \
+ ev-page-cache.c \
ev-ps-exporter.c \
ev-ps-exporter.h \
ev-document-misc.h \
diff --git a/backend/ev-document-links.c b/backend/ev-document-links.c
index 242efb6..d9baae0 100644
--- a/backend/ev-document-links.c
+++ b/backend/ev-document-links.c
@@ -24,6 +24,7 @@
#include "config.h"
#include "ev-document-links.h"
+#include "ev-job-queue.h"
GType
ev_document_links_get_type (void)
@@ -51,51 +52,20 @@ gboolean
ev_document_links_has_document_links (EvDocumentLinks *document_links)
{
EvDocumentLinksIface *iface = EV_DOCUMENT_LINKS_GET_IFACE (document_links);
- return iface->has_document_links (document_links);
-}
-
-EvDocumentLinksIter *
-ev_document_links_begin_read (EvDocumentLinks *document_links)
-{
- EvDocumentLinksIface *iface = EV_DOCUMENT_LINKS_GET_IFACE (document_links);
-
- return iface->begin_read (document_links);
-}
+ gboolean retval;
-EvLink *
-ev_document_links_get_link (EvDocumentLinks *document_links,
- EvDocumentLinksIter *iter)
-{
- EvDocumentLinksIface *iface = EV_DOCUMENT_LINKS_GET_IFACE (document_links);
+ retval = iface->has_document_links (document_links);
- return iface->get_link (document_links, iter);
+ return retval;
}
-EvDocumentLinksIter *
-ev_document_links_get_child (EvDocumentLinks *document_links,
- EvDocumentLinksIter *iter)
+GtkTreeModel *
+ev_document_links_get_links_model (EvDocumentLinks *document_links)
{
EvDocumentLinksIface *iface = EV_DOCUMENT_LINKS_GET_IFACE (document_links);
+ GtkTreeModel *retval;
- return iface->get_child (document_links, iter);
-}
-
-
-gboolean
-ev_document_links_next (EvDocumentLinks *document_links,
- EvDocumentLinksIter *iter)
-{
- EvDocumentLinksIface *iface = EV_DOCUMENT_LINKS_GET_IFACE (document_links);
-
- return iface->next (document_links, iter);
-}
-
-
-void
-ev_document_links_free_iter (EvDocumentLinks *document_links,
- EvDocumentLinksIter *iter)
-{
- EvDocumentLinksIface *iface = EV_DOCUMENT_LINKS_GET_IFACE (document_links);
+ retval = iface->get_links_model (document_links);
- iface->free_iter (document_links, iter);
+ return retval;
}
diff --git a/backend/ev-document-links.h b/backend/ev-document-links.h
index 59e638b..6105a70 100644
--- a/backend/ev-document-links.h
+++ b/backend/ev-document-links.h
@@ -26,7 +26,7 @@
#include <glib-object.h>
#include <glib.h>
-#include <gdk/gdk.h>
+#include <gtk/gtk.h>
#include "ev-document.h"
#include "ev-link.h"
@@ -43,37 +43,25 @@ G_BEGIN_DECLS
typedef struct _EvDocumentLinks EvDocumentLinks;
typedef struct _EvDocumentLinksIface EvDocumentLinksIface;
-typedef struct _EvDocumentLinksIter EvDocumentLinksIter;
+
+enum {
+ EV_DOCUMENT_LINKS_COLUMN_MARKUP,
+ EV_DOCUMENT_LINKS_COLUMN_LINK,
+ EV_DOCUMENT_LINKS_COLUMN_NUM_COLUMNS
+};
struct _EvDocumentLinksIface
{
GTypeInterface base_iface;
/* Methods */
- gboolean (* has_document_links) (EvDocumentLinks *document_links);
- EvDocumentLinksIter *(* begin_read) (EvDocumentLinks *document_links);
- EvLink *(* get_link) (EvDocumentLinks *document_links,
- EvDocumentLinksIter *iter);
- EvDocumentLinksIter *(* get_child) (EvDocumentLinks *document_links,
- EvDocumentLinksIter *iter);
- gboolean (* next) (EvDocumentLinks *document_links,
- EvDocumentLinksIter *iter);
- void (* free_iter) (EvDocumentLinks *document_links,
- EvDocumentLinksIter *iter);
+ gboolean (* has_document_links) (EvDocumentLinks *document_links);
+ GtkTreeModel *(* get_links_model) (EvDocumentLinks *document_links);
};
-GType ev_document_links_get_type (void);
-gboolean ev_document_links_has_document_links (EvDocumentLinks *document_links);
-EvDocumentLinksIter *ev_document_links_begin_read (EvDocumentLinks *document_links);
-EvLink *ev_document_links_get_link (EvDocumentLinks *document_links,
- EvDocumentLinksIter *iter);
-EvDocumentLinksIter *ev_document_links_get_child (EvDocumentLinks *document_links,
- EvDocumentLinksIter *iter);
-gboolean ev_document_links_next (EvDocumentLinks *document_links,
- EvDocumentLinksIter *iter);
-void ev_document_links_free_iter (EvDocumentLinks *document_links,
- EvDocumentLinksIter *iter);
-
+GType ev_document_links_get_type (void);
+gboolean ev_document_links_has_document_links (EvDocumentLinks *document_links);
+GtkTreeModel *ev_document_links_get_links_model (EvDocumentLinks *document_links);
G_END_DECLS
diff --git a/backend/ev-document.c b/backend/ev-document.c
index 5109969..6238ac5 100644
--- a/backend/ev-document.c
+++ b/backend/ev-document.c
@@ -21,7 +21,9 @@
#include "config.h"
#include "ev-document.h"
+
#include "ev-backend-marshalers.h"
+#include "ev-job-queue.h"
static void ev_document_class_init (gpointer g_class);
@@ -33,7 +35,10 @@ enum
};
static guint signals[LAST_SIGNAL] = { 0 };
+GMutex *ev_doc_mutex = NULL;
+
+#define LOG(x)
GType
ev_document_get_type (void)
{
@@ -98,13 +103,46 @@ ev_document_class_init (gpointer g_class)
G_PARAM_READABLE));
}
+#define PAGE_CACHE_STRING "ev-page-cache"
+
+EvPageCache *
+ev_document_get_page_cache (EvDocument *document)
+{
+ EvPageCache *page_cache;
+
+ g_return_val_if_fail (EV_IS_DOCUMENT (document), NULL);
+
+ page_cache = g_object_get_data (G_OBJECT (document), PAGE_CACHE_STRING);
+ if (page_cache == NULL) {
+ page_cache = _ev_page_cache_new (document);
+ g_object_set_data_full (G_OBJECT (document), PAGE_CACHE_STRING, page_cache, g_object_unref);
+ }
+
+ return page_cache;
+}
+
+GMutex *
+ev_document_get_doc_mutex (void)
+{
+ if (ev_doc_mutex == NULL) {
+ ev_doc_mutex = g_mutex_new ();
+ }
+ return ev_doc_mutex;
+}
+
+
gboolean
ev_document_load (EvDocument *document,
const char *uri,
GError **error)
{
EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
- return iface->load (document, uri, error);
+ gboolean retval;
+ LOG ("ev_document_load");
+ retval = iface->load (document, uri, error);
+ /* Call this to make the initial cached copy */
+ ev_document_get_page_cache (document);
+ return retval;
}
gboolean
@@ -113,7 +151,12 @@ ev_document_save (EvDocument *document,
GError **error)
{
EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
- return iface->save (document, uri, error);
+ gboolean retval;
+
+ LOG ("ev_document_save");
+ retval = iface->save (document, uri, error);
+
+ return retval;
}
char *
@@ -121,6 +164,7 @@ ev_document_get_title (EvDocument *document)
{
char *title;
+ LOG ("ev_document_get_title");
g_object_get (document, "title", &title, NULL);
return title;
@@ -130,7 +174,12 @@ int
ev_document_get_n_pages (EvDocument *document)
{
EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
- return iface->get_n_pages (document);
+ gint retval;
+
+ LOG ("ev_document_get_n_pages");
+ retval = iface->get_n_pages (document);
+
+ return retval;
}
void
@@ -138,6 +187,8 @@ ev_document_set_page (EvDocument *document,
int page)
{
EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
+
+ LOG ("ev_document_set_page");
iface->set_page (document, page);
}
@@ -145,7 +196,12 @@ int
ev_document_get_page (EvDocument *document)
{
EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
- return iface->get_page (document);
+ int retval;
+
+ LOG ("ev_document_get_page");
+ retval = iface->get_page (document);
+
+ return retval;
}
void
@@ -153,6 +209,8 @@ ev_document_set_target (EvDocument *document,
GdkDrawable *target)
{
EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
+
+ LOG ("ev_document_set_target");
iface->set_target (document, target);
}
@@ -161,6 +219,8 @@ ev_document_set_scale (EvDocument *document,
double scale)
{
EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
+
+ LOG ("ev_document_set_scale");
iface->set_scale (document, scale);
}
@@ -170,6 +230,8 @@ ev_document_set_page_offset (EvDocument *document,
int y)
{
EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
+
+ LOG ("ev_document_set_page_offset");
iface->set_page_offset (document, x, y);
}
@@ -180,6 +242,8 @@ ev_document_get_page_size (EvDocument *document,
int *height)
{
EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
+
+ LOG ("ev_document_get_page_size");
iface->get_page_size (document, page, width, height);
}
@@ -188,7 +252,12 @@ ev_document_get_text (EvDocument *document,
GdkRectangle *rect)
{
EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
- return iface->get_text (document, rect);
+ char *retval;
+
+ LOG ("ev_document_get_text");
+ retval = iface->get_text (document, rect);
+
+ return retval;
}
EvLink *
@@ -197,7 +266,12 @@ ev_document_get_link (EvDocument *document,
int y)
{
EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
- return iface->get_link (document, x, y);
+ EvLink *retval;
+
+ LOG ("ev_document_get_link");
+ retval = iface->get_link (document, x, y);
+
+ return retval;
}
void
@@ -208,9 +282,27 @@ ev_document_render (EvDocument *document,
int clip_height)
{
EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
+
+ LOG ("ev_document_render");
iface->render (document, clip_x, clip_y, clip_width, clip_height);
}
+
+GdkPixbuf *
+ev_document_render_pixbuf (EvDocument *document)
+{
+ EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
+ GdkPixbuf *retval;
+
+ LOG ("ev_document_render_pixbuf");
+ g_assert (iface->render_pixbuf);
+
+ retval = iface->render_pixbuf (document);
+
+ return retval;
+}
+
+
void
ev_document_page_changed (EvDocument *document)
{
@@ -221,4 +313,4 @@ void
ev_document_scale_changed (EvDocument *document)
{
g_signal_emit (G_OBJECT (document), signals[SCALE_CHANGED], 0);
-}
+}
diff --git a/backend/ev-document.h b/backend/ev-document.h
index b54a0b9..be0d1db 100644
--- a/backend/ev-document.h
+++ b/backend/ev-document.h
@@ -37,10 +37,16 @@ G_BEGIN_DECLS
#define EV_IS_DOCUMENT_IFACE(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EV_TYPE_DOCUMENT))
#define EV_DOCUMENT_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), EV_TYPE_DOCUMENT, EvDocumentIface))
-typedef struct _EvDocument EvDocument;
-typedef struct _EvDocumentIface EvDocumentIface;
+typedef struct _EvDocument EvDocument;
+typedef struct _EvDocumentIface EvDocumentIface;
+typedef struct _EvPageCache EvPageCache;
+typedef struct _EvPageCacheClass EvPageCacheClass;
+
+#include "ev-page-cache.h"
+
#define EV_DOCUMENT_ERROR ev_document_error_quark ()
+#define EV_DOC_MUTEX (ev_document_get_doc_mutex ())
typedef enum
{
@@ -88,12 +94,17 @@ struct _EvDocumentIface
int clip_y,
int clip_width,
int clip_height);
+ GdkPixbuf *(* render_pixbuf) (EvDocument *document);
+
};
-GType ev_document_get_type (void);
-GQuark ev_document_error_quark (void);
+GType ev_document_get_type (void);
+GQuark ev_document_error_quark (void);
+EvPageCache *ev_document_get_page_cache (EvDocument *document);
+GMutex *ev_document_get_doc_mutex (void);
+
gboolean ev_document_load (EvDocument *document,
const char *uri,
@@ -127,6 +138,8 @@ void ev_document_render (EvDocument *document,
int clip_y,
int clip_width,
int clip_height);
+/* Quick hack to test threaded rendering */
+GdkPixbuf *ev_document_render_pixbuf (EvDocument *document);
void ev_document_page_changed (EvDocument *document);
void ev_document_scale_changed (EvDocument *document);
diff --git a/backend/ev-job-queue.c b/backend/ev-job-queue.c
new file mode 100644
index 0000000..4bd824f
--- /dev/null
+++ b/backend/ev-job-queue.c
@@ -0,0 +1,211 @@
+#include "ev-job-queue.h"
+
+/* Like glib calling convention, all functions with _locked in their name assume
+ * that we've already locked the doc mutex and can freely and safely access
+ * data.
+ */
+GCond *render_cond = NULL;
+GMutex *ev_queue_mutex = NULL;
+
+static GQueue *links_queue = NULL;
+static GQueue *render_queue_high = NULL;
+static GQueue *render_queue_low = NULL;
+static GQueue *thumbnail_queue_high = NULL;
+static GQueue *thumbnail_queue_low = NULL;
+
+static gboolean
+remove_object_from_queue (GQueue *queue, EvJob *job)
+{
+ GList *list;
+
+ list = g_queue_find (queue, job);
+ if (list) {
+ g_object_unref (G_OBJECT (job));
+ g_queue_delete_link (queue, list);
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+static gboolean
+notify_finished (GObject *job)
+{
+ ev_job_finished (EV_JOB (job));
+
+ return FALSE;
+}
+
+
+static void
+handle_job (EvJob *job)
+{
+ g_object_ref (G_OBJECT (job));
+
+ if (EV_IS_JOB_THUMBNAIL (job))
+ ev_job_thumbnail_run (EV_JOB_THUMBNAIL (job));
+ else if (EV_IS_JOB_LINKS (job))
+ ev_job_links_run (EV_JOB_LINKS (job));
+ else if (EV_IS_JOB_RENDER (job))
+ ev_job_render_run (EV_JOB_RENDER (job));
+
+ /* We let the idle own a ref, as we (the queue) are done with the job. */
+ g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+ (GSourceFunc) notify_finished,
+ job,
+ g_object_unref);
+}
+
+static EvJob *
+search_for_jobs_unlocked (void)
+{
+ EvJob *job;
+
+ job = (EvJob *) g_queue_pop_head (render_queue_high);
+ if (job)
+ return job;
+
+ job = (EvJob *) g_queue_pop_head (thumbnail_queue_high);
+ if (job)
+ return job;
+
+ job = (EvJob *) g_queue_pop_head (render_queue_low);
+ if (job)
+ return job;
+
+ job = (EvJob *) g_queue_pop_head (links_queue);
+ if (job)
+ return job;
+
+ job = (EvJob *) g_queue_pop_head (thumbnail_queue_low);
+ if (job)
+ return job;
+
+ return NULL;
+}
+
+static gboolean
+no_jobs_available_unlocked (void)
+{
+ return g_queue_is_empty (render_queue_high)
+ && g_queue_is_empty (render_queue_low)
+ && g_queue_is_empty (links_queue)
+ && g_queue_is_empty (thumbnail_queue_high)
+ && g_queue_is_empty (thumbnail_queue_low);
+}
+
+/* the thread mainloop function */
+static gpointer
+ev_render_thread (gpointer data)
+{
+ while (TRUE) {
+ EvJob *job;
+
+ g_mutex_lock (ev_queue_mutex);
+ if (no_jobs_available_unlocked ()) {
+ g_cond_wait (render_cond, ev_queue_mutex);
+ }
+
+ job = search_for_jobs_unlocked ();
+ g_mutex_unlock (ev_queue_mutex);
+
+ /* Now that we have our job, we handle it */
+ if (job) {
+ handle_job (job);
+ g_object_unref (G_OBJECT (job));
+ }
+ }
+ return NULL;
+
+}
+
+/* Public Functions */
+void
+ev_job_queue_init (void)
+{
+ if (!g_thread_supported ()) g_thread_init (NULL);
+
+ render_cond = g_cond_new ();
+ ev_queue_mutex = g_mutex_new ();
+
+ links_queue = g_queue_new ();
+ render_queue_high = g_queue_new ();
+ render_queue_low = g_queue_new ();
+ thumbnail_queue_high = g_queue_new ();
+ thumbnail_queue_low = g_queue_new ();
+
+ g_thread_create (ev_render_thread, NULL, FALSE, NULL);
+
+}
+
+static GQueue *
+find_queue (EvJob *job,
+ EvJobPriority priority)
+{
+ if (EV_IS_JOB_RENDER (job)) {
+ if (priority == EV_JOB_PRIORITY_HIGH)
+ return render_queue_high;
+ else
+ return render_queue_low;
+ } else if (EV_IS_JOB_THUMBNAIL (job)) {
+ if (priority == EV_JOB_PRIORITY_HIGH)
+ return thumbnail_queue_high;
+ else
+ return thumbnail_queue_low;
+ } else if (EV_IS_JOB_LINKS (job)) {
+ /* the priority doesn't effect links */
+ return links_queue;
+ }
+
+ g_assert_not_reached ();
+ return NULL;
+}
+
+void
+ev_job_queue_add_job (EvJob *job,
+ EvJobPriority priority)
+{
+ GQueue *queue;
+
+ g_return_if_fail (EV_IS_JOB (job));
+
+ queue = find_queue (job, priority);
+
+ g_mutex_lock (ev_queue_mutex);
+
+ g_object_ref (job);
+ g_queue_push_tail (queue, job);
+ g_cond_broadcast (render_cond);
+
+ g_mutex_unlock (ev_queue_mutex);
+
+}
+
+gboolean
+ev_job_queue_remove_job (EvJob *job)
+{
+ gboolean retval = FALSE;
+
+ g_return_val_if_fail (EV_IS_JOB (job), FALSE);
+
+ g_mutex_lock (ev_queue_mutex);
+
+ if (EV_IS_JOB_THUMBNAIL (job)) {
+ retval = remove_object_from_queue (thumbnail_queue_high, job);
+ retval = retval || remove_object_from_queue (thumbnail_queue_low, job);
+ } else if (EV_IS_JOB_RENDER (job)) {
+ retval = remove_object_from_queue (render_queue_high, job);
+ retval = retval || remove_object_from_queue (render_queue_low, job);
+ } else if (EV_IS_JOB_LINKS (job)) {
+ retval = remove_object_from_queue (links_queue, job);
+ } else {
+ g_assert_not_reached ();
+ }
+
+ g_mutex_unlock (ev_queue_mutex);
+
+ return retval;
+}
+
+
diff --git a/backend/ev-job-queue.h b/backend/ev-job-queue.h
new file mode 100644
index 0000000..ec93389
--- /dev/null
+++ b/backend/ev-job-queue.h
@@ -0,0 +1,37 @@
+/* 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_JOB_QUEUE_H__
+#define __EV_JOB_QUEUE_H__
+
+#include <gtk/gtk.h>
+#include "ev-jobs.h"
+
+G_BEGIN_DECLS
+
+
+void ev_job_queue_init (void);
+
+void ev_job_queue_add_job (EvJob *job,
+ EvJobPriority priority);
+gboolean ev_job_queue_remove_job (EvJob *job);
+
+G_END_DECLS
+
+#endif /* __EV_JOB_QUEUE_H__ */
diff --git a/backend/ev-jobs.c b/backend/ev-jobs.c
new file mode 100644
index 0000000..355a103
--- /dev/null
+++ b/backend/ev-jobs.c
@@ -0,0 +1,246 @@
+#include "ev-jobs.h"
+#include "ev-job-queue.h"
+#include "ev-document-thumbnails.h"
+#include "ev-document-links.h"
+
+static void ev_job_init (EvJob *job);
+static void ev_job_class_init (EvJobClass *class);
+static void ev_job_links_init (EvJobLinks *job);
+static void ev_job_links_class_init (EvJobLinksClass *class);
+static void ev_job_render_init (EvJobRender *job);
+static void ev_job_render_class_init (EvJobRenderClass *class);
+static void ev_job_thumbnail_init (EvJobThumbnail *job);
+static void ev_job_thumbnail_class_init (EvJobThumbnailClass *class);
+
+enum
+{
+ FINISHED,
+ LAST_SIGNAL
+};
+
+static guint job_signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (EvJob, ev_job, G_TYPE_OBJECT)
+G_DEFINE_TYPE (EvJobLinks, ev_job_links, EV_TYPE_JOB)
+G_DEFINE_TYPE (EvJobRender, ev_job_render, EV_TYPE_JOB)
+G_DEFINE_TYPE (EvJobThumbnail, ev_job_thumbnail, EV_TYPE_JOB)
+
+
+static void ev_job_init (EvJob *job) { /* Do Nothing */ }
+
+static void
+ev_job_dispose (GObject *object)
+{
+ EvJob *job;
+
+ job = EV_JOB (object);
+
+ if (job->document) {
+ g_object_unref (job->document);
+ job->document = NULL;
+ }
+
+ (* G_OBJECT_CLASS (ev_job_parent_class)->dispose) (object);
+}
+
+static void
+ev_job_class_init (EvJobClass *class)
+{
+ GObjectClass *oclass;
+
+ oclass = G_OBJECT_CLASS (class);
+
+ oclass->dispose = ev_job_dispose;
+
+ job_signals [FINISHED] =
+ g_signal_new ("finished",
+ EV_TYPE_JOB,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EvJobClass, finished),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+
+static void ev_job_links_init (EvJobLinks *job) { /* Do Nothing */ }
+
+static void
+ev_job_links_dispose (GObject *object)
+{
+ EvJobLinks *job;
+
+ job = EV_JOB_LINKS (object);
+
+ if (job->model) {
+ g_object_unref (job->model);
+ job->model = NULL;
+ }
+
+ (* G_OBJECT_CLASS (ev_job_links_parent_class)->dispose) (object);
+}
+
+static void
+ev_job_links_class_init (EvJobLinksClass *class)
+{
+ GObjectClass *oclass;
+
+ oclass = G_OBJECT_CLASS (class);
+
+ oclass->dispose = ev_job_links_dispose;
+}
+
+
+static void ev_job_render_init (EvJobRender *job) { /* Do Nothing */ }
+
+static void
+ev_job_render_dispose (GObject *object)
+{
+ EvJobRender *job;
+
+ job = EV_JOB_RENDER (object);
+
+ if (job->pixbuf) {
+ g_object_unref (job->pixbuf);
+ job->pixbuf = NULL;
+ }
+
+ (* G_OBJECT_CLASS (ev_job_render_parent_class)->dispose) (object);
+}
+
+static void
+ev_job_render_class_init (EvJobRenderClass *class)
+{
+ GObjectClass *oclass;
+
+ oclass = G_OBJECT_CLASS (class);
+
+ oclass->dispose = ev_job_render_dispose;
+}
+
+static void ev_job_thumbnail_init (EvJobThumbnail *job) { /* Do Nothing */ }
+
+static void
+ev_job_thumbnail_dispose (GObject *object)
+{
+ EvJobThumbnail *job;
+
+ job = EV_JOB_THUMBNAIL (object);
+
+ if (job->thumbnail) {
+ g_object_unref (job->thumbnail);
+ job->thumbnail = NULL;
+ }
+
+ (* G_OBJECT_CLASS (ev_job_thumbnail_parent_class)->dispose) (object);
+}
+
+static void
+ev_job_thumbnail_class_init (EvJobThumbnailClass *class)
+{
+ GObjectClass *oclass;
+
+ oclass = G_OBJECT_CLASS (class);
+
+ oclass->dispose = ev_job_thumbnail_dispose;
+}
+
+/* Public functions */
+void
+ev_job_finished (EvJob *job)
+{
+ g_return_if_fail (EV_IS_JOB (job));
+
+ g_signal_emit (job, job_signals[FINISHED], 0);
+}
+
+EvJob *
+ev_job_links_new (EvDocument *document)
+{
+ EvJob *job;
+
+ job = g_object_new (EV_TYPE_JOB_LINKS, NULL);
+ job->document = g_object_ref (document);
+
+ return job;
+}
+
+void
+ev_job_links_run (EvJobLinks *job)
+{
+ g_return_if_fail (EV_IS_JOB_LINKS (job));
+
+ g_mutex_lock (EV_DOC_MUTEX);
+ job->model = ev_document_links_get_links_model (EV_DOCUMENT_LINKS (EV_JOB (job)->document));
+ EV_JOB (job)->finished = TRUE;
+ g_mutex_unlock (EV_DOC_MUTEX);
+}
+
+
+EvJob *
+ev_job_render_new (EvDocument *document,
+ gint page,
+ double scale,
+ gint width,
+ gint height)
+{
+ EvJobRender *job;
+
+ job = g_object_new (EV_TYPE_JOB_RENDER, NULL);
+
+ EV_JOB (job)->document = g_object_ref (document);
+ job->page = page;
+ job->scale = scale;
+ job->target_width = width;
+ job->target_height = height;
+
+ return EV_JOB (job);
+}
+
+void
+ev_job_render_run (EvJobRender *job)
+{
+ g_return_if_fail (EV_IS_JOB_RENDER (job));
+
+ g_mutex_lock (EV_DOC_MUTEX);
+
+ ev_document_set_scale (EV_JOB (job)->document, job->scale);
+ ev_document_set_page (EV_JOB (job)->document, job->page);
+ job->pixbuf = ev_document_render_pixbuf (EV_JOB (job)->document);
+ EV_JOB (job)->finished = TRUE;
+
+ g_mutex_unlock (EV_DOC_MUTEX);
+}
+
+EvJob *
+ev_job_thumbnail_new (EvDocument *document,
+ gint page,
+ gint requested_width)
+{
+ EvJobThumbnail *job;
+
+ job = g_object_new (EV_TYPE_JOB_THUMBNAIL, NULL);
+
+ EV_JOB (job)->document = g_object_ref (document);
+ job->page = page;
+ job->requested_width = requested_width;
+
+ return EV_JOB (job);
+}
+
+void
+ev_job_thumbnail_run (EvJobThumbnail *job)
+{
+ g_return_if_fail (EV_IS_JOB_THUMBNAIL (job));
+
+ g_mutex_lock (EV_DOC_MUTEX);
+
+ job->thumbnail =
+ ev_document_thumbnails_get_thumbnail (EV_DOCUMENT_THUMBNAILS (EV_JOB (job)->document),
+ job->page,
+ job->requested_width,
+ TRUE);
+ EV_JOB (job)->finished = TRUE;
+
+ g_mutex_unlock (EV_DOC_MUTEX);
+}
diff --git a/backend/ev-jobs.h b/backend/ev-jobs.h
new file mode 100644
index 0000000..a212349
--- /dev/null
+++ b/backend/ev-jobs.h
@@ -0,0 +1,150 @@
+/* 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_JOBS_H__
+#define __EV_JOBS_H__
+
+#include <gtk/gtk.h>
+#include "ev-document.h"
+
+G_BEGIN_DECLS
+
+typedef struct _EvJob EvJob;
+typedef struct _EvJobClass EvJobClass;
+
+typedef struct _EvJobRender EvJobRender;
+typedef struct _EvJobRenderClass EvJobRenderClass;
+
+typedef struct _EvJobThumbnail EvJobThumbnail;
+typedef struct _EvJobThumbnailClass EvJobThumbnailClass;
+
+typedef struct _EvJobLinks EvJobLinks;
+typedef struct _EvJobLinksClass EvJobLinksClass;
+
+#define EV_TYPE_JOB (ev_job_get_type())
+#define EV_JOB(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB, EvJob))
+#define EV_JOB_CLASS(klass) (G_TYPE_CHACK_CLASS_CAST((klass), EV_TYPE_JOB, EvJobClass))
+#define EV_IS_JOB(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB))
+
+#define EV_TYPE_JOB_LINKS (ev_job_links_get_type())
+#define EV_JOB_LINKS(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_LINKS, EvJobLinks))
+#define EV_JOB_LINKS_CLASS(klass) (G_TYPE_CHACK_CLASS_CAST((klass), EV_TYPE_JOB_LINKS, EvJobLinksClass))
+#define EV_IS_JOB_LINKS(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_LINKS))
+
+#define EV_TYPE_JOB_RENDER (ev_job_render_get_type())
+#define EV_JOB_RENDER(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_RENDER, EvJobRender))
+#define EV_JOB_RENDER_CLASS(klass) (G_TYPE_CHACK_CLASS_CAST((klass), EV_TYPE_JOB_RENDER, EvJobRenderClass))
+#define EV_IS_JOB_RENDER(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_RENDER))
+
+#define EV_TYPE_JOB_THUMBNAIL (ev_job_thumbnail_get_type())
+#define EV_JOB_THUMBNAIL(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_THUMBNAIL, EvJobThumbnail))
+#define EV_JOB_THUMBNAIL_CLASS(klass) (G_TYPE_CHACK_CLASS_CAST((klass), EV_TYPE_JOB_THUMBNAIL, EvJobThumbnailClass))
+#define EV_IS_JOB_THUMBNAIL(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_THUMBNAIL))
+
+typedef enum {
+ EV_JOB_PRIORITY_LOW,
+ EV_JOB_PRIORITY_HIGH,
+} EvJobPriority;
+
+struct _EvJob
+{
+ GObject parent;
+ EvDocument *document;
+ gboolean finished;
+};
+
+struct _EvJobClass
+{
+ GObjectClass parent_class;
+
+ void (* finished) (EvJob *job);
+};
+
+struct _EvJobLinks
+{
+ EvJob parent;
+
+ GtkTreeModel *model;
+};
+
+struct _EvJobLinksClass
+{
+ EvJobClass parent_class;
+};
+
+struct _EvJobRender
+{
+ EvJob parent;
+
+ gint page;
+ double scale;
+ gint target_width;
+ gint target_height;
+ GdkPixbuf *pixbuf;
+};
+
+struct _EvJobRenderClass
+{
+ EvJobClass parent_class;
+};
+
+struct _EvJobThumbnail
+{
+ EvJob parent;
+
+ gint page;
+ gint requested_width;
+ GdkPixbuf *thumbnail;
+};
+
+struct _EvJobThumbnailClass
+{
+ EvJobClass parent_class;
+};
+
+
+/* Base job class */
+GType ev_job_get_type (void);
+void ev_job_finished (EvJob *job);
+
+/* EvJobLinks */
+GType ev_job_links_get_type (void);
+EvJob *ev_job_links_new (EvDocument *document);
+void ev_job_links_run (EvJobLinks *thumbnail);
+
+/* EvJobRender */
+GType ev_job_render_get_type (void);
+EvJob *ev_job_render_new (EvDocument *document,
+ gint page,
+ double scale,
+ gint width,
+ gint height);
+void ev_job_render_run (EvJobRender *thumbnail);
+
+/* EvJobThumbnail */
+GType ev_job_thumbnail_get_type (void);
+EvJob *ev_job_thumbnail_new (EvDocument *document,
+ gint page,
+ gint requested_width);
+void ev_job_thumbnail_run (EvJobThumbnail *thumbnail);
+
+
+G_END_DECLS
+
+#endif /* __EV_JOBS_H__ */
diff --git a/backend/ev-link.c b/backend/ev-link.c
index e01aa19..7e6eb52 100644
--- a/backend/ev-link.c
+++ b/backend/ev-link.c
@@ -32,6 +32,16 @@ enum {
PROP_URI
};
+
+struct _EvLink {
+ GObject base_instance;
+ EvLinkPrivate *priv;
+};
+
+struct _EvLinkClass {
+ GObjectClass base_class;
+};
+
struct _EvLinkPrivate {
char *title;
char *uri;
diff --git a/backend/ev-link.h b/backend/ev-link.h
index 00d97c4..d92d428 100644
--- a/backend/ev-link.h
+++ b/backend/ev-link.h
@@ -41,18 +41,11 @@ typedef enum
{
EV_LINK_TYPE_TITLE,
EV_LINK_TYPE_PAGE,
- EV_LINK_TYPE_EXTERNAL_URI
+ EV_LINK_TYPE_EXTERNAL_URI,
+ /* We'll probably fill this in more as we support the other types of
+ * links */
} EvLinkType;
-struct _EvLink {
- GObject base_instance;
- EvLinkPrivate *priv;
-};
-
-struct _EvLinkClass {
- GObjectClass base_class;
-};
-
GType ev_link_type_get_type (void);
GType ev_link_get_type (void);
diff --git a/backend/ev-page-cache.c b/backend/ev-page-cache.c
new file mode 100644
index 0000000..e2771b6
--- /dev/null
+++ b/backend/ev-page-cache.c
@@ -0,0 +1,256 @@
+#include "ev-page-cache.h"
+#include "ev-job-queue.h"
+
+typedef struct _EvPageCacheInfo
+{
+ gint width;
+ gint height;
+}
+EvPageCacheInfo;
+
+
+struct _EvPageCache
+{
+ GObject parent;
+
+ gint current_page;
+ int n_pages;
+ char *title;
+
+ gboolean uniform;
+ gint uniform_width;
+ gint uniform_height;
+
+ EvPageCacheInfo *size_cache;
+};
+
+struct _EvPageCacheClass
+{
+ GObjectClass parent_class;
+
+ void (* page_changed) (EvPageCache *page_cache, gint page);
+};
+
+enum
+{
+ PAGE_CHANGED,
+ N_SIGNALS,
+};
+
+static guint signals[N_SIGNALS] = {0, };
+
+static void ev_page_cache_init (EvPageCache *page_cache);
+static void ev_page_cache_class_init (EvPageCacheClass *page_cache);
+static void ev_page_cache_finalize (GObject *object);
+
+G_DEFINE_TYPE (EvPageCache, ev_page_cache, G_TYPE_OBJECT)
+
+static void
+ev_page_cache_init (EvPageCache *page_cache)
+{
+ page_cache->current_page = 1;
+}
+
+static void
+ev_page_cache_class_init (EvPageCacheClass *class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = ev_page_cache_finalize;
+
+ signals [PAGE_CHANGED] =
+ g_signal_new ("page-changed",
+ EV_TYPE_PAGE_CACHE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EvPageCacheClass, page_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE, 1,
+ G_TYPE_INT);
+
+}
+
+static void
+ev_page_cache_finalize (GObject *object)
+{
+ EvPageCache *page_cache;
+
+ page_cache = EV_PAGE_CACHE (object);
+
+ g_free (page_cache->title);
+ g_free (page_cache->size_cache);
+}
+
+EvPageCache *
+_ev_page_cache_new (EvDocument *document)
+{
+ EvPageCache *page_cache;
+ EvPageCacheInfo *info;
+ gint i;
+
+ page_cache = (EvPageCache *) g_object_new (EV_TYPE_PAGE_CACHE, NULL);
+
+ g_mutex_lock (EV_DOC_MUTEX);
+
+ /* We read page information out of the document */
+
+ /* Assume all pages are the same size until proven otherwise */
+ page_cache->uniform = TRUE;
+ page_cache->n_pages = ev_document_get_n_pages (document);
+ page_cache->title = ev_document_get_title (document);
+
+ ev_document_set_scale (document, 1.0);
+ for (i = 1; i <= page_cache->n_pages; i++) {
+ gint page_width = 0;
+ gint page_height = 0;
+
+ ev_document_get_page_size (document, i, &page_width, &page_height);
+
+ if (i == 1) {
+ page_cache->uniform_width = page_width;
+ page_cache->uniform_height = page_height;
+ } else if (page_cache->uniform &&
+ (page_cache->uniform_width != page_width ||
+ page_cache->uniform_height != page_height)) {
+ /* It's a different page size. Backfill the array. */
+ int j;
+
+ page_cache->size_cache = g_new0 (EvPageCacheInfo, page_cache->n_pages);
+
+ for (j = 1; j < i; j++) {
+ info = &(page_cache->size_cache [j - 1]);
+ info->width = page_width;
+ info->height = page_height;
+ }
+ page_cache->uniform = FALSE;
+
+ }
+
+ if (! page_cache->uniform) {
+ info = &(page_cache->size_cache [i - 1]);
+
+ info->width = page_width;
+ info->height = page_height;
+ }
+ }
+
+ /* make some sanity check assertions */
+ g_assert (page_cache->n_pages > 0);
+ if (! page_cache->uniform)
+ g_assert (page_cache->size_cache != NULL);
+ if (page_cache->uniform)
+ g_assert (page_cache->uniform_width > 0 && page_cache->uniform_height > 0);
+
+ g_mutex_unlock (EV_DOC_MUTEX);
+
+ return page_cache;
+}
+
+gint
+ev_page_cache_get_n_pages (EvPageCache *page_cache)
+{
+ g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0);
+
+ return page_cache->n_pages;
+}
+
+gint
+ev_page_cache_get_current_page (EvPageCache *page_cache)
+{
+ g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0);
+
+ return page_cache->current_page;
+}
+
+void
+ev_page_cache_set_current_page (EvPageCache *page_cache,
+ int page)
+{
+ g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
+ g_return_if_fail (page > 0 || page <= page_cache->n_pages);
+
+ if (page == page_cache->current_page)
+ return;
+
+ page_cache->current_page = page;
+ g_signal_emit (page_cache, signals[PAGE_CHANGED], 0, page);
+}
+
+void
+ev_page_cache_set_link (EvPageCache *page_cache,
+ EvLink *link)
+{
+ g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
+ g_return_if_fail (EV_IS_LINK (link));
+
+ ev_page_cache_set_current_page (page_cache, ev_link_get_page (link));
+}
+
+char *
+ev_page_cache_get_title (EvPageCache *page_cache)
+{
+ g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), NULL);
+
+ return page_cache->title;
+}
+
+void
+ev_page_cache_get_size (EvPageCache *page_cache,
+ gint page,
+ gfloat scale,
+ gint *width,
+ gint *height)
+{
+ g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
+ g_return_if_fail (page > 0 && page <= page_cache->n_pages);
+
+ if (page_cache->uniform) {
+ if (width)
+ *width = page_cache->uniform_width;
+ if (height)
+ *height = page_cache->uniform_height;
+ } else {
+ EvPageCacheInfo *info;
+
+ info = &(page_cache->size_cache [page - 1]);
+
+ if (width)
+ *width = info->width;
+ if (height)
+ *height = info->height;
+ }
+
+ if (width)
+ *width = (*width) * scale;
+ if (width)
+ *height = (*height) * scale;
+
+}
+
+gboolean
+ev_page_cache_next_page (EvPageCache *page_cache)
+{
+ g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE);
+
+ if (page_cache->current_page >= page_cache->n_pages)
+ return FALSE;
+
+ ev_page_cache_set_current_page (page_cache, page_cache->current_page + 1);
+ return TRUE;
+
+}
+
+gboolean
+ev_page_cache_prev_page (EvPageCache *page_cache)
+{
+ g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE);
+
+ if (page_cache->current_page <= 1)
+ return FALSE;
+
+ ev_page_cache_set_current_page (page_cache, page_cache->current_page - 1);
+ return TRUE;
+}
+
diff --git a/backend/ev-page-cache.h b/backend/ev-page-cache.h
new file mode 100644
index 0000000..9edf67c
--- /dev/null
+++ b/backend/ev-page-cache.h
@@ -0,0 +1,54 @@
+/* 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_PAGE_CACHE_H__
+#define __EV_PAGE_CACHE_H__
+
+#include <gtk/gtkwidget.h>
+#include "ev-document.h"
+
+G_BEGIN_DECLS
+#define EV_TYPE_PAGE_CACHE (ev_page_cache_get_type ())
+#define EV_PAGE_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_PAGE_CACHE, EvPageCache))
+#define EV_IS_PAGE_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_PAGE_CACHE))
+
+GType ev_page_cache_get_type (void) G_GNUC_CONST;
+/* Used by ev-document.c only */
+EvPageCache *_ev_page_cache_new (EvDocument *document);
+
+gint ev_page_cache_get_n_pages (EvPageCache *page_cache);
+char *ev_page_cache_get_title (EvPageCache *page_cache);
+void ev_page_cache_get_size (EvPageCache *page_cache,
+ gint page,
+ gfloat scale,
+ gint *width,
+ gint *height);
+
+/* Navigation */
+gint ev_page_cache_get_current_page (EvPageCache *page_cache);
+void ev_page_cache_set_current_page (EvPageCache *page_cache,
+ int page);
+void ev_page_cache_set_link (EvPageCache *page_cache,
+ EvLink *link);
+gboolean ev_page_cache_next_page (EvPageCache *page_cache);
+gboolean ev_page_cache_prev_page (EvPageCache *page_cache);
+
+G_END_DECLS
+
+#endif /* __EV_PAGE_CACHE_H__ */