From e8096c18ba580156072e8c84103bee6f6d3f0bfc Mon Sep 17 00:00:00 2001 From: Jonathan Blandford Date: Thu, 31 Mar 2005 15:34:35 +0000 Subject: [PATCH] Remove pixbuf backend for now Thu Mar 31 01:21:58 2005 Jonathan Blandford * Makefile.am: Remove pixbuf backend for now * configure.ac: Require poppler-glib instead of just poppler. * backend/ev-document-thumbnails.h: Add a comment * backend/ev-document.h: * backend/ev-document.c: (ev_document_class_init), (ev_document_load), (ev_document_get_link), (ev_document_get_links): Remove 3 methods and add get_links. Also, made 0 based. * backend/ev-jobs.c: (ev_job_render_new), (ev_job_render_run): * backend/ev-jobs.h: now EvJobRender can grab the links for a document. * backend/ev-link.c: (ev_link_set_title), (ev_link_mapping_free_foreach), (ev_link_mapping_free), (ev_link_mapping_find): * backend/ev-link.h: Allow NULL titles. Also, introduce a mapping link. * backend/ev-page-cache.c: (ev_page_cache_init), (_ev_page_cache_new), (ev_page_cache_set_current_page), (ev_page_cache_get_size), (ev_page_cache_next_page), (ev_page_cache_prev_page): Fix to be 0 based. * pdf/Makefile.am: * pdf/ev-poppler.h: * pdf/ev-poppler.cc: New backend. * ps/ps-document.c: (ps_document_init), (ps_document_set_page), (ps_document_get_page), (ps_document_document_iface_init): * shell/ev-pixbuf-cache.h: * shell/ev-pixbuf-cache.c: (ev_pixbuf_cache_init), (dispose_cache_job_info), (job_finished_cb), (move_one_job), (ev_pixbuf_cache_update_range), (copy_job_to_job_info), (add_job_if_needed), (ev_pixbuf_cache_set_page_range), (ev_pixbuf_cache_get_pixbuf), (ev_pixbuf_cache_get_link_mapping): Fix up code to grab a page cache per each doc. Also, fix to be 0 based. * shell/ev-sidebar-thumbnails.c: (ev_sidebar_tree_selection_changed), (page_changed_cb), (ev_sidebar_thumbnails_set_document): Fix to be 0 based. * shell/ev-view.c: (status_message_from_link), (find_page_at_location), (get_link_at_location), (ev_view_motion_notify_event), (ev_view_button_release_event), (ev_view_init): Use the new link code. Fix to be 0 based. * shell/ev-window.c: (update_action_sensitivity), (document_supports_sidebar): 0 based. --- ChangeLog | 55 +++ Makefile.am | 2 +- backend/ev-document-thumbnails.h | 6 + backend/ev-document.c | 86 +---- backend/ev-document.h | 77 ++-- backend/ev-jobs.c | 8 +- backend/ev-jobs.h | 5 +- backend/ev-link.c | 54 ++- backend/ev-link.h | 18 + backend/ev-page-cache.c | 16 +- configure.ac | 6 +- pdf/Makefile.am | 14 +- pdf/ev-poppler.cc | 592 +++++++++++++++++++++++++++++++ pdf/ev-poppler.h | 39 ++ ps/ps-document.c | 18 +- shell/ev-pixbuf-cache.c | 74 +++- shell/ev-pixbuf-cache.h | 19 +- shell/ev-sidebar-thumbnails.c | 10 +- shell/ev-view.c | 75 +++- shell/ev-window.c | 11 +- 20 files changed, 971 insertions(+), 214 deletions(-) create mode 100644 pdf/ev-poppler.cc create mode 100644 pdf/ev-poppler.h diff --git a/ChangeLog b/ChangeLog index 00b6ceb2..940e8550 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,58 @@ +Thu Mar 31 01:21:58 2005 Jonathan Blandford + + * Makefile.am: Remove pixbuf backend for now + + * configure.ac: Require poppler-glib instead of just poppler. + + * backend/ev-document-thumbnails.h: Add a comment + + * backend/ev-document.h: + * backend/ev-document.c: (ev_document_class_init), + (ev_document_load), (ev_document_get_link), + (ev_document_get_links): Remove 3 methods and add get_links. + Also, made 0 based. + + * backend/ev-jobs.c: (ev_job_render_new), (ev_job_render_run): + * backend/ev-jobs.h: now EvJobRender can grab the links for a document. + + * backend/ev-link.c: (ev_link_set_title), + (ev_link_mapping_free_foreach), (ev_link_mapping_free), + (ev_link_mapping_find): + * backend/ev-link.h: Allow NULL titles. Also, introduce a mapping link. + + * backend/ev-page-cache.c: (ev_page_cache_init), + (_ev_page_cache_new), (ev_page_cache_set_current_page), + (ev_page_cache_get_size), (ev_page_cache_next_page), + (ev_page_cache_prev_page): Fix to be 0 based. + + * pdf/Makefile.am: + * pdf/ev-poppler.h: + * pdf/ev-poppler.cc: New backend. + + * ps/ps-document.c: (ps_document_init), (ps_document_set_page), + (ps_document_get_page), (ps_document_document_iface_init): + + * shell/ev-pixbuf-cache.h: + * shell/ev-pixbuf-cache.c: (ev_pixbuf_cache_init), + (dispose_cache_job_info), (job_finished_cb), (move_one_job), + (ev_pixbuf_cache_update_range), (copy_job_to_job_info), + (add_job_if_needed), (ev_pixbuf_cache_set_page_range), + (ev_pixbuf_cache_get_pixbuf), (ev_pixbuf_cache_get_link_mapping): + Fix up code to grab a page cache per each doc. Also, fix to be 0 + based. + + * shell/ev-sidebar-thumbnails.c: + (ev_sidebar_tree_selection_changed), (page_changed_cb), + (ev_sidebar_thumbnails_set_document): Fix to be 0 based. + + * shell/ev-view.c: (status_message_from_link), + (find_page_at_location), (get_link_at_location), + (ev_view_motion_notify_event), (ev_view_button_release_event), + (ev_view_init): Use the new link code. Fix to be 0 based. + + * shell/ev-window.c: (update_action_sensitivity), + (document_supports_sidebar): 0 based. + Fri Mar 25 16:55:58 2005 Jonathan Blandford * pdf/pdf-document.cc: Patch from Fernando Herrera diff --git a/Makefile.am b/Makefile.am index 41d8abdd..155dac80 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = lib cut-n-paste data backend po pdf ps pixbuf shell thumbnailer +SUBDIRS = lib cut-n-paste data backend po pdf ps shell thumbnailer intltool_extra = intltool-extract.in intltool-merge.in intltool-update.in diff --git a/backend/ev-document-thumbnails.h b/backend/ev-document-thumbnails.h index 76b0cc8c..c84e4268 100644 --- a/backend/ev-document-thumbnails.h +++ b/backend/ev-document-thumbnails.h @@ -52,6 +52,12 @@ struct _EvDocumentThumbnailsIface }; GType ev_document_thumbnails_get_type (void); + +/* FIXME: This is a little bit busted. We call get_thumbnail w/ a suggested + * width, but we should call it with a scale so that different sized pages get + * sized proportionally. + */ + GdkPixbuf *ev_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document, gint page, gint size, diff --git a/backend/ev-document.c b/backend/ev-document.c index 6238ac54..080af0bd 100644 --- a/backend/ev-document.c +++ b/backend/ev-document.c @@ -27,17 +27,9 @@ static void ev_document_class_init (gpointer g_class); -enum -{ - PAGE_CHANGED, - SCALE_CHANGED, - LAST_SIGNAL -}; -static guint signals[LAST_SIGNAL] = { 0 }; GMutex *ev_doc_mutex = NULL; - #define LOG(x) GType ev_document_get_type (void) @@ -75,26 +67,6 @@ ev_document_error_quark (void) static void ev_document_class_init (gpointer g_class) { - signals[PAGE_CHANGED] = - g_signal_new ("page_changed", - EV_TYPE_DOCUMENT, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EvDocumentIface, page_changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - signals[SCALE_CHANGED] = - g_signal_new ("scale_changed", - EV_TYPE_DOCUMENT, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EvDocumentIface, scale_changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - g_object_interface_install_property (g_class, g_param_spec_string ("title", "Document Title", @@ -140,8 +112,11 @@ ev_document_load (EvDocument *document, 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); + if (retval) + ev_document_get_page_cache (document); + return retval; } @@ -204,16 +179,6 @@ ev_document_get_page (EvDocument *document) return retval; } -void -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); -} - void ev_document_set_scale (EvDocument *document, double scale) @@ -224,17 +189,6 @@ ev_document_set_scale (EvDocument *document, iface->set_scale (document, scale); } -void -ev_document_set_page_offset (EvDocument *document, - int x, - int y) -{ - EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document); - - LOG ("ev_document_set_page_offset"); - iface->set_page_offset (document, x, y); -} - void ev_document_get_page_size (EvDocument *document, int page, @@ -269,25 +223,29 @@ ev_document_get_link (EvDocument *document, EvLink *retval; LOG ("ev_document_get_link"); + if (iface->get_link == NULL) + return NULL; retval = iface->get_link (document, x, y); return retval; } -void -ev_document_render (EvDocument *document, - int clip_x, - int clip_y, - int clip_width, - int clip_height) +GList * +ev_document_get_links (EvDocument *document) { EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document); + GList *retval; + + LOG ("ev_document_get_link"); + if (iface->get_links == NULL) + return NULL; + retval = iface->get_links (document); - LOG ("ev_document_render"); - iface->render (document, clip_x, clip_y, clip_width, clip_height); + return retval; } + GdkPixbuf * ev_document_render_pixbuf (EvDocument *document) { @@ -302,15 +260,3 @@ ev_document_render_pixbuf (EvDocument *document) return retval; } - -void -ev_document_page_changed (EvDocument *document) -{ - g_signal_emit (G_OBJECT (document), signals[PAGE_CHANGED], 0); -} - -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 be0d1dbf..15b2cc95 100644 --- a/backend/ev-document.h +++ b/backend/ev-document.h @@ -73,13 +73,8 @@ struct _EvDocumentIface void (* set_page) (EvDocument *document, int page); int (* get_page) (EvDocument *document); - void (* set_target) (EvDocument *document, - GdkDrawable *target); void (* set_scale) (EvDocument *document, double scale); - void (* set_page_offset) (EvDocument *document, - int x, - int y); void (* get_page_size) (EvDocument *document, int page, int *width, @@ -89,15 +84,8 @@ struct _EvDocumentIface EvLink * (* get_link) (EvDocument *document, int x, int y); - void (* render) (EvDocument *document, - int clip_x, - int clip_y, - int clip_width, - int clip_height); - GdkPixbuf *(* render_pixbuf) (EvDocument *document); - - - + GList * (* get_links) (EvDocument *document); + GdkPixbuf * (* render_pixbuf) (EvDocument *document); }; GType ev_document_get_type (void); @@ -106,42 +94,31 @@ EvPageCache *ev_document_get_page_cache (EvDocument *document); GMutex *ev_document_get_doc_mutex (void); -gboolean ev_document_load (EvDocument *document, - const char *uri, - GError **error); -gboolean ev_document_save (EvDocument *document, - const char *uri, - GError **error); -char *ev_document_get_title (EvDocument *document); -int ev_document_get_n_pages (EvDocument *document); -void ev_document_set_page (EvDocument *document, - int page); -int ev_document_get_page (EvDocument *document); -void ev_document_set_target (EvDocument *document, - GdkDrawable *target); -void ev_document_set_scale (EvDocument *document, - double scale); -void ev_document_set_page_offset (EvDocument *document, - int x, - int y); -void ev_document_get_page_size (EvDocument *document, - int page, - int *width, - int *height); -char *ev_document_get_text (EvDocument *document, - GdkRectangle *rect); -EvLink *ev_document_get_link (EvDocument *document, - int x, - int y); -void ev_document_render (EvDocument *document, - int clip_x, - 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); +gboolean ev_document_load (EvDocument *document, + const char *uri, + GError **error); +gboolean ev_document_save (EvDocument *document, + const char *uri, + GError **error); +char *ev_document_get_title (EvDocument *document); +int ev_document_get_n_pages (EvDocument *document); +void ev_document_set_page (EvDocument *document, + int page); +int ev_document_get_page (EvDocument *document); +void ev_document_set_scale (EvDocument *document, + double scale); +void ev_document_get_page_size (EvDocument *document, + int page, + int *width, + int *height); +char *ev_document_get_text (EvDocument *document, + GdkRectangle *rect); +EvLink *ev_document_get_link (EvDocument *document, + int x, + int y); +GList *ev_document_get_links (EvDocument *document); +GdkPixbuf *ev_document_render_pixbuf (EvDocument *document); + G_END_DECLS diff --git a/backend/ev-jobs.c b/backend/ev-jobs.c index 355a1037..8265aebd 100644 --- a/backend/ev-jobs.c +++ b/backend/ev-jobs.c @@ -182,7 +182,8 @@ ev_job_render_new (EvDocument *document, gint page, double scale, gint width, - gint height) + gint height, + gboolean include_links) { EvJobRender *job; @@ -193,6 +194,7 @@ ev_job_render_new (EvDocument *document, job->scale = scale; job->target_width = width; job->target_height = height; + job->include_links = include_links; return EV_JOB (job); } @@ -204,9 +206,11 @@ ev_job_render_run (EvJobRender *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); + ev_document_set_scale (EV_JOB (job)->document, job->scale); job->pixbuf = ev_document_render_pixbuf (EV_JOB (job)->document); + if (job->include_links) + job->link_mapping = ev_document_get_links (EV_JOB (job)->document); EV_JOB (job)->finished = TRUE; g_mutex_unlock (EV_DOC_MUTEX); diff --git a/backend/ev-jobs.h b/backend/ev-jobs.h index a212349a..1b64e01d 100644 --- a/backend/ev-jobs.h +++ b/backend/ev-jobs.h @@ -97,6 +97,8 @@ struct _EvJobRender gint target_width; gint target_height; GdkPixbuf *pixbuf; + GList *link_mapping; + gboolean include_links; }; struct _EvJobRenderClass @@ -134,7 +136,8 @@ EvJob *ev_job_render_new (EvDocument *document, gint page, double scale, gint width, - gint height); + gint height, + gboolean include_links); void ev_job_render_run (EvJobRender *thumbnail); /* EvJobThumbnail */ diff --git a/backend/ev-link.c b/backend/ev-link.c index 7e6eb522..7e26a580 100644 --- a/backend/ev-link.c +++ b/backend/ev-link.c @@ -85,13 +85,14 @@ void ev_link_set_title (EvLink* self, const char *title) { g_assert (EV_IS_LINK (self)); - g_assert (title != NULL); if (self->priv->title != NULL) { g_free (self->priv->title); } - - self->priv->title = g_strdup (title); + if (title) + self->priv->title = g_strdup (title); + else + self->priv->title = NULL; g_object_notify (G_OBJECT (self), "title"); } @@ -314,3 +315,50 @@ ev_link_new_external (const char *title, const char *uri) "type", EV_LINK_TYPE_EXTERNAL_URI, NULL)); } + + + +static void +ev_link_mapping_free_foreach (EvLinkMapping *mapping) +{ + g_object_unref (G_OBJECT (mapping->link)); + g_free (mapping); +} + +void +ev_link_mapping_free (GList *link_mapping) +{ + if (link_mapping == NULL) + return; + + g_list_foreach (link_mapping, (GFunc) (ev_link_mapping_free_foreach), NULL); + g_list_free (link_mapping); +} + + +EvLink * +ev_link_mapping_find (GList *link_mapping, + gdouble x, + gdouble y) +{ + GList *list; + EvLink *link = NULL; + int i; + + i = 0; + for (list = link_mapping; list; list = list->next) { + EvLinkMapping *mapping = list->data; + + i++; + if ((x >= mapping->x1) && + (y >= mapping->y1) && + (x <= mapping->x2) && + (y <= mapping->y2)) { + link = mapping->link; + break; + } + } + + return link; +} + diff --git a/backend/ev-link.h b/backend/ev-link.h index d92d428e..b79e2fa4 100644 --- a/backend/ev-link.h +++ b/backend/ev-link.h @@ -37,6 +37,8 @@ typedef struct _EvLinkPrivate EvLinkPrivate; #define EV_TYPE_LINK_TYPE (ev_link_type_get_type ()) + + typedef enum { EV_LINK_TYPE_TITLE, @@ -67,6 +69,22 @@ int ev_link_get_page (EvLink *link); void ev_link_set_page (EvLink *link, int page); +/* Link Mapping stuff */ + +typedef struct _EvLinkMapping EvLinkMapping; +struct _EvLinkMapping +{ + EvLink *link; + gdouble x1; + gdouble y1; + gdouble x2; + gdouble y2; +}; + +void ev_link_mapping_free (GList *link_mapping); +EvLink *ev_link_mapping_find (GList *link_mapping, + gdouble x, + gdouble y); G_END_DECLS #endif /* !EV_LINK_H */ diff --git a/backend/ev-page-cache.c b/backend/ev-page-cache.c index e2771b66..f16ddc55 100644 --- a/backend/ev-page-cache.c +++ b/backend/ev-page-cache.c @@ -48,7 +48,7 @@ G_DEFINE_TYPE (EvPageCache, ev_page_cache, G_TYPE_OBJECT) static void ev_page_cache_init (EvPageCache *page_cache) { - page_cache->current_page = 1; + page_cache->current_page = 0; } static void @@ -102,13 +102,13 @@ _ev_page_cache_new (EvDocument *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++) { + for (i = 0; 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) { + if (i == 0) { page_cache->uniform_width = page_width; page_cache->uniform_height = page_height; } else if (page_cache->uniform && @@ -169,7 +169,7 @@ 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); + g_return_if_fail (page >= 0 || page < page_cache->n_pages); if (page == page_cache->current_page) return; @@ -204,7 +204,7 @@ ev_page_cache_get_size (EvPageCache *page_cache, gint *height) { g_return_if_fail (EV_IS_PAGE_CACHE (page_cache)); - g_return_if_fail (page > 0 && page <= page_cache->n_pages); + g_return_if_fail (page >= 0 && page < page_cache->n_pages); if (page_cache->uniform) { if (width) @@ -214,7 +214,7 @@ ev_page_cache_get_size (EvPageCache *page_cache, } else { EvPageCacheInfo *info; - info = &(page_cache->size_cache [page - 1]); + info = &(page_cache->size_cache [page]); if (width) *width = info->width; @@ -234,7 +234,7 @@ 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) + if (page_cache->current_page > page_cache->n_pages) return FALSE; ev_page_cache_set_current_page (page_cache, page_cache->current_page + 1); @@ -247,7 +247,7 @@ 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) + if (page_cache->current_page <= 0) return FALSE; ev_page_cache_set_current_page (page_cache, page_cache->current_page - 1); diff --git a/configure.ac b/configure.ac index d5c6624c..0d9f5dd3 100644 --- a/configure.ac +++ b/configure.ac @@ -32,12 +32,12 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Gettext package.]) PKG_CHECK_MODULES(LIBEVPRIVATE, gtk+-2.0 >= 2.4.0) PKG_CHECK_MODULES(RECENT_FILES, gtk+-2.0 >= 2.4.0 libgnomeui-2.0 >= 2.4.0) -PKG_CHECK_MODULES(SHELL, gtk+-2.0 >= 2.6.0 libgnomeui-2.0 gnome-vfs-2.0 libgnomeprint-2.2 libgnomeprintui-2.2 libglade-2.0 gconf-2.0 poppler >= 0.1.1) -PKG_CHECK_MODULES(THUMBNAILER, gtk+-2.0 >= 2.6.0 gnome-vfs-2.0 poppler >= 0.1.1) +PKG_CHECK_MODULES(SHELL, gtk+-2.0 >= 2.6.0 libgnomeui-2.0 gnome-vfs-2.0 libgnomeprint-2.2 libgnomeprintui-2.2 libglade-2.0 gconf-2.0 poppler-glib >= 0.1.1) +PKG_CHECK_MODULES(THUMBNAILER, gtk+-2.0 >= 2.6.0 gnome-vfs-2.0 poppler-glib >= 0.1.1) PKG_CHECK_MODULES(DVI, gtk+-2.0 >= 2.6.0) PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.6.0) PKG_CHECK_MODULES(PS, gtk+-2.0 >= 2.6.0 gnome-vfs-2.0 libgnomeui-2.0) -PKG_CHECK_MODULES(POPPLER, poppler >= 0.1.1) +PKG_CHECK_MODULES(POPPLER_GLIB, poppler-glib >= 0.1.2) GLIB_GENMARSHAL=`$PKG_CONFIG --variable=glib_genmarshal glib-2.0` AC_SUBST(GLIB_GENMARSHAL) diff --git a/pdf/Makefile.am b/pdf/Makefile.am index 4604706d..dd7ccc73 100644 --- a/pdf/Makefile.am +++ b/pdf/Makefile.am @@ -1,24 +1,16 @@ INCLUDES = \ -I$(top_srcdir) \ -I$(top_srcdir)/backend \ - $(POPPLER_CFLAGS) \ + $(POPPLER_GLIB_CFLAGS) \ $(GTK_CFLAGS) \ -DDATADIR=\""$(datadir)"\" -noinst_PROGRAMS = test-gdk-output-dev - noinst_LTLIBRARIES = libpdfdocument.la libpdfdocument_la_SOURCES = \ - GDKSplashOutputDev.cc \ - GDKSplashOutputDev.h \ - Thumb.cc \ - Thumb.h \ - pdf-document.cc \ - pdf-document.h + ev-poppler.cc \ + ev-poppler.h -test_gdk_output_dev_SOURCES = \ - test-gdk-output-dev.cc test_gdk_output_dev_LDADD = \ libpdfdocument.la \ diff --git a/pdf/ev-poppler.cc b/pdf/ev-poppler.cc new file mode 100644 index 00000000..6a516727 --- /dev/null +++ b/pdf/ev-poppler.cc @@ -0,0 +1,592 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */ +/* pdfdocument.h: Implementation of EvDocument for PDF + * Copyright (C) 2004, Red Hat, Inc. + * + * This program 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, or (at your option) + * any later version. + * + * This program 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. + */ + +#include +#include +#include +#include + +#include "ev-poppler.h" +#include "ev-ps-exporter.h" +#include "ev-document-find.h" +#include "ev-document-misc.h" +#include "ev-document-links.h" +#include "ev-document-security.h" +#include "ev-document-thumbnails.h" + + +enum { + PROP_0, + PROP_TITLE +}; + + +struct _PdfDocumentClass +{ + GObjectClass parent_class; +}; + +struct _PdfDocument +{ + GObject parent_instance; + + PopplerDocument *document; + PopplerPage *page; + double scale; + gchar *password; +}; + +static void pdf_document_document_iface_init (EvDocumentIface *iface); +static void pdf_document_security_iface_init (EvDocumentSecurityIface *iface); +static void pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface); +static void pdf_document_document_links_iface_init (EvDocumentLinksIface *iface); +static void pdf_document_thumbnails_get_dimensions (EvDocumentThumbnails *document_thumbnails, + gint page, + gint size, + gint *width, + gint *height); +static EvLink * ev_link_from_action (PopplerAction *action); + + +G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT, + { + G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT, + pdf_document_document_iface_init); + G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_SECURITY, + pdf_document_security_iface_init); + G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS, + pdf_document_document_thumbnails_iface_init); + G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_LINKS, + pdf_document_document_links_iface_init); +#if 0 + G_IMPLEMENT_INTERFACE (EV_TYPE_PS_EXPORTER, + pdf_document_ps_exporter_iface_init); + G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FIND, + pdf_document_find_iface_init); +#endif + }); + + + + + + +static void +pdf_document_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (object); + + switch (prop_id) + { + case PROP_TITLE: + if (pdf_document->document == NULL) + g_value_set_string (value, NULL); + else + g_object_get_property (G_OBJECT (pdf_document->document), "title", value); + break; + } +} + +static void +pdf_document_class_init (PdfDocumentClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->get_property = pdf_document_get_property; + + g_object_class_override_property (gobject_class, PROP_TITLE, "title"); +} + +static void +pdf_document_init (PdfDocument *pdf_document) +{ + pdf_document->page = NULL; + pdf_document->scale = 1.0; + pdf_document->password = NULL; +} + +static void +convert_error (GError *poppler_error, + GError **error) +{ + if (poppler_error == NULL) + return; + + if (poppler_error->domain == POPPLER_ERROR) { + /* convert poppler errors into EvDocument errors */ + gint code = EV_DOCUMENT_ERROR_INVALID; + if (poppler_error->code == POPPLER_ERROR_INVALID) + code = EV_DOCUMENT_ERROR_INVALID; + else if (poppler_error->code == POPPLER_ERROR_ENCRYPTED) + code = EV_DOCUMENT_ERROR_ENCRYPTED; + + + g_set_error (error, + EV_DOCUMENT_ERROR, + code, + poppler_error->message, + NULL); + } else { + g_propagate_error (error, poppler_error); + } +} + + +/* EvDocument */ +static gboolean +pdf_document_save (EvDocument *document, + const char *uri, + GError **error) +{ + gboolean retval; + GError *poppler_error = NULL; + + retval = poppler_document_save (PDF_DOCUMENT (document)->document, + uri, + &poppler_error); + if (! retval) + convert_error (poppler_error, error); + + return retval; +} + +static gboolean +pdf_document_load (EvDocument *document, + const char *uri, + GError **error) +{ + GError *poppler_error = NULL; + PdfDocument *pdf_document = PDF_DOCUMENT (document); + + pdf_document->document = + poppler_document_new_from_file (uri, pdf_document->password, &poppler_error); + + if (pdf_document->document == NULL) { + convert_error (poppler_error, error); + return FALSE; + } + + return TRUE; +} + +static int +pdf_document_get_n_pages (EvDocument *document) +{ + return poppler_document_get_n_pages (PDF_DOCUMENT (document)->document); +} + +static void +pdf_document_set_page (EvDocument *document, + int page) +{ + page = CLAMP (page, 0, poppler_document_get_n_pages (PDF_DOCUMENT (document)->document) - 1); + + PDF_DOCUMENT (document)->page = poppler_document_get_page (PDF_DOCUMENT (document)->document, page); +} + +static int +pdf_document_get_page (EvDocument *document) +{ + PdfDocument *pdf_document; + + pdf_document = PDF_DOCUMENT (document); + + if (pdf_document->page) + return poppler_page_get_index (pdf_document->page); + + return 1; +} + +static void +pdf_document_set_scale (EvDocument *document, + double scale) +{ + PDF_DOCUMENT (document)->scale = scale; +} + + +static void +get_size_from_page (PopplerPage *poppler_page, + double scale, + int *width, + int *height) +{ + gdouble width_d, height_d; + poppler_page_get_size (poppler_page, &width_d, &height_d); + if (width) + *width = (int) (width_d * scale); + if (height) + *height = (int) (height_d * scale); + +} + +static void +pdf_document_get_page_size (EvDocument *document, + int page, + int *width, + int *height) +{ + PopplerPage *poppler_page = NULL; + + if (page == -1) + poppler_page = PDF_DOCUMENT (document)->page; + else + poppler_page = poppler_document_get_page (PDF_DOCUMENT (document)->document, + page); + + if (poppler_page == NULL) + poppler_document_get_page (PDF_DOCUMENT (document)->document, 0); + + get_size_from_page (poppler_page, + PDF_DOCUMENT (document)->scale, + width, height); +} + +static GList * +pdf_document_get_links (EvDocument *document) +{ + PdfDocument *pdf_document; + GList *retval = NULL; + GList *mapping_list; + GList *list; + gint height; + + pdf_document = PDF_DOCUMENT (document); + g_return_val_if_fail (pdf_document->page != NULL, NULL); + + mapping_list = poppler_page_get_link_mapping (pdf_document->page); + get_size_from_page (pdf_document->page, 1.0, NULL, &height); + + for (list = mapping_list; list; list = list->next) { + PopplerLinkMapping *link_mapping; + EvLinkMapping *ev_link_mapping; + + link_mapping = (PopplerLinkMapping *)list->data; + ev_link_mapping = g_new (EvLinkMapping, 1); + ev_link_mapping->link = ev_link_from_action (link_mapping->action); + ev_link_mapping->x1 = link_mapping->x1; + ev_link_mapping->x2 = link_mapping->x2; + /* Invert this for X-style coordinates */ + ev_link_mapping->y1 = height - link_mapping->y2; + ev_link_mapping->y2 = height - link_mapping->y1; + + retval = g_list_prepend (retval, ev_link_mapping); + } + + poppler_page_free_link_mapping (mapping_list); + + return g_list_reverse (retval); +} + + +static GdkPixbuf * +pdf_document_render_pixbuf (EvDocument *document) +{ + PdfDocument *pdf_document; + GdkPixbuf *pixbuf; + gint width, height; + + pdf_document = PDF_DOCUMENT (document); + g_return_val_if_fail (pdf_document->page != NULL, NULL); + + get_size_from_page (pdf_document->page, + pdf_document->scale, + &width, &height); + + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, + FALSE, 8, + width, height); + + poppler_page_render_to_pixbuf (pdf_document->page, + 0, 0, + width, height, + pdf_document->scale, + pixbuf, + 0, 0); + + return pixbuf; +} + +/* EvDocumentSecurity */ + +static gboolean +pdf_document_has_document_security (EvDocumentSecurity *document_security) +{ + /* FIXME: do we really need to have this? */ + return FALSE; +} + +static void +pdf_document_set_password (EvDocumentSecurity *document_security, + const char *password) +{ + PdfDocument *document = PDF_DOCUMENT (document_security); + + if (document->password) + g_free (document->password); + + document->password = g_strdup (password); +} + + + +static void +pdf_document_document_iface_init (EvDocumentIface *iface) +{ + iface->save = pdf_document_save; + iface->load = pdf_document_load; + iface->get_n_pages = pdf_document_get_n_pages; + iface->set_page = pdf_document_set_page; + iface->get_page = pdf_document_get_page; + iface->set_scale = pdf_document_set_scale; + iface->get_page_size = pdf_document_get_page_size; + iface->get_links = pdf_document_get_links; + iface->render_pixbuf = pdf_document_render_pixbuf; +}; + +static void +pdf_document_security_iface_init (EvDocumentSecurityIface *iface) +{ + iface->has_document_security = pdf_document_has_document_security; + iface->set_password = pdf_document_set_password; +} + +static gboolean +pdf_document_links_has_document_links (EvDocumentLinks *document_links) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document_links); + PopplerIndexIter *iter; + + g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE); + + iter = poppler_index_iter_new (pdf_document->document); + if (iter == NULL) + return FALSE; + poppler_index_iter_free (iter); + + return TRUE; +} + +static EvLink * +ev_link_from_action (PopplerAction *action) +{ + EvLink *link; + const char *title; + + title = action->any.title; + + if (action->type == POPPLER_ACTION_GOTO_DEST) { + link = ev_link_new_page (title, action->goto_dest.dest->page_num - 1); + } else if (action->type == POPPLER_ACTION_URI) { + link = ev_link_new_external (title, action->uri.uri); + } else { + link = ev_link_new_title (title); + } + + return link; +} + + +static void +build_tree (PdfDocument *pdf_document, + GtkTreeModel *model, + GtkTreeIter *parent, + PopplerIndexIter *iter) +{ + + do { + GtkTreeIter tree_iter; + PopplerIndexIter *child; + PopplerAction *action; + EvLink *link; + + action = poppler_index_iter_get_action (iter); + if (action) { + gtk_tree_store_append (GTK_TREE_STORE (model), &tree_iter, parent); + link = ev_link_from_action (action); + poppler_action_free (action); + + gtk_tree_store_set (GTK_TREE_STORE (model), &tree_iter, + EV_DOCUMENT_LINKS_COLUMN_MARKUP, ev_link_get_title (link), + EV_DOCUMENT_LINKS_COLUMN_LINK, link, + -1); + child = poppler_index_iter_get_child (iter); + if (child) + build_tree (pdf_document, model, &tree_iter, child); + poppler_index_iter_free (child); + } + } while (poppler_index_iter_next (iter)); +} + + +static GtkTreeModel * +pdf_document_links_get_links_model (EvDocumentLinks *document_links) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document_links); + GtkTreeModel *model = NULL; + PopplerIndexIter *iter; + + g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), NULL); + + iter = poppler_index_iter_new (pdf_document->document); + /* Create the model iff we have items*/ + if (iter != NULL) { + model = (GtkTreeModel *) gtk_tree_store_new (EV_DOCUMENT_LINKS_COLUMN_NUM_COLUMNS, + G_TYPE_STRING, + G_TYPE_POINTER); + build_tree (pdf_document, model, NULL, iter); + poppler_index_iter_free (iter); + } + + + return model; +} + + +static void +pdf_document_document_links_iface_init (EvDocumentLinksIface *iface) +{ + iface->has_document_links = pdf_document_links_has_document_links; + iface->get_links_model = pdf_document_links_get_links_model; +} + + +static GdkPixbuf * +make_thumbnail_for_size (PdfDocument *pdf_document, + gint page, + gint size, + gboolean border) +{ + PopplerPage *poppler_page; + GdkPixbuf *pixbuf; + int width, height; + int x_offset, y_offset; + double scale; + gdouble unscaled_width, unscaled_height; + + poppler_page = poppler_document_get_page (pdf_document->document, page); + + g_return_val_if_fail (poppler_page != NULL, NULL); + + pdf_document_thumbnails_get_dimensions (EV_DOCUMENT_THUMBNAILS (pdf_document), page, size, &width, &height); + poppler_page_get_size (poppler_page, &unscaled_width, &unscaled_height); + scale = width / unscaled_width; + + if (border) { + pixbuf = ev_document_misc_get_thumbnail_frame (width, height, NULL); + x_offset = 1; + y_offset = 1; + } else { + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, + width, height); + gdk_pixbuf_fill (pixbuf, 0xffffffff); + x_offset = 0; + y_offset = 0; + } + + poppler_page_render_to_pixbuf (poppler_page, 0, 0, + width, height, + scale, pixbuf, + x_offset, y_offset); + + return pixbuf; +} + +static GdkPixbuf * +pdf_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document_thumbnails, + gint page, + gint size, + gboolean border) +{ + PdfDocument *pdf_document; + PopplerPage *poppler_page; + GdkPixbuf *pixbuf; + + pdf_document = PDF_DOCUMENT (document_thumbnails); + + poppler_page = poppler_document_get_page (pdf_document->document, page); + g_return_val_if_fail (poppler_page != NULL, NULL); + + pixbuf = poppler_page_get_thumbnail (poppler_page); + if (pixbuf != NULL) { + /* The document provides its own thumbnails. */ + if (border) { + GdkPixbuf *real_pixbuf; + + real_pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, pixbuf); + g_object_unref (pixbuf); + pixbuf = real_pixbuf; + } + } else { + /* There is no provided thumbnail. We need to make one. */ + pixbuf = make_thumbnail_for_size (pdf_document, page, size, border); + } + return pixbuf; +} + +static void +pdf_document_thumbnails_get_dimensions (EvDocumentThumbnails *document_thumbnails, + gint page, + gint size, + gint *width, + gint *height) +{ + PdfDocument *pdf_document; + PopplerPage *poppler_page; + gint has_thumb; + + pdf_document = PDF_DOCUMENT (document_thumbnails); + poppler_page = poppler_document_get_page (pdf_document->document, page); + + g_return_if_fail (width != NULL); + g_return_if_fail (height != NULL); + g_return_if_fail (poppler_page != NULL); + + has_thumb = poppler_page_get_thumbnail_size (poppler_page, width, height); + + if (!has_thumb) { + int page_width, page_height; + + get_size_from_page (poppler_page, 1.0, &page_width, &page_height); + + if (page_width > page_height) { + *width = size; + *height = (int) (size * page_height / page_width); + } else { + *width = (int) (size * page_width / page_height); + *height = size; + } + } +} + +static void +pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface) +{ + iface->get_thumbnail = pdf_document_thumbnails_get_thumbnail; + iface->get_dimensions = pdf_document_thumbnails_get_dimensions; +} + +PdfDocument * +pdf_document_new (void) +{ + return PDF_DOCUMENT (g_object_new (PDF_TYPE_DOCUMENT, NULL)); +} diff --git a/pdf/ev-poppler.h b/pdf/ev-poppler.h new file mode 100644 index 00000000..8cc65d12 --- /dev/null +++ b/pdf/ev-poppler.h @@ -0,0 +1,39 @@ +/* pdfdocument.h: Implementation of EvDocument for PDF + * Copyright (C) 2004, Red Hat, Inc. + * + * This program 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, or (at your option) + * any later version. + * + * This program 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 __PDF_DOCUMENT_H__ +#define __PDF_DOCUMENT_H__ + +#include "ev-document.h" + +G_BEGIN_DECLS + +#define PDF_TYPE_DOCUMENT (pdf_document_get_type ()) +#define PDF_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PDF_TYPE_DOCUMENT, PdfDocument)) +#define PDF_IS_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PDF_TYPE_DOCUMENT)) + +typedef struct _PdfDocument PdfDocument; +typedef struct _PdfDocumentClass PdfDocumentClass; + +PdfDocument *pdf_document_new (void); +GType pdf_document_get_type (void) G_GNUC_CONST; + + +G_END_DECLS + +#endif /* __PDF_DOCUMENT_H__ */ diff --git a/ps/ps-document.c b/ps/ps-document.c index 4dd344be..4b2d4c43 100644 --- a/ps/ps-document.c +++ b/ps/ps-document.c @@ -137,8 +137,6 @@ ps_document_init (PSDocument *gs) gs->bytes_left = 0; gs->buffer_bytes_left = 0; - gs->page_x_offset = 0; - gs->page_y_offset = 0; gs->zoom_factor = 1.0; gs->gs_status = _("No document loaded."); @@ -1208,7 +1206,7 @@ ps_document_set_page (EvDocument *document, LOG ("Set document page %d\n", page); - gs->current_page = page - 1; + gs->current_page = page; compute_dimensions (gs, page); } @@ -1219,7 +1217,7 @@ ps_document_get_page (EvDocument *document) g_return_val_if_fail (ps != NULL, -1); - return ps->current_page + 1; + return ps->current_page; } static void @@ -1232,17 +1230,6 @@ ps_document_set_scale (EvDocument *document, compute_dimensions (gs, gs->current_page); } -static void -ps_document_set_page_offset (EvDocument *document, - int x, - int y) -{ - PSDocument *gs = PS_DOCUMENT (document); - - gs->page_x_offset = x; - gs->page_y_offset = y; -} - static void ps_document_get_page_size (EvDocument *document, int page, @@ -1338,7 +1325,6 @@ ps_document_document_iface_init (EvDocumentIface *iface) iface->set_page = ps_document_set_page; iface->get_page = ps_document_get_page; iface->set_scale = ps_document_set_scale; - iface->set_page_offset = ps_document_set_page_offset; iface->get_page_size = ps_document_get_page_size; iface->render_pixbuf = ps_document_render_pixbuf; } diff --git a/shell/ev-pixbuf-cache.c b/shell/ev-pixbuf-cache.c index 7d076dba..7200b37c 100644 --- a/shell/ev-pixbuf-cache.c +++ b/shell/ev-pixbuf-cache.c @@ -6,6 +6,7 @@ typedef struct _CacheJobInfo { EvJob *job; GdkPixbuf *pixbuf; + GList *link_mapping; } CacheJobInfo; struct _EvPixbufCache @@ -50,14 +51,16 @@ static void job_finished_cb (EvJob *job, EvPixbufCache *pixbuf_cache); static CacheJobInfo *find_job_cache (EvPixbufCache *pixbuf_cache, int page); - +static void copy_job_to_job_info (EvJobRender *job_render, + CacheJobInfo *job_info, + EvPixbufCache *pixbuf_cache); /* 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)) + (MIN(pixbuf_cache->preload_cache_size, ev_page_cache_get_n_pages (page_cache) - (1 + pixbuf_cache->end_page))) #define PAGE_CACHE_LEN(pixbuf_cache) \ ((pixbuf_cache->end_page - pixbuf_cache->start_page) + 1) @@ -66,8 +69,8 @@ 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->start_page = 0; + pixbuf_cache->end_page = 0; pixbuf_cache->job_list = g_new0 (CacheJobInfo, PAGE_CACHE_LEN (pixbuf_cache)); pixbuf_cache->preload_cache_size = 1; @@ -123,6 +126,10 @@ dispose_cache_job_info (CacheJobInfo *job_info, g_object_unref (G_OBJECT (job_info->pixbuf)); job_info->pixbuf = NULL; } + if (job_info->link_mapping) { + ev_link_mapping_free (job_info->link_mapping); + job_info->link_mapping = NULL; + } } static void @@ -177,6 +184,12 @@ job_finished_cb (EvJob *job, g_object_unref (job_info->pixbuf); job_info->pixbuf = pixbuf; + if (job_render->link_mapping) { + if (job_info->link_mapping) + ev_link_mapping_free (job_info->link_mapping); + job_info->link_mapping = job_render->link_mapping; + } + if (job_info->job == job) job_info->job = NULL; g_object_unref (job); @@ -268,6 +281,7 @@ move_one_job (CacheJobInfo *job_info, *target_page = *job_info; job_info->job = NULL; job_info->pixbuf = NULL; + job_info->link_mapping = NULL; if (new_priority != priority && target_page->job) { g_print ("FIXME: update priority \n"); @@ -303,7 +317,7 @@ ev_pixbuf_cache_update_range (EvPixbufCache *pixbuf_cache, /* 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) { + if (page < 0) { dispose_cache_job_info (pixbuf_cache->prev_job + i, pixbuf_cache); } else { move_one_job (pixbuf_cache->prev_job + i, @@ -324,7 +338,7 @@ ev_pixbuf_cache_update_range (EvPixbufCache *pixbuf_cache, } for (i = 0; i < pixbuf_cache->preload_cache_size; i++) { - if (page > ev_page_cache_get_n_pages (page_cache)) { + 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, @@ -347,6 +361,22 @@ ev_pixbuf_cache_update_range (EvPixbufCache *pixbuf_cache, pixbuf_cache->end_page = end_page; } +static void +copy_job_to_job_info (EvJobRender *job_render, + CacheJobInfo *job_info, + EvPixbufCache *pixbuf_cache) +{ + GdkPixbuf *pixbuf; + + pixbuf = g_object_ref (job_render->pixbuf); + + dispose_cache_job_info (job_info, pixbuf_cache); + + job_info->pixbuf = pixbuf; + if (job_render->link_mapping) + job_info->link_mapping = job_render->link_mapping; +} + static CacheJobInfo * find_job_cache (EvPixbufCache *pixbuf_cache, int page) @@ -426,7 +456,8 @@ add_job_if_needed (EvPixbufCache *pixbuf_cache, /* make a new job now */ job_info->job = ev_job_render_new (pixbuf_cache->document, page, scale, - width, height); + width, height, + (job_info->link_mapping == NULL)?TRUE:FALSE); ev_job_queue_add_job (job_info->job, priority); g_signal_connect (job_info->job, "finished", G_CALLBACK (job_finished_cb), pixbuf_cache); } @@ -484,8 +515,8 @@ ev_pixbuf_cache_set_page_range (EvPixbufCache *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 (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 @@ -514,12 +545,27 @@ ev_pixbuf_cache_get_pixbuf (EvPixbufCache *pixbuf_cache, /* 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; + copy_job_to_job_info (EV_JOB_RENDER (job_info->job), job_info, pixbuf_cache); } return job_info->pixbuf; } + +GList * +ev_pixbuf_cache_get_link_mapping (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) { + copy_job_to_job_info (EV_JOB_RENDER (job_info->job), job_info, pixbuf_cache); + } + + return job_info->link_mapping; +} diff --git a/shell/ev-pixbuf-cache.h b/shell/ev-pixbuf-cache.h index e49faa02..0bd1cbc7 100644 --- a/shell/ev-pixbuf-cache.h +++ b/shell/ev-pixbuf-cache.h @@ -37,14 +37,17 @@ G_BEGIN_DECLS 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); +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); +GList *ev_pixbuf_cache_get_link_mapping (EvPixbufCache *pixbuf_cache, + gint page); + G_END_DECLS diff --git a/shell/ev-sidebar-thumbnails.c b/shell/ev-sidebar-thumbnails.c index c548e297..7bbaa098 100644 --- a/shell/ev-sidebar-thumbnails.c +++ b/shell/ev-sidebar-thumbnails.c @@ -118,7 +118,7 @@ ev_sidebar_tree_selection_changed (GtkTreeSelection *selection, path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->list_store), &iter); - page = gtk_tree_path_get_indices (path)[0] + 1; + page = gtk_tree_path_get_indices (path)[0]; gtk_tree_path_free (path); page_cache = ev_document_get_page_cache (priv->document); @@ -189,7 +189,7 @@ page_changed_cb (EvPageCache *page_cache, GtkTreePath *path; GtkTreeSelection *selection; - path = gtk_tree_path_new_from_indices (page - 1, -1); + path = gtk_tree_path_new_from_indices (page, -1); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (sidebar->priv->tree_view)); @@ -247,12 +247,12 @@ ev_sidebar_thumbnails_set_document (EvSidebarThumbnails *sidebar_thumbnails, 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++) { + for (i = 0; i < n_pages; i++) { EvJob *job; /* FIXME: Bah. This is still -1 for some reason. Need to track it down.. */ - job = ev_job_thumbnail_new (priv->document, i - 1, THUMBNAIL_WIDTH); - page = g_strdup_printf ("%d", i); + job = ev_job_thumbnail_new (priv->document, i, THUMBNAIL_WIDTH); + page = g_strdup_printf ("%d", i + 1); /* FIXME: replace with string. */ gtk_list_store_append (priv->list_store, &iter); gtk_list_store_set (priv->list_store, &iter, COLUMN_PAGE_STRING, page, diff --git a/shell/ev-view.c b/shell/ev-view.c index 9921ed45..97e0c549 100644 --- a/shell/ev-view.c +++ b/shell/ev-view.c @@ -704,14 +704,15 @@ static char * status_message_from_link (EvLink *link) { EvLinkType type; - char *msg; + char *msg = NULL; int page; type = ev_link_get_link_type (link); switch (type) { case EV_LINK_TYPE_TITLE: - msg = g_strdup (ev_link_get_title (link)); + if (ev_link_get_title (link)) + msg = g_strdup (ev_link_get_title (link)); break; case EV_LINK_TYPE_PAGE: page = ev_link_get_page (link); @@ -721,7 +722,7 @@ status_message_from_link (EvLink *link) msg = g_strdup (ev_link_get_uri (link)); break; default: - msg = NULL; + break; } return msg; @@ -799,6 +800,56 @@ ev_view_set_cursor (EvView *view, EvViewCursor new_cursor) } } + +static void +find_page_at_location (EvView *view, + gdouble x, + gdouble y, + gint *page, + gint *x_offset, + gint *y_offset) +{ + GtkBorder border; + gint 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 -= (border.left + view->spacing); + y -= (border.top + view->spacing); + + if ((x < 0) || (y < 0) || + (x >= width) || (y >= height)) { + *page = -1; + return; + } + *page = view->current_page; + *x_offset = (gint) x; + *y_offset = (gint) y; +} + +static EvLink * +get_link_at_location (EvView *view, + gdouble x, + gdouble y) +{ + gint page; + gint x_offset, y_offset; + GList *link_mapping; + + find_page_at_location (view, x, y, &page, &x_offset, &y_offset); + if (page == -1) + return NULL; + + link_mapping = ev_pixbuf_cache_get_link_mapping (view->pixbuf_cache, page); + + return ev_link_mapping_find (link_mapping, x_offset /view->scale, y_offset /view->scale); +} + + static gboolean ev_view_motion_notify_event (GtkWidget *widget, GdkEventMotion *event) @@ -816,13 +867,10 @@ ev_view_motion_notify_event (GtkWidget *widget, view_rect_to_doc_rect (view, &selection, &view->selection); gtk_widget_queue_draw (widget); - } else if (FALSE && view->document) { + } 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); - + link = get_link_at_location (view, event->x, event->y); if (link) { char *msg; @@ -830,8 +878,6 @@ ev_view_motion_notify_event (GtkWidget *widget, ev_view_set_status (view, msg); ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK); g_free (msg); - - g_object_unref (link); } else { ev_view_set_status (view, NULL); if (view->cursor == EV_VIEW_CURSOR_LINK) { @@ -856,14 +902,9 @@ 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); + link = get_link_at_location (view, event->x, event->y); if (link) { ev_view_go_to_link (view, link); - g_object_unref (link); } } @@ -1089,7 +1130,7 @@ ev_view_init (EvView *view) view->spacing = 10; view->scale = 1.0; - view->current_page = 1; + view->current_page = 0; view->pressed_button = -1; view->cursor = EV_VIEW_CURSOR_NORMAL; } diff --git a/shell/ev-window.c b/shell/ev-window.c index 849adaf1..8b3044f1 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -202,10 +202,10 @@ update_action_sensitivity (EvWindow *ev_window) 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); - set_action_sensitive (ev_window, "GoFirstPage", page > 1); - set_action_sensitive (ev_window, "GoLastPage", page < n_pages); + set_action_sensitive (ev_window, "GoPreviousPage", page > 0); + set_action_sensitive (ev_window, "GoNextPage", page < n_pages - 1); + set_action_sensitive (ev_window, "GoFirstPage", page > 0); + set_action_sensitive (ev_window, "GoLastPage", page < n_pages - 1); } else { set_action_sensitive (ev_window, "GoFirstPage", FALSE); set_action_sensitive (ev_window, "GoPreviousPage", FALSE); @@ -495,7 +495,8 @@ update_total_pages (EvWindow *ev_window) static gboolean document_supports_sidebar (EvDocument *document) { - return (EV_IS_DOCUMENT_THUMBNAILS (document) && EV_IS_DOCUMENT_LINKS (document)); + /* FIXME: Remove the (TRUE ||) after links are fixed in poppler-glib */ + return (EV_IS_DOCUMENT_THUMBNAILS (document) && (EV_IS_DOCUMENT_LINKS (document))); } static void -- 2.43.5