From 1c0d19bd22598eca159c3febdcdaf4168891cb8f Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Wed, 23 Mar 2005 11:07:32 +0000 Subject: merge evince-threads branch --- (limited to 'backend') 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 #include -#include +#include #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 +#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 +#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 +#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__ */ -- cgit v0.9.1