]> www.fi.muni.cz Git - evince.git/commitdiff
merge evince-threads branch
authorMarco Pesenti Gritti <marco@src.gnome.org>
Wed, 23 Mar 2005 11:07:32 +0000 (11:07 +0000)
committerMarco Pesenti Gritti <marco@src.gnome.org>
Wed, 23 Mar 2005 11:07:32 +0000 (11:07 +0000)
32 files changed:
ChangeLog
TODO
backend/Makefile.am
backend/ev-document-links.c
backend/ev-document-links.h
backend/ev-document.c
backend/ev-document.h
backend/ev-job-queue.c [new file with mode: 0644]
backend/ev-job-queue.h [new file with mode: 0644]
backend/ev-jobs.c [new file with mode: 0644]
backend/ev-jobs.h [new file with mode: 0644]
backend/ev-link.c
backend/ev-link.h
backend/ev-page-cache.c [new file with mode: 0644]
backend/ev-page-cache.h [new file with mode: 0644]
pdf/pdf-document.cc
ps/gsdefaults.c
ps/gsdefaults.h
ps/ps-document.c
ps/ps-document.h
shell/Makefile.am
shell/ev-pixbuf-cache.c [new file with mode: 0644]
shell/ev-pixbuf-cache.h [new file with mode: 0644]
shell/ev-print-job.c
shell/ev-sidebar-links.c
shell/ev-sidebar-thumbnails.c
shell/ev-sidebar-thumbnails.h
shell/ev-sidebar.c
shell/ev-view.c
shell/ev-view.h
shell/ev-window.c
shell/main.c

index b09c962b594e03b1d0c82a1e185f1c8aa1e56f25..c4eada246a9a77fd8040313e1c1b652925318e17 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,112 @@
+2005-03-23  Marco Pesenti Gritti <marco@gnome.org>
+
+       * TODO:
+       * backend/Makefile.am:
+       * backend/ev-document-links.c:
+       (ev_document_links_has_document_links),
+       (ev_document_links_get_links_model):
+       * backend/ev-document-links.h:
+       * backend/ev-document.c: (ev_document_get_page_cache),
+       (ev_document_get_doc_mutex), (ev_document_load),
+       (ev_document_save), (ev_document_get_title),
+       (ev_document_get_n_pages), (ev_document_set_page),
+       (ev_document_get_page), (ev_document_set_target),
+       (ev_document_set_scale), (ev_document_set_page_offset),
+       (ev_document_get_page_size), (ev_document_get_text),
+       (ev_document_get_link), (ev_document_render),
+       (ev_document_render_pixbuf), (ev_document_scale_changed):
+       * backend/ev-document.h:
+       * backend/ev-job-queue.c: (remove_object_from_queue),
+       (notify_finished), (handle_job), (search_for_jobs_unlocked),
+       (no_jobs_available_unlocked), (ev_render_thread),
+       (ev_job_queue_init), (find_queue), (ev_job_queue_add_job),
+       (ev_job_queue_remove_job):
+       * backend/ev-job-queue.h:
+       * backend/ev-jobs.c: (ev_job_init), (ev_job_dispose),
+       (ev_job_class_init), (ev_job_links_init), (ev_job_links_dispose),
+       (ev_job_links_class_init), (ev_job_render_init),
+       (ev_job_render_dispose), (ev_job_render_class_init),
+       (ev_job_thumbnail_init), (ev_job_thumbnail_dispose),
+       (ev_job_thumbnail_class_init), (ev_job_finished),
+       (ev_job_links_new), (ev_job_links_run), (ev_job_render_new),
+       (ev_job_render_run), (ev_job_thumbnail_new),
+       (ev_job_thumbnail_run):
+       * backend/ev-jobs.h:
+       * backend/ev-link.c:
+       * backend/ev-link.h:
+       * backend/ev-page-cache.c: (ev_page_cache_init),
+       (ev_page_cache_class_init), (ev_page_cache_finalize),
+       (_ev_page_cache_new), (ev_page_cache_get_n_pages),
+       (ev_page_cache_get_current_page), (ev_page_cache_set_current_page),
+       (ev_page_cache_set_link), (ev_page_cache_get_title),
+       (ev_page_cache_get_size), (ev_page_cache_next_page),
+       (ev_page_cache_prev_page):
+       * backend/ev-page-cache.h:
+       * pdf/pdf-document.cc:
+       * ps/gsdefaults.c:
+       * ps/gsdefaults.h:
+       * ps/ps-document.c: (ps_document_init), (ps_document_class_init),
+       (push_pixbuf), (interpreter_failed), (ps_document_cleanup),
+       (ps_document_widget_event), (ps_document_finalize), (get_xdpi),
+       (get_ydpi), (setup_pixmap), (setup_page), (close_pipe),
+       (is_interpreter_ready), (output), (catchPipe), (input),
+       (start_interpreter), (check_filecompressed), (compute_dimensions),
+       (ps_document_enable_interpreter), (document_load),
+       (ps_document_next_page), (render_page), (ps_document_set_page),
+       (ps_document_set_scale), (render_pixbuf_idle),
+       (ps_document_render_pixbuf), (ps_document_document_iface_init):
+       * ps/ps-document.h:
+       * shell/Makefile.am:
+       * shell/ev-pixbuf-cache.c: (ev_pixbuf_cache_init),
+       (ev_pixbuf_cache_class_init), (ev_pixbuf_cache_finalize),
+       (dispose_cache_job_info), (ev_pixbuf_cache_dispose),
+       (ev_pixbuf_cache_new), (job_finished_cb),
+       (check_job_size_and_unref), (move_one_job),
+       (ev_pixbuf_cache_update_range), (find_job_cache),
+       (ev_pixbuf_cache_clear_job_sizes), (add_job_if_needed),
+       (ev_pixbuf_cache_add_jobs_if_needed),
+       (ev_pixbuf_cache_set_page_range), (ev_pixbuf_cache_get_pixbuf):
+       * shell/ev-pixbuf-cache.h:
+       * shell/ev-print-job.c: (ev_print_job_use_print_dialog_settings),
+       (idle_print_handler):
+       * shell/ev-sidebar-links.c: (ev_sidebar_links_destroy),
+       (selection_changed_cb), (create_loading_model),
+       (ev_sidebar_links_construct), (links_page_num_func),
+       (ev_sidebar_links_clear_document), (update_page_callback_foreach),
+       (update_page_callback), (job_finished_cb),
+       (ev_sidebar_links_set_document):
+       * shell/ev-sidebar-thumbnails.c:
+       (ev_sidebar_thumbnails_class_init), (adjustment_changed_cb),
+       (ev_sidebar_tree_selection_changed), (ev_sidebar_thumbnails_init),
+       (page_changed_cb), (thumbnail_job_completed_callback),
+       (ev_sidebar_thumbnails_set_document):
+       * shell/ev-sidebar-thumbnails.h:
+       * shell/ev-sidebar.c: (ev_sidebar_set_document):
+       * shell/ev-view.c: (ev_view_finalize), (ev_view_destroy),
+       (ev_view_get_offsets), (ev_view_size_request), (ev_view_realize),
+       (ev_view_unrealize), (highlight_find_results), (expose_bin_window),
+       (ev_view_select_all), (ev_view_copy), (ev_view_primary_get_cb),
+       (ev_view_create_invisible_cursor), (ev_view_motion_notify_event),
+       (ev_view_button_release_event), (ev_view_scroll_view),
+       (ev_view_class_init), (ev_view_init), (update_find_status_message),
+       (jump_to_find_result), (jump_to_find_page), (find_changed_cb),
+       (ev_view_new), (job_finished_cb), (page_changed_cb),
+       (ev_view_set_document), (go_to_link), (ev_view_zoom),
+       (size_to_zoom_factor), (ev_view_set_size), (ev_view_find_next),
+       (ev_view_find_previous):
+       * shell/ev-view.h:
+       * shell/ev-window.c: (update_action_sensitivity),
+       (ev_window_open_page), (update_window_title), (update_total_pages),
+       (page_changed_cb), (ev_window_setup_document),
+       (password_dialog_response), (ev_window_cmd_save_as),
+       (ev_window_print), (ev_window_cmd_go_previous_page),
+       (ev_window_cmd_go_next_page), (ev_window_cmd_go_first_page),
+       (ev_window_cmd_go_last_page), (ev_window_cmd_view_reload),
+       (find_bar_search_changed_cb), (goto_page_cb), (ev_window_init):
+       * shell/main.c: (main):
+
+       Merge evince-threads branch
+
 2005-03-16  Žygimantas Beručka  <uid0@akl.lt>
 
        * configure.ac: Added "lt" to ALL_LINGUAS.
diff --git a/TODO b/TODO
index 73d4b0d2774841ce5be28c6876e67518235c0754..afe2a0f8a4b4bcf88dd4ea6025c934bd4de14abf 100644 (file)
--- a/TODO
+++ b/TODO
@@ -12,17 +12,13 @@ Move to three page views:
 
 Sidebar improvements for ps/pixbuf, or PDF files without a TOC.                bug 164811
 
-Improve look of combobox Thumbnails/Index                              bug 166683
-
 Improve Printing Support: (libgnomeprintui?)
 
- * Print Page Selection
+ * Print Page Selection                                                        bug 169099
  * Print Page Layout                                                   bug 166564
 
 Document Properties Dialog for document meta-data                      bug 164843
 
-Provide Desktop icon Thumbnailer for Documents                         bug 163789
-
 Make an object that handles the page count.
 
 Move to having three sizing types:
@@ -41,3 +37,5 @@ Encrypted PDF support
 Improve Find system
        Find Next/Previous don't go to other pages
        Find Next/Previous doesn't focus the results
+Improve look of combobox Thumbnails/Index                              bug 166683
+Provide Desktop icon Thumbnailer for Documents                         bug 163789
index 90303332880c1531f38fae1574ebff184ca39b40..be844588d3ea92d05cde6bf0c3aee1ddff946784 100644 (file)
@@ -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                      \
index 242efb61c5e330c791e1723cc918cef0a50b8c5d..d9baae0322d9e9171e979ac5eefb954c54a29cc7 100644 (file)
@@ -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;
 }
index 59e638b24ca9f99bf90022047215d0f68851700d..6105a704ab79c7c760e79768426afc21c196d230 100644 (file)
@@ -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
 
index 51099692635da14e8afd04cecbc70510c11703e6..6238ac54b93d01f6e8d0b0c31adfb303f5ca3150 100644 (file)
@@ -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);
-}                  
+}
index b54a0b9f9e7e32d6969805084aa7d39c26873f15..be0d1dbfedb70d2e6e912e9f674f79d5b2a51b8b 100644 (file)
@@ -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 (file)
index 0000000..4bd824f
--- /dev/null
@@ -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 (file)
index 0000000..ec93389
--- /dev/null
@@ -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 (file)
index 0000000..355a103
--- /dev/null
@@ -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 (file)
index 0000000..a212349
--- /dev/null
@@ -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__ */
index e01aa1994faac78f5c6dc2c833547844842f702b..7e6eb52251c42dfbaaa53024210ddf29fa3e71c4 100644 (file)
@@ -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;
index 00d97c43bcb640d2eb0b78be6011b40381b55f24..d92d428e186223a94dbf6c319c30e3eed9f17dff 100644 (file)
@@ -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 (file)
index 0000000..e2771b6
--- /dev/null
@@ -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 (file)
index 0000000..9edf67c
--- /dev/null
@@ -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__ */
index fc2568ba75b77f8e61ca05c020573c7748b821a2..0d0ad893f45d39f7770d57dc41a90b862d80f3f0 100644 (file)
@@ -92,6 +92,10 @@ struct _PdfDocument
        PdfDocumentSearch *search;
 };
 
+static EvLink *build_link_from_action (PdfDocument *pdf_document,
+                                      LinkAction  *link_action,
+                                      const char  *title);
+
 static void pdf_document_document_links_iface_init      (EvDocumentLinksIface      *iface);
 static void pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface);
 static void pdf_document_document_iface_init            (EvDocumentIface           *iface);
@@ -101,6 +105,11 @@ static void pdf_document_security_iface_init            (EvDocumentSecurityIface
 static void pdf_document_search_free                    (PdfDocumentSearch         *search);
 static void pdf_document_search_page_changed            (PdfDocumentSearch         *search);
 
+static GdkPixbuf *bitmap_to_pixbuf (SplashBitmap *bitmap,
+                                   GdkPixbuf    *target,
+                                   gint          x_offset,
+                                   gint          y_offset);
+
 
 G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT,
                          {
@@ -259,7 +268,7 @@ pdf_document_set_page (EvDocument  *document,
 {
        PdfDocument *pdf_document = PDF_DOCUMENT (document);
 
-       page = CLAMP (page, 1, ev_document_get_n_pages (document));
+       page = CLAMP (page, 1, pdf_document_get_n_pages (document));
 
        if (page != pdf_document->page) {
                pdf_document->page = page;
@@ -362,7 +371,7 @@ pdf_document_get_page_size (EvDocument   *document,
        int page_width = 1, page_height = 1;
        double scale = pdf_document->scale;
 
-       if (page == -1) 
+       if (page == -1)
                page = pdf_document->page;
 
        doc_page = pdf_document->doc->getCatalog ()->getPage (page);
@@ -415,6 +424,38 @@ pdf_document_render (EvDocument  *document,
                                           draw.width, draw.height);
 }
 
+
+
+static GdkPixbuf *
+pdf_document_render_pixbuf (EvDocument *document)
+{
+       PdfDocument *pdf_document = PDF_DOCUMENT (document);
+       SplashOutputDev *output;
+       GdkPixbuf *pixbuf;
+       SplashColor color;
+
+       color.rgb8 = splashMakeRGB8 (255, 255, 255);
+
+       output = new SplashOutputDev (splashModeRGB8, gFalse, color);
+       output->startDoc (pdf_document->doc->getXRef());
+
+       pdf_document->doc->displayPage (output,
+                                       pdf_document->page,
+                                       72*pdf_document->scale,
+                                       72*pdf_document->scale,
+                                       0, gTrue, gFalse);
+
+       pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+                                FALSE, 8,
+                                output->getBitmap()->getWidth(),
+                                output->getBitmap()->getHeight());
+
+       bitmap_to_pixbuf (output->getBitmap(), pixbuf, 0, 0);
+       delete output;
+
+       return pixbuf;
+}
+
 double
 pdf_document_find_get_progress (EvDocumentFind *document_find)
 {
@@ -427,7 +468,7 @@ pdf_document_find_get_progress (EvDocumentFind *document_find)
                return 0;
        }
 
-       n_pages = ev_document_get_n_pages (EV_DOCUMENT (document_find));
+       n_pages = pdf_document_get_n_pages (EV_DOCUMENT (document_find));
        if (search->search_page > search->start_page) {
                pages_done = search->search_page - search->start_page + 1;
        } else if (search->search_page == search->start_page) {
@@ -544,7 +585,7 @@ pdf_document_search_idle_callback (void *data)
          * and then when the user switches to the current page, we
          * will emit "found" again with the real results.
          */
-        n_pages = ev_document_get_n_pages (EV_DOCUMENT (search->document));
+        n_pages = pdf_document_get_n_pages (EV_DOCUMENT (search->document));
 
         if (search->output_dev == 0) {
                 /* First time through here... */
@@ -632,7 +673,7 @@ pdf_document_find_begin (EvDocumentFind   *document,
         search->current_page_results = g_array_new (FALSE,
                                                     FALSE,
                                                     sizeof (GdkRectangle));
-        n_pages = ev_document_get_n_pages (EV_DOCUMENT (document));
+        n_pages = pdf_document_get_n_pages (EV_DOCUMENT (document));
 
         search->other_page_flags = g_new0 (int, n_pages + 1);
        for (i = 0; i <= n_pages; i++) {
@@ -716,7 +757,7 @@ pdf_document_ps_export_begin (EvPSExporter *exporter, const char *filename)
 
        document->ps_out = new PSOutputDev ((char *)filename, document->doc->getXRef(),
                                            document->doc->getCatalog(), 1,
-                                           ev_document_get_n_pages (EV_DOCUMENT (document)),
+                                           pdf_document_get_n_pages (EV_DOCUMENT (document)),
                                            psModePS);
 }
 
@@ -780,27 +821,65 @@ pdf_document_links_has_document_links (EvDocumentLinks *document_links)
        return FALSE;
 }
 
-static EvDocumentLinksIter *
-pdf_document_links_begin_read (EvDocumentLinks *document_links)
+static void
+build_tree (PdfDocument  *pdf_document,
+           GtkTreeModel *model,
+           GtkTreeIter  *parent,
+           GooList      *items)
+{
+       int i;
+
+       for (i = 0; i < items->getLength (); i++) {
+               OutlineItem *item;
+               GtkTreeIter iter;
+               LinkAction *link_action;
+               gchar *title;
+               EvLink *link;
+               
+               item = (OutlineItem *)items->get (i);
+               gtk_tree_store_append (GTK_TREE_STORE (model), &iter, parent);
+
+               link_action = item->getAction ();
+               title = unicode_to_char (item, pdf_document->umap);
+               link = build_link_from_action (pdf_document, link_action, title);
+
+               gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
+                                   EV_DOCUMENT_LINKS_COLUMN_MARKUP, title,
+                                   EV_DOCUMENT_LINKS_COLUMN_LINK, link,
+                                   -1);
+
+               item->open ();
+               if (item->hasKids () && item->getKids ()) {
+                       build_tree (pdf_document,
+                                   model,
+                                   &iter,
+                                   item->getKids ());
+               }
+       }
+}
+
+static GtkTreeModel *
+pdf_document_links_get_links_model (EvDocumentLinks *document_links)
 {
        PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
+       GtkTreeModel *model = NULL;
        Outline *outline;
-       LinksIter *iter;
        GooList *items;
 
        g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), NULL);
 
        outline = pdf_document->doc->getOutline();
        items = outline->getItems();
-       if (! items)
-               return NULL;
 
-       iter = g_new0 (LinksIter, 1);
-       iter->items = items;
-       iter->index = 0;
-       iter->level = 0;
+       /* Create the model iff we have items*/
+       if (items != 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, items);
+       }
 
-       return (EvDocumentLinksIter *) iter;
+       return model;
 }
 
 static EvLink *
@@ -873,6 +952,31 @@ build_link_from_action (PdfDocument *pdf_document,
        return link;
 }
 
+
+#if 0
+static EvDocumentLinksIter *
+pdf_document_links_begin_read (EvDocumentLinks *document_links)
+{
+       PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
+       Outline *outline;
+       LinksIter *iter;
+       GooList *items;
+
+       g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), NULL);
+
+       outline = pdf_document->doc->getOutline();
+       items = outline->getItems();
+       if (! items)
+               return NULL;
+
+       iter = g_new0 (LinksIter, 1);
+       iter->items = items;
+       iter->index = 0;
+       iter->level = 0;
+
+       return (EvDocumentLinksIter *) iter;
+}
+
 /* FIXME This returns a new object every time, probably we should cache it
    in the iter */
 static EvLink *
@@ -946,6 +1050,7 @@ pdf_document_links_free_iter (EvDocumentLinks     *document_links,
        /* FIXME: Should I close all the nodes?? Free them? */
        g_free (iter);
 }
+#endif
 
 static void
 pdf_document_finalize (GObject *object)
@@ -1086,7 +1191,7 @@ pdf_document_get_link (EvDocument *document, int x, int y)
        link_y = link_y / pdf_document->scale;
 
        action = pdf_document->links->find (link_x, link_y);
-       
+
        if (action) {
                return build_link_from_action (pdf_document, action, "");
        } else {
@@ -1140,6 +1245,7 @@ pdf_document_document_iface_init (EvDocumentIface *iface)
        iface->set_page_offset = pdf_document_set_page_offset;
        iface->get_page_size = pdf_document_get_page_size;
        iface->render = pdf_document_render;
+       iface->render_pixbuf = pdf_document_render_pixbuf;
 }
 
 static void
@@ -1173,11 +1279,7 @@ static void
 pdf_document_document_links_iface_init (EvDocumentLinksIface *iface)
 {
        iface->has_document_links = pdf_document_links_has_document_links;
-       iface->begin_read = pdf_document_links_begin_read;
-       iface->get_link = pdf_document_links_get_link;
-       iface->get_child = pdf_document_links_get_child;
-       iface->next = pdf_document_links_next;
-       iface->free_iter = pdf_document_links_free_iter;
+       iface->get_links_model = pdf_document_links_get_links_model;
 }
 
 /* Thumbnails */
@@ -1217,7 +1319,7 @@ bitmap_to_pixbuf (SplashBitmap *bitmap,
                guchar *q;
 
                p = dataPtr.rgb8 + y * width;
-               q = target_data + ((y + y_offset) * target_rowstride + 
+               q = target_data + ((y + y_offset) * target_rowstride +
                                   x_offset * (target_has_alpha?4:3));
                for (x = 0; x < width; x++) {
                        rgb = *p++;
@@ -1287,7 +1389,7 @@ pdf_document_thumbnails_get_dimensions (EvDocumentThumbnails *document_thumbnail
        Object the_thumb;
        Thumb *thumb = NULL;
 
-       the_page = pdf_document->doc->getCatalog ()->getPage (page);
+       the_page = pdf_document->doc->getCatalog ()->getPage (page + 1);
        the_page->getThumb (&the_thumb);
 
        if (!(the_thumb.isNull () || the_thumb.isNone())) {
index faa4d06298f6c4aa1ab45b51f557bbf11ad88c32..a0c61d5a3fbb4a536410420bc7c4218d82e1bf8c 100644 (file)
@@ -60,12 +60,6 @@ gtk_gs_defaults_get_interpreter_cmd()
     return GS_PATH;
 }
 
-const gchar *
-gtk_gs_defaults_get_alpha_parameters (void)
-{
-       return ALPHA_PARAMS;
-}
-
 const gchar *
 gtk_gs_defaults_get_ungzip_cmd (void)
 {
index e8f477985602555cdbb2b4697f046062905e4d3b..08431ff78dcf799e162c4468f609b15cbec2978d 100644 (file)
@@ -32,7 +32,6 @@ G_BEGIN_DECLS
 
 GtkGSPaperSize *gtk_gs_defaults_get_paper_sizes(void);
 const gchar *gtk_gs_defaults_get_interpreter_cmd(void);
-const gchar *gtk_gs_defaults_get_alpha_parameters(void);
 const gchar *gtk_gs_defaults_get_ungzip_cmd(void);
 const gchar *gtk_gs_defaults_get_unbzip2_cmd(void);
 
index 958d7687c2a196213d4604ee0c032ebce667616c..4dd344be573d51efedec486eddc065163f27b3c8 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
  
-/*
-Ghostview interface to ghostscript
-
-When the GHOSTVIEW environment variable is set, ghostscript draws on
-an existing drawable rather than creating its own window.  Ghostscript
-can be directed to draw on either a window or a pixmap.
-
-Drawing on a Window
-
-The GHOSTVIEW environment variable contains the window id of the target
-window.  The window id is an integer.  Ghostscript will use the attributes
-of the window to obtain the width, height, colormap, screen, and visual of
-the window. The remainder of the information is gotten from the GHOSTVIEW
-property on that window.
-
-
-Drawing on a Pixmap
-
-The GHOSTVIEW environment variable contains a window id and a pixmap id.
-They are integers separated by white space.  Ghostscript will use the
-attributes of the window to obtain the colormap, screen, and visual to use.
-The width and height will be obtained from the pixmap. The remainder of the
-information, is gotten from the GHOSTVIEW property on the window.  In this
-case, the property is deleted when read.
-
-The GHOSTVIEW environment variable
-
-parameters:    window-id [pixmap-id]
-
-scanf format:  "%d %d"
-
-explanation of parameters:
-
-       window-id: tells ghostscript where to
-                   - read the GHOSTVIEW property
-                   - send events
-                   If pixmap-id is not present,
-                   ghostscript will draw on this window.
-
-       pixmap-id: If present, tells ghostscript that a pixmap will be used
-                   as the final destination for drawing.  The window will
-                   not be touched for drawing purposes.
-
-The GHOSTVIEW property
-
-type:  STRING
-
-parameters:
-
-    bpixmap orient llx lly urx ury xdpi ydpi [left bottom top right]
-
-scanf format: "%d %d %d %d %d %d %f %f %d %d %d %d"
-
-explanation of parameters:
-
-       bpixmap: pixmap id of the backing pixmap for the window.  If no
-               pixmap is to be used, this parameter should be zero.  This
-               parameter must be zero when drawing on a pixmap.
-
-       orient: orientation of the page.  The number represents clockwise
-               rotation of the paper in degrees.  Permitted values are
-               0, 90, 180, 270.
-
-       llx, lly, urx, ury: Bounding box of the drawable.  The bounding box
-               is specified in PostScript points in default user coordinates.
-
-       xdpi, ydpi: Resolution of window.  (This can be derived from the
-               other parameters, but not without roundoff error.  These
-               values are included to avoid this error.)
-
-       left, bottom, top, right: (optional)
-               Margins around the window.  The margins extend the imageable
-               area beyond the boundaries of the window.  This is primarily
-               used for popup zoom windows.  I have encountered several
-               instances of PostScript programs that position themselves
-               with respect to the imageable area.  The margins are specified
-               in PostScript points.  If omitted, the margins are assumed to
-               be 0.
-
-Events from ghostscript
-
-If the final destination is a pixmap, the client will get a property notify
-event when ghostscript reads the GHOSTVIEW property causing it to be deleted.
-
-Ghostscript sends events to the window where it read the GHOSTVIEW property.
-These events are of type ClientMessage.  The message_type is set to
-either PAGE or DONE.  The first long data value gives the window to be used
-to send replies to ghostscript.  The second long data value gives the primary
-drawable.  If rendering to a pixmap, it is the primary drawable.  If rendering
-to a window, the backing pixmap is the primary drawable.  If no backing pixmap
-is employed, then the window is the primary drawable.  This field is necessary
-to distinguish multiple ghostscripts rendering to separate pixmaps where the
-GHOSTVIEW property was placed on the same window.
-
-The PAGE message indicates that a "page" has completed.  Ghostscript will
-wait until it receives a ClientMessage whose message_type is NEXT before
-continuing.
-
-The DONE message indicates that ghostscript has finished processing.
-
-*/
-
 #include "config.h"
 #include <string.h>
 #include <stdlib.h>
@@ -134,10 +32,6 @@ The DONE message indicates that ghostscript has finished processing.
 #include <gdk/gdkx.h>
 #include <gdk/gdk.h>
 #include <glib/gi18n.h>
-#ifdef  HAVE_XINERAMA
-#   include <gdk/gdkx.h>
-#   include <X11/extensions/Xinerama.h>
-#endif /* HAVE_XINERAMA */
 #include <X11/Intrinsic.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -162,9 +56,6 @@ The DONE message indicates that ghostscript has finished processing.
 #   define O_NONBLOCK O_NDELAY
 #endif
 
-#define PS_DOCUMENT_WATCH_INTERVAL 1000
-#define PS_DOCUMENT_WATCH_TIMEOUT  2
-
 #define MAX_BUFSIZE 1024
 
 #define PS_DOCUMENT_IS_COMPRESSED(gs)       (PS_DOCUMENT(gs)->gs_filename_unc != NULL)
@@ -172,7 +63,9 @@ The DONE message indicates that ghostscript has finished processing.
                                         PS_DOCUMENT(gs)->gs_filename_unc : \
                                         PS_DOCUMENT(gs)->gs_filename)
 
-enum { INTERPRETER_MESSAGE, INTERPRETER_ERROR, LAST_SIGNAL };
+GCond* pixbuf_cond = NULL;
+GMutex* pixbuf_mutex = NULL;
+GdkPixbuf *current_pixbuf = NULL;
 
 enum {
        PROP_0,
@@ -191,100 +84,67 @@ struct record_list {
 
 static gboolean broken_pipe = FALSE;
 
-static void
-catchPipe(int i)
-{
-  broken_pipe = True;
-}
-
 /* Forward declarations */
 static void ps_document_init(PSDocument * gs);
 static void ps_document_class_init(PSDocumentClass * klass);
-static void ps_document_emit_error_msg(PSDocument * gs, const gchar * msg);
 static void ps_document_finalize(GObject * object);
 static void send_ps(PSDocument * gs, long begin, unsigned int len, gboolean close);
-static void set_up_page(PSDocument * gs);
 static void close_pipe(int p[2]);
-static void interpreter_failed(PSDocument * gs);
-static float compute_xdpi(void);
-static float compute_ydpi(void);
-static gboolean compute_size(PSDocument * gs);
 static void output(gpointer data, gint source, GdkInputCondition condition);
 static void input(gpointer data, gint source, GdkInputCondition condition);
 static void stop_interpreter(PSDocument * gs);
 static gint start_interpreter(PSDocument * gs);
-gboolean computeSize(void);
-static gboolean ps_document_set_page_size(PSDocument * gs, gint new_pagesize, gint pageid);
 static void ps_document_document_iface_init (EvDocumentIface *iface);
-static gboolean ps_document_goto_page(PSDocument * gs, gint page);
+static gboolean ps_document_widget_event (GtkWidget *widget, GdkEvent *event, gpointer data);
 
 static GObjectClass *parent_class = NULL;
 
 static PSDocumentClass *gs_class = NULL;
 
 static void
-ps_document_init(PSDocument * gs)
+ps_document_init (PSDocument *gs)
 {
-  gs->bpixmap = NULL;
+       gs->bpixmap = NULL;
 
-  gs->current_page = 0;
-  gs->disable_start = FALSE;
-  gs->interpreter_pid = -1;
+       gs->current_page = 0;
+       gs->interpreter_pid = -1;
 
-  gs->width = -1;
-  gs->height = -1;
-  gs->busy = FALSE;
-  gs->changed = FALSE;
-  gs->gs_scanstyle = 0;
-  gs->gs_filename = 0;
-  gs->gs_filename_dsc = 0;
-  gs->gs_filename_unc = 0;
+       gs->width = -1;
+       gs->height = -1;
+       gs->busy = FALSE;
+       gs->gs_filename = 0;
+       gs->gs_filename_unc = 0;
 
-  broken_pipe = FALSE;
+       broken_pipe = FALSE;
 
-  gs->structured_doc = FALSE;
-  gs->reading_from_pipe = FALSE;
-  gs->send_filename_to_gs = FALSE;
+       gs->structured_doc = FALSE;
+       gs->reading_from_pipe = FALSE;
+       gs->send_filename_to_gs = FALSE;
 
-  gs->doc = NULL;
-  gs->loaded = FALSE;
+       gs->doc = NULL;
+       gs->loaded = FALSE;
+
+       gs->interpreter_input = -1;
+       gs->interpreter_output = -1;
+       gs->interpreter_err = -1;
+       gs->interpreter_input_id = 0;
+       gs->interpreter_output_id = 0;
+       gs->interpreter_error_id = 0;
+
+       gs->ps_input = NULL;
+       gs->input_buffer = NULL;
+       gs->input_buffer_ptr = NULL;
+       gs->bytes_left = 0;
+       gs->buffer_bytes_left = 0;
 
-  gs->interpreter_input = -1;
-  gs->interpreter_output = -1;
-  gs->interpreter_err = -1;
-  gs->interpreter_input_id = 0;
-  gs->interpreter_output_id = 0;
-  gs->interpreter_error_id = 0;
-
-  gs->ps_input = NULL;
-  gs->input_buffer = NULL;
-  gs->input_buffer_ptr = NULL;
-  gs->bytes_left = 0;
-  gs->buffer_bytes_left = 0;
-
-  gs->llx = 0;
-  gs->lly = 0;
-  gs->urx = 0;
-  gs->ury = 0;
-  gs->xdpi = compute_xdpi();
-  gs->ydpi = compute_ydpi();
-
-  gs->left_margin = 0;
-  gs->top_margin = 0;
-  gs->right_margin = 0;
-  gs->bottom_margin = 0;
-
-  gs->page_x_offset = 0;
-  gs->page_y_offset = 0;
-
-  /* Set user defined defaults */
-  gs->fallback_orientation = GTK_GS_ORIENTATION_PORTRAIT;
-  gs->zoom_factor = 1.0;
-  gs->default_size = 1;
-  gs->antialiased = TRUE;
-  gs->respect_eof = TRUE;
-
-  gs->gs_status = _("No document loaded.");
+       gs->page_x_offset = 0;
+       gs->page_y_offset = 0;
+       gs->zoom_factor = 1.0;
+
+       gs->gs_status = _("No document loaded.");
+
+       pixbuf_cond = g_cond_new ();
+       pixbuf_mutex = g_mutex_new ();
 }
 
 static void
@@ -325,63 +185,85 @@ ps_document_get_property (GObject *object,
 static void
 ps_document_class_init(PSDocumentClass *klass)
 {
-  GObjectClass *object_class;
+       GObjectClass *object_class;
 
-  object_class = (GObjectClass *) klass;
-  parent_class = g_type_class_peek_parent (klass);
-  gs_class = klass;
+       object_class = (GObjectClass *) klass;
+       parent_class = g_type_class_peek_parent (klass);
+       gs_class = klass;
 
-  object_class->finalize = ps_document_finalize;
-  object_class->get_property = ps_document_get_property;
-  object_class->set_property = ps_document_set_property;
+       object_class->finalize = ps_document_finalize;
+       object_class->get_property = ps_document_get_property;
+       object_class->set_property = ps_document_set_property;
 
-  /* Create atoms */
-  klass->gs_atom = gdk_atom_intern("GHOSTVIEW", FALSE);
-  klass->next_atom = gdk_atom_intern("NEXT", FALSE);
-  klass->page_atom = gdk_atom_intern("PAGE", FALSE);
-  klass->string_atom = gdk_atom_intern("STRING", FALSE);
+       klass->gs_atom = gdk_atom_intern ("GHOSTVIEW", FALSE);
+       klass->next_atom = gdk_atom_intern ("NEXT", FALSE);
+       klass->page_atom = gdk_atom_intern ("PAGE", FALSE);
+       klass->string_atom = gdk_atom_intern ("STRING", FALSE);
 
-  g_object_class_override_property (object_class, PROP_TITLE, "title");
+       g_object_class_override_property (object_class, PROP_TITLE, "title");
 }
 
-/* Clean all memory and temporal files */
 static void
-ps_document_cleanup(PSDocument * gs)
+push_pixbuf (PSDocument *gs)
 {
-  g_return_if_fail(gs != NULL);
-  g_return_if_fail(GTK_IS_GS(gs));
+       GdkColormap *cmap;
+       GdkPixbuf *pixbuf;
+
+       cmap = gdk_window_get_colormap (gs->pstarget);
+       
+       pixbuf =  gdk_pixbuf_get_from_drawable (NULL, gs->bpixmap, cmap,
+                                               0, 0, 0, 0,
+                                               gs->width, gs->height);
+       g_mutex_lock (pixbuf_mutex);
+       current_pixbuf = pixbuf;
+       g_cond_signal (pixbuf_cond);
+       g_mutex_unlock (pixbuf_mutex);
 
-  stop_interpreter(gs);
+}
 
-  if(gs->gs_psfile) {
-    fclose(gs->gs_psfile);
-    gs->gs_psfile = NULL;
-  }
-  if(gs->gs_filename) {
-    g_free(gs->gs_filename);
-    gs->gs_filename = NULL;
-  }
-  if(gs->doc) {
-    psfree(gs->doc);
-    gs->doc = NULL;
-  }
-  if(gs->gs_filename_dsc) {
-    unlink(gs->gs_filename_dsc);
-    g_free(gs->gs_filename_dsc);
-    gs->gs_filename_dsc = NULL;
-  }
-  if(gs->gs_filename_unc) {
-    unlink(gs->gs_filename_unc);
-    g_free(gs->gs_filename_unc);
-    gs->gs_filename_unc = NULL;
-  }
-  gs->current_page = 0;
-  gs->loaded = FALSE;
-  gs->llx = 0;
-  gs->lly = 0;
-  gs->urx = 0;
-  gs->ury = 0;
-  set_up_page(gs);
+static void
+interpreter_failed (PSDocument *gs, char *msg)
+{
+       LOG ("Interpreter failed %s", msg);
+
+       push_pixbuf (gs);
+
+       stop_interpreter (gs);
+}
+
+static void
+ps_document_cleanup (PSDocument *gs)
+{
+       g_return_if_fail (gs != NULL);
+       g_return_if_fail (PS_IS_DOCUMENT (gs));
+
+       LOG ("Cleanup\n");
+
+       stop_interpreter (gs);
+
+       if (gs->gs_psfile) {
+               fclose (gs->gs_psfile);
+               gs->gs_psfile = NULL;
+       }
+
+       if (gs->gs_filename) {
+               g_free (gs->gs_filename);
+               gs->gs_filename = NULL;
+       }
+
+       if (gs->doc) {
+               psfree (gs->doc);
+               gs->doc = NULL;
+       }
+
+       if (gs->gs_filename_unc) {
+               unlink(gs->gs_filename_unc);
+               g_free(gs->gs_filename_unc);
+               gs->gs_filename_unc = NULL;
+       }
+
+       gs->current_page = 0;
+       gs->loaded = FALSE;
 }
 
 static gboolean
@@ -398,56 +280,19 @@ ps_document_widget_event (GtkWidget *widget, GdkEvent *event, gpointer data)
                LOG ("GS rendered the document");
                gs->busy = FALSE;
 
-               if (gs->scaling) {
-                       ev_document_scale_changed (EV_DOCUMENT (gs));
-                       gs->scaling = FALSE;
-               } else {
-                       ev_document_page_changed (EV_DOCUMENT (gs));
-               }
+               push_pixbuf (gs);
        }
 
        return TRUE;
 }
 
-static void
-ps_document_set_target (EvDocument  *document,
-                       GdkDrawable *target)
-{
-       PSDocument *gs = PS_DOCUMENT (document);
-       GtkWidget *widget;
-       gpointer data;
-
-       if (gs->pstarget) {
-               gdk_window_get_user_data (gs->pstarget, &data);
-               g_return_if_fail (GTK_IS_WIDGET (data));
-
-               widget = GTK_WIDGET (data);
-               g_signal_handlers_disconnect_by_func
-                       (widget, ps_document_widget_event, document);
-       }
-
-       gs->pstarget = target;
-
-       if (gs->pstarget) {
-               gdk_window_get_user_data (gs->pstarget, &data);
-               g_return_if_fail (GTK_IS_WIDGET (data));
-
-               widget = GTK_WIDGET (data);
-               g_signal_connect (widget, "event",
-                                 G_CALLBACK (ps_document_widget_event),
-                                 document);
-       }
-
-       ps_document_goto_page (gs, gs->current_page);
-}
-
 static void
 ps_document_finalize (GObject * object)
 {
        PSDocument *gs;
 
        g_return_if_fail (object != NULL);
-       g_return_if_fail (GTK_IS_GS (object));
+       g_return_if_fail (PS_IS_DOCUMENT (object));
 
        LOG ("Finalize");
 
@@ -456,14 +301,12 @@ ps_document_finalize (GObject * object)
        ps_document_cleanup (gs);
        stop_interpreter (gs);
 
-       ps_document_set_target (EV_DOCUMENT (object), NULL);
-
        if(gs->input_buffer) {
                g_free(gs->input_buffer);
                gs->input_buffer = NULL;
        }
 
-       (*G_OBJECT_CLASS(parent_class)->finalize) (object);
+       (*G_OBJECT_CLASS (parent_class)->finalize) (object);
 }
 
 static void
@@ -505,143 +348,88 @@ send_ps(PSDocument * gs, long begin, unsigned int len, gboolean close)
   }
 }
 
-static gint
-ps_document_get_orientation(PSDocument * gs)
+static float
+get_xdpi (PSDocument *gs)
 {
-  g_return_val_if_fail(gs != NULL, -1);
-  g_return_val_if_fail(GTK_IS_GS(gs), -1);
-
-  if(gs->doc) {
-    if(gs->structured_doc) {
-      if(gs->doc->pages[MAX(gs->current_page, 0)].orientation !=
-         GTK_GS_ORIENTATION_NONE)
-        gs->real_orientation =
-          gs->doc->pages[MAX(gs->current_page, 0)].orientation;
-      else
-        gs->real_orientation = gs->doc->default_page_orientation;
-    }
-
-    if(gs->real_orientation == GTK_GS_ORIENTATION_NONE)
-      gs->real_orientation = gs->doc->orientation;
-  }
+       return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
+}
 
-  if(gs->real_orientation == GTK_GS_ORIENTATION_NONE)
-    return gs->fallback_orientation;
-  else
-    return gs->real_orientation;
+static float
+get_ydpi (PSDocument *gs)
+{
+       return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
 }
 
 static void
-set_up_page(PSDocument * gs)
+setup_pixmap (PSDocument *gs)
 {
-  guint orientation;
-  char buf[1024];
-  //GdkColormap *colormap;
-  GdkGC *fill;
-  GdkColor white = { 0, 0xFFFF, 0xFFFF, 0xFFFF };   /* pixel, r, g, b */
-  GdkColormap *colormap;
-  gboolean size_changed;
-
-#ifdef HAVE_LOCALE_H
-  char *savelocale;
-#endif
-
-  LOG ("Setup the page");
-
-  size_changed = compute_size (gs);
-
-  if (gs->pstarget == NULL)
-    return;
-
-  /* Do we have to check if the actual geometry changed? */
-
-  stop_interpreter(gs);
-
-  orientation = ps_document_get_orientation(gs);
-
-  if (size_changed || gs->bpixmap == NULL) {
-    gdk_flush();
-
-    /* clear new pixmap (set to white) */
-    fill = gdk_gc_new(gs->pstarget);
-    if(fill) {
-      colormap = gdk_drawable_get_colormap(gs->pstarget);
-      gdk_color_alloc (colormap, &white);
-      gdk_gc_set_foreground(fill, &white);
-
-      if(gs->width > 0 && gs->height > 0) {
-        if(gs->bpixmap) {
-          gdk_drawable_unref(gs->bpixmap);
-          gs->bpixmap = NULL;
-        }
+       GdkGC *fill;
+       GdkColor white = { 0, 0xFFFF, 0xFFFF, 0xFFFF };   /* pixel, r, g, b */
+       GdkColormap *colormap;
 
         LOG ("Create our internal pixmap");
-        gs->bpixmap = gdk_pixmap_new(gs->pstarget, gs->width, gs->height, -1);
 
-        gdk_draw_rectangle(gs->bpixmap, fill, TRUE,
-                           0, 0, gs->width, gs->height);
-      }
-      else {
-        gdk_draw_rectangle(gs->pstarget, fill, TRUE,
-                           0, 0, gs->width, gs->height);
-      }
-      gdk_gc_unref(fill);
+       if(gs->bpixmap) {
+               gdk_drawable_unref(gs->bpixmap);
+       }
 
-      gdk_flush();
-    }
-  }
+       fill = gdk_gc_new (gs->pstarget);
+       colormap = gdk_drawable_get_colormap (gs->pstarget);
+       gdk_color_alloc (colormap, &white);
+       gdk_gc_set_foreground (fill, &white);
+       gs->bpixmap = gdk_pixmap_new (gs->pstarget, gs->width, gs->height, -1);
+       gdk_draw_rectangle (gs->bpixmap, fill, TRUE,
+                            0, 0, gs->width, gs->height);
+}
 
+static void
+setup_page (PSDocument *gs)
+{
+       char buf[1024];
 #ifdef HAVE_LOCALE_H
-  /* gs needs floating point parameters with '.' as decimal point
-   * while some (european) locales use ',' instead, so we set the 
-   * locale for this snprintf to "C".
-   */
-  savelocale = setlocale(LC_NUMERIC, "C");
+       char *savelocale;
 #endif
 
-  g_snprintf(buf, 1024, "%ld %d %d %d %d %d %f %f %d %d %d %d",
-             0L,
-             orientation * 90,
-             gs->llx,
-             gs->lly,
-             gs->urx,
-             gs->ury,
-             gs->xdpi * gs->zoom_factor,
-             gs->ydpi * gs->zoom_factor,
-             gs->left_margin,
-             gs->bottom_margin, gs->right_margin, gs->top_margin);
+       LOG ("Setup the page");
 
-  LOG ("GS property %s", buf);
+#ifdef HAVE_LOCALE_H
+       /* gs needs floating point parameters with '.' as decimal point
+        * while some (european) locales use ',' instead, so we set the 
+        * locale for this snprintf to "C".
+        */
+       savelocale = setlocale (LC_NUMERIC, "C");
+#endif
+
+       g_snprintf (buf, 1024, "%ld %d %d %d %d %d %f %f %d %d %d %d",
+                   0L, gs->orientation * 90, gs->llx, gs->lly, gs->urx, gs->ury,
+                   get_xdpi (gs) * gs->zoom_factor,
+                   get_ydpi (gs) * gs->zoom_factor,
+                   0, 0, 0, 0);
+       LOG ("GS property %s", buf);
 
 #ifdef HAVE_LOCALE_H
-  setlocale(LC_NUMERIC, savelocale);
+       setlocale(LC_NUMERIC, savelocale);
 #endif
-  gdk_property_change(gs->pstarget,
-                      gs_class->gs_atom,
-                      gs_class->string_atom,
-                      8, GDK_PROP_MODE_REPLACE, buf, strlen(buf));
-  gdk_flush();
+       gdk_property_change (gs->pstarget, gs_class->gs_atom, gs_class->string_atom,
+                            8, GDK_PROP_MODE_REPLACE, (guchar *)buf, strlen(buf));
+       gdk_flush ();
 }
 
 static void
-close_pipe(int p[2])
+close_pipe (int p[2])
 {
-  if(p[0] != -1)
-    close(p[0]);
-  if(p[1] != -1)
-    close(p[1]);
+       if (p[0] != -1) {
+               close (p[0]);
+       }
+       if (p[1] != -1) {
+               close (p[1]);
+       }
 }
 
 static gboolean
-is_interpreter_ready(PSDocument * gs)
+is_interpreter_ready (PSDocument *gs)
 {
-  return (gs->interpreter_pid != -1 && !gs->busy && gs->ps_input == NULL);
-}
-
-static void
-interpreter_failed(PSDocument * gs)
-{
-  stop_interpreter(gs);
+       return (gs->interpreter_pid != -1 && !gs->busy && gs->ps_input == NULL);
 }
 
 static void
@@ -661,11 +449,11 @@ output(gpointer data, gint source, GdkInputCondition condition)
     }
     else if(bytes == -1) {
       /* trouble... */
-      interpreter_failed(gs);
+      interpreter_failed(gs, NULL);
       return;
     }
     if(gs->interpreter_err == -1) {
-      stop_interpreter(gs);
+      interpreter_failed(gs, NULL);
     }
   }
   else if(source == gs->interpreter_err) {
@@ -678,20 +466,26 @@ output(gpointer data, gint source, GdkInputCondition condition)
     }
     else if(bytes == -1) {
       /* trouble... */
-      interpreter_failed(gs);
+      interpreter_failed(gs, NULL);
       return;
     }
     if(gs->interpreter_output == -1) {
-      stop_interpreter(gs);
+      interpreter_failed(gs, NULL);
     }
   }
   if(bytes > 0) {
     buf[bytes] = '\0';
     msg = g_strdup(buf);
-    ps_document_emit_error_msg (gs, msg);   
+    interpreter_failed (gs, msg);   
   }
 }
 
+static void
+catchPipe(int i)
+{
+  broken_pipe = True;
+}
+
 static void
 input(gpointer data, gint source, GdkInputCondition condition)
 {
@@ -700,6 +494,8 @@ input(gpointer data, gint source, GdkInputCondition condition)
   void (*oldsig) (int);
   oldsig = signal(SIGPIPE, catchPipe);
 
+  LOG ("Input");
+
   do {
     if(gs->buffer_bytes_left == 0) {
       /* Get a new section if required */
@@ -730,26 +526,24 @@ input(gpointer data, gint source, GdkInputCondition condition)
         gs->buffer_bytes_left = 0;
       }
       if(gs->bytes_left > 0 && gs->buffer_bytes_left == 0) {
-        interpreter_failed(gs); /* Error occurred */
+        interpreter_failed (gs, NULL); /* Error occurred */
       }
       gs->input_buffer_ptr = gs->input_buffer;
       gs->bytes_left -= gs->buffer_bytes_left;
     }
 
     if(gs->buffer_bytes_left > 0) {
-      /* g_print (" writing: %s\n",gs->input_buffer_ptr); */
-
       bytes_written = write(gs->interpreter_input,
                             gs->input_buffer_ptr, gs->buffer_bytes_left);
 
       if(broken_pipe) {
-        ps_document_emit_error_msg(gs, g_strdup(_("Broken pipe.")));
+        interpreter_failed (gs, g_strdup(_("Broken pipe.")));
         broken_pipe = FALSE;
-        interpreter_failed(gs);
+        interpreter_failed (gs, NULL);
       }
       else if(bytes_written == -1) {
         if((errno != EWOULDBLOCK) && (errno != EAGAIN)) {
-          interpreter_failed(gs);   /* Something bad happened */
+          interpreter_failed (gs, NULL);   /* Something bad happened */
         }
       }
       else {
@@ -771,161 +565,149 @@ input(gpointer data, gint source, GdkInputCondition condition)
 }
 
 static int
-start_interpreter(PSDocument * gs)
+start_interpreter (PSDocument *gs)
 {
-  int std_in[2] = { -1, -1 };   /* pipe to interp stdin */
-  int std_out[2];               /* pipe from interp stdout */
-  int std_err[2];               /* pipe from interp stderr */
+       int std_in[2] = { -1, -1 };   /* pipe to interp stdin */
+       int std_out[2];               /* pipe from interp stdout */
+       int std_err[2];               /* pipe from interp stderr */
 
 #define NUM_ARGS    100
 #define NUM_GS_ARGS (NUM_ARGS - 20)
 #define NUM_ALPHA_ARGS 10
 
-  char *argv[NUM_ARGS], *dir, *gv_env;
-  char **gs_args, **alpha_args = NULL;
-  int argc = 0, i;
+       char *argv[NUM_ARGS], *dir, *gv_env;
+       char **gs_args, **alpha_args = NULL;
+       int argc = 0, i;
 
-  LOG ("Start the interpreter");
+       LOG ("Start the interpreter");
 
-  if(!gs->gs_filename)
-    return 0;
+       if(!gs->gs_filename)
+               return 0;
 
-  stop_interpreter(gs);
+       stop_interpreter(gs);
 
-  if(gs->disable_start == TRUE)
-    return 0;
+       /* set up the args... */
+       gs_args = g_strsplit (gtk_gs_defaults_get_interpreter_cmd (), " ", NUM_GS_ARGS);
+       for(i = 0; i < NUM_GS_ARGS && gs_args[i]; i++, argc++) {
+               argv[argc] = gs_args[i];
+       }
 
-  /* set up the args... */
-  gs_args = g_strsplit(gtk_gs_defaults_get_interpreter_cmd(), " ", NUM_GS_ARGS);
-  for(i = 0; i < NUM_GS_ARGS && gs_args[i]; i++, argc++)
-    argv[argc] = gs_args[i];
-
-  if(gs->antialiased) {
-    if(strlen(gtk_gs_defaults_get_alpha_parameters()) == 0)
-      alpha_args = g_strsplit(ALPHA_PARAMS, " ", NUM_ALPHA_ARGS);
-    else
-      alpha_args = g_strsplit(gtk_gs_defaults_get_alpha_parameters(),
-                              " ", NUM_ALPHA_ARGS);
-    for(i = 0; i < NUM_ALPHA_ARGS && alpha_args[i]; i++, argc++)
-      argv[argc] = alpha_args[i];
-  }
-  else
-    argv[argc++] = "-sDEVICE=x11";
-  argv[argc++] = "-dNOPAUSE";
-  argv[argc++] = "-dQUIET";
-  /* I assume we do _not_ want to change this... (: */
-  argv[argc++] = "-dSAFER";
-
-  /* set up the pipes */
-  if(gs->send_filename_to_gs) {
-    argv[argc++] = PS_DOCUMENT_GET_PS_FILE(gs);
-    argv[argc++] = "-c";
-    argv[argc++] = "quit";
-  }
-  else
-    argv[argc++] = "-";
+       alpha_args = g_strsplit (ALPHA_PARAMS, " ", NUM_ALPHA_ARGS);
 
-  argv[argc++] = NULL;
+       argv[argc++] = "-dNOPAUSE";
+       argv[argc++] = "-dQUIET";
+       argv[argc++] = "-dSAFER";
 
-  if(!gs->reading_from_pipe && !gs->send_filename_to_gs) {
-    if(pipe(std_in) == -1) {
-      g_critical("Unable to open pipe to Ghostscript.");
-      return -1;
-    }
-  }
-  if(pipe(std_out) == -1) {
-    close_pipe(std_in);
-    return -1;
-  }
-  if(pipe(std_err) == -1) {
-    close_pipe(std_in);
-    close_pipe(std_out);
-    return -1;
-  }
+       /* set up the pipes */
+       if (gs->send_filename_to_gs) {
+               argv[argc++] = PS_DOCUMENT_GET_PS_FILE (gs);
+               argv[argc++] = "-c";
+               argv[argc++] = "quit";
+       } else {
+               argv[argc++] = "-";
+       }
 
-  gv_env = g_strdup_printf("GHOSTVIEW=%ld %ld",
-                           gdk_x11_drawable_get_xid(gs->pstarget),
-                          gdk_x11_drawable_get_xid(gs->bpixmap));
-
-  LOG ("Launching ghostview with env %s", gv_env);
-
-  gs->busy = TRUE;
-  gs->interpreter_pid = fork();
-  switch (gs->interpreter_pid) {
-  case -1:                     /* error */
-    close_pipe(std_in);
-    close_pipe(std_out);
-    close_pipe(std_err);
-    return -2;
-    break;
-  case 0:                      /* child */
-    close(std_out[0]);
-    dup2(std_out[1], 1);
-    close(std_out[1]);
-
-    close(std_err[0]);
-    dup2(std_err[1], 2);
-    close(std_err[1]);
-
-    if(!gs->reading_from_pipe) {
-      if(gs->send_filename_to_gs) {
-        int stdinfd;
-        /* just in case gs tries to read from stdin */
-        stdinfd = open("/dev/null", O_RDONLY);
-        if(stdinfd != 0) {
-          dup2(stdinfd, 0);
-          close(stdinfd);
-        }
-      }
-      else {
-        close(std_in[1]);
-        dup2(std_in[0], 0);
-        close(std_in[0]);
-      }
-    }
+       argv[argc++] = NULL;
 
-    putenv(gv_env);
-
-    /* change to directory where the input file is. This helps
-     * with postscript-files which include other files using
-     * a relative path */
-    dir = g_path_get_dirname(gs->gs_filename);
-    chdir(dir);
-    g_free(dir);
-
-    execvp(argv[0], argv);
-
-    /* Notify error */
-    g_print("Unable to execute [%s]\n", argv[0]);
-    g_strfreev(gs_args);
-    g_free(gv_env);
-    if(alpha_args)
-      g_strfreev(alpha_args);
-    _exit(1);
-    break;
-  default:                     /* parent */
-    if(!gs->send_filename_to_gs && !gs->reading_from_pipe) {
-      int result;
-      close(std_in[0]);
-      /* use non-blocking IO for pipe to ghostscript */
-      result = fcntl(std_in[1], F_GETFL, 0);
-      fcntl(std_in[1], F_SETFL, result | O_NONBLOCK);
-      gs->interpreter_input = std_in[1];
-    }
-    else {
-      gs->interpreter_input = -1;
-    }
-    close(std_out[1]);
-    gs->interpreter_output = std_out[0];
-    close(std_err[1]);
-    gs->interpreter_err = std_err[0];
-    gs->interpreter_output_id =
-      gdk_input_add(std_out[0], GDK_INPUT_READ, output, gs);
-    gs->interpreter_error_id =
-      gdk_input_add(std_err[0], GDK_INPUT_READ, output, gs);
-    break;
-  }
-  return TRUE;
+       if (!gs->reading_from_pipe && !gs->send_filename_to_gs) {
+               if (pipe (std_in) == -1) {
+                       g_critical ("Unable to open pipe to Ghostscript.");
+                       return -1;
+               }
+       }
+
+       if (pipe (std_out) == -1) {
+               close_pipe (std_in);
+               return -1;
+       }
+
+       if (pipe(std_err) == -1) {
+               close_pipe (std_in);
+               close_pipe (std_out);
+               return -1;
+       }
+
+       gv_env = g_strdup_printf ("GHOSTVIEW=%ld %ld",
+                                 gdk_x11_drawable_get_xid (gs->pstarget),
+                                 gdk_x11_drawable_get_xid (gs->bpixmap));
+       LOG ("Launching ghostview with env %s", gv_env);
+
+       gs->busy = TRUE;
+       gs->interpreter_pid = fork ();
+       switch (gs->interpreter_pid) {
+               case -1:                     /* error */
+                       close_pipe (std_in);
+                       close_pipe (std_out);
+                       close_pipe (std_err);
+                       return -2;
+                       break;
+               case 0:                      /* child */
+                       close (std_out[0]);
+                       dup2 (std_out[1], 1);
+                       close (std_out[1]);
+
+                       close (std_err[0]);
+                       dup2 (std_err[1], 2);
+                       close (std_err[1]);
+
+                       if (!gs->reading_from_pipe) {
+                               if (gs->send_filename_to_gs) {
+                                       int stdinfd;
+                                       /* just in case gs tries to read from stdin */
+                                       stdinfd = open("/dev/null", O_RDONLY);
+                                       if (stdinfd != 0) {
+                                               dup2(stdinfd, 0);
+                                               close(stdinfd);
+                                       }
+                               } else {
+                                       close (std_in[1]);
+                                       dup2 (std_in[0], 0);
+                                       close (std_in[0]);
+                               }
+                       }
+
+                       putenv(gv_env);
+
+                       /* change to directory where the input file is. This helps
+                        * with postscript-files which include other files using
+                        * a relative path */
+                       dir = g_path_get_dirname (gs->gs_filename);
+                       chdir (dir);
+                       g_free (dir);
+
+                       execvp (argv[0], argv);
+
+                       /* Notify error */
+                       g_critical ("Unable to execute [%s]\n", argv[0]);
+                       g_strfreev (gs_args);
+                       g_free (gv_env);
+                       g_strfreev (alpha_args);
+                       _exit (1);
+                       break;
+               default:                     /* parent */
+                       if (!gs->send_filename_to_gs && !gs->reading_from_pipe) {
+                               int result;
+                               close (std_in[0]);
+                               /* use non-blocking IO for pipe to ghostscript */
+                               result = fcntl (std_in[1], F_GETFL, 0);
+                               fcntl (std_in[1], F_SETFL, result | O_NONBLOCK);
+                               gs->interpreter_input = std_in[1];
+                       } else {
+                               gs->interpreter_input = -1;
+                       }
+                       close (std_out[1]);
+
+                       gs->interpreter_output = std_out[0];
+                       close (std_err[1]);
+                       gs->interpreter_err = std_err[0];
+                       gs->interpreter_output_id =
+                               gdk_input_add (std_out[0], GDK_INPUT_READ, output, gs);
+                       gs->interpreter_error_id =
+                               gdk_input_add (std_err[0], GDK_INPUT_READ, output, gs);
+                       break;
+       }
+
+       return TRUE;
 }
 
 static void
@@ -1063,16 +845,7 @@ check_filecompressed(PSDocument * gs)
     /* report error */
     g_snprintf(buf, 1024, _("Error while decompressing file %s:\n"),
                gs->gs_filename);
-    ps_document_emit_error_msg(gs, buf);
-    if(file_length(filename_err) > 0) {
-      FILE *err;
-      if((err = fopen(filename_err, "r"))) {
-        /* print file to message window */
-        while(fgets(buf, 1024, err))
-          ps_document_emit_error_msg(gs, buf);
-        fclose(err);
-      }
-    }
+    interpreter_failed (gs, buf);
     unlink(filename_unc);
     g_free(filename_unc);
     filename_unc = NULL;
@@ -1084,112 +857,100 @@ check_filecompressed(PSDocument * gs)
   return filename_unc;
 }
 
-#ifdef BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED
-/* never mind this patch: a properly working X server should take care of
-   calculating the proper values. */
-static float
-compute_xdpi(void)
-{
-#   ifndef HAVE_XINERAMA
-  return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
-#   else
-  Display *dpy;
-  dpy = (Display *) GDK_DISPLAY();
-  if(XineramaIsActive(dpy)) {
-    int num_heads;
-    XineramaScreenInfo *head_info;
-    head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads);
-    /* fake it with dimensions of the first head for now */
-    return 25.4 * head_info[0].width / gdk_screen_width_mm();
-  }
-  else {
-    return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
-  }
-#   endif
-  /* HAVE_XINERAMA */
-}
-
-static float
-compute_ydpi(void)
-{
-#   ifndef HAVE_XINERAMA
-  return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
-#   else
-  Display *dpy;
-  dpy = (Display *) GDK_DISPLAY();
-  if(XineramaIsActive(dpy)) {
-    int num_heads;
-    XineramaScreenInfo *head_info;
-    head_info = (XineramaScreenInfo *) XineramaQueryScreens(dpy, &num_heads);
-    /* fake it with dimensions of the first head for now */
-    return 25.4 * head_info[0].height / gdk_screen_height_mm();
-  }
-  else {
-    return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
-  }
-#   endif
-  /* HAVE_XINERAMA */
-}
-#else
-static float
-compute_xdpi(void)
-{
-  return 25.4 * gdk_screen_width() / gdk_screen_width_mm();
-}
-
-static float
-compute_ydpi(void)
+static void
+compute_dimensions (PSDocument *gs, int page)
 {
-  return 25.4 * gdk_screen_height() / gdk_screen_height_mm();
-}
-#endif /* BROKEN_XINERAMA_PATCH_THAT_SHOULD_NOT_BE_USED */
+       GtkGSPaperSize *paper_sizes = gtk_gs_defaults_get_paper_sizes ();
+       int urx, ury, llx, lly;
+       int width, height;
+       int orientation;
+
+       g_return_if_fail (PS_IS_DOCUMENT (gs));
+       g_return_if_fail (gs->doc != NULL);
+       g_return_if_fail (page >= 0);
+       g_return_if_fail (gs->doc->numpages > page);
+
+       orientation = GTK_GS_ORIENTATION_NONE;
+       if (gs->structured_doc) {
+               orientation = gs->doc->pages[gs->current_page].orientation;
+       }
+       if (orientation == GTK_GS_ORIENTATION_NONE) {
+               orientation = GTK_GS_ORIENTATION_PORTRAIT;
+       }
 
-/* Compute new size of window, sets xdpi and ydpi if necessary.
- * returns True if new window size is different */
-static gboolean
-compute_size(PSDocument * gs)
-{
-  guint new_width = 1;
-  guint new_height = 1;
-  gboolean change = FALSE;
-  gint orientation;
-
-  /* width and height can be changed, calculate window size according */
-  /* to xpdi and ydpi */
-  orientation = ps_document_get_orientation(gs);
-
-  switch (orientation) {
-  case GTK_GS_ORIENTATION_PORTRAIT:
-  case GTK_GS_ORIENTATION_UPSIDEDOWN:
-    new_width = (gs->urx - gs->llx) / 72.0 * gs->xdpi + 0.5;
-    new_height = (gs->ury - gs->lly) / 72.0 * gs->ydpi + 0.5;
-    break;
-  case GTK_GS_ORIENTATION_LANDSCAPE:
-  case GTK_GS_ORIENTATION_SEASCAPE:
-    new_width = (gs->ury - gs->lly) / 72.0 * gs->xdpi + 0.5;
-    new_height = (gs->urx - gs->llx) / 72.0 * gs->ydpi + 0.5;
-    break;
-  }
+       if (gs->doc->pages && gs->doc->pages[page].size) {
+               int page_size;
+
+               page_size = gs->doc->pages[page].size - gs->doc->size;
+               llx = lly = 0;
+               urx = gs->doc->size[page_size].width;
+               ury = gs->doc->size[page_size].height;
+       } else if (gs->doc->pages &&
+                   (gs->doc->pages[page].boundingbox[URX] >
+                    gs->doc->pages[page].boundingbox[LLX]) &&
+                   (gs->doc->pages[page].boundingbox[URY] >
+                    gs->doc->pages[page].boundingbox[LLY])) {
+               llx = gs->doc->pages[page].boundingbox[LLX];
+               lly = gs->doc->pages[page].boundingbox[LLY];
+               urx = gs->doc->pages[page].boundingbox[URX];
+               ury = gs->doc->pages[page].boundingbox[URY];
+       } else if ((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
+                   (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
+               llx = gs->doc->boundingbox[LLX];
+               lly = gs->doc->boundingbox[LLY];
+               urx = gs->doc->boundingbox[URX];
+               ury = gs->doc->boundingbox[URY];
+       } else {
+               /* Fallback to A4 */
+               llx = lly = 0;
+               urx = paper_sizes[12].width;
+               ury = paper_sizes[12].height;
+       }
 
-  change = (new_width != gs->width * gs->zoom_factor)
-    || (new_height != gs->height * gs->zoom_factor);
-  gs->width = (gint) (new_width * gs->zoom_factor);
-  gs->height = (gint) (new_height * gs->zoom_factor);
+       switch (orientation) {
+               case GTK_GS_ORIENTATION_PORTRAIT:
+               case GTK_GS_ORIENTATION_UPSIDEDOWN:
+                       width = (urx - llx) / 72.0 * get_xdpi (gs) + 0.5;
+                       height = (ury - lly) / 72.0 * get_ydpi (gs) + 0.5;
+                       break;
+               case GTK_GS_ORIENTATION_LANDSCAPE:
+               case GTK_GS_ORIENTATION_SEASCAPE:
+                       width = (ury - lly) / 72.0 * get_xdpi (gs) + 0.5;
+                       height = (urx - llx) / 72.0 * get_ydpi (gs) + 0.5;
+                       break;
+               default:
+                       width = height = 0;
+                       g_assert_not_reached ();
+                       break;
+       }
 
-  return (change);
+       width = width * gs->zoom_factor;
+       height = height * gs->zoom_factor;
+
+       if (llx != gs->llx || lly != gs->lly ||
+           urx != gs->urx || ury != gs->ury ||
+           gs->width != width || gs->height != height ||
+           orientation != gs->orientation) {
+               gs->llx = llx;
+               gs->lly = lly;
+               gs->urx = urx;
+               gs->ury = ury;
+               gs->width = width;
+               gs->height = height;
+               gs->orientation = orientation;
+               gs->changed = TRUE;
+       }
 }
 
 static gint
 ps_document_enable_interpreter(PSDocument * gs)
 {
   g_return_val_if_fail(gs != NULL, FALSE);
-  g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
+  g_return_val_if_fail(PS_IS_DOCUMENT(gs), FALSE);
 
   if(!gs->gs_filename)
     return 0;
 
-  gs->disable_start = FALSE;
-  
   return start_interpreter(gs);
 }
 
@@ -1231,24 +992,11 @@ ps_document_get_type(void)
 
 }
 
-/*
- * Show error message -> send signal "interpreter_message"
- */
-static void
-ps_document_emit_error_msg(PSDocument * gs, const gchar * msg)
-{
-  gdk_pointer_ungrab(GDK_CURRENT_TIME);
-  if(strstr(msg, "Error:")) {
-    gs->gs_status = _("File is not a valid PostScript document.");
-    ps_document_cleanup(gs);
-  }
-}
-
 static gboolean
 document_load(PSDocument * gs, const gchar * fname)
 {
   g_return_val_if_fail(gs != NULL, FALSE);
-  g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
+  g_return_val_if_fail(PS_IS_DOCUMENT(gs), FALSE);
 
   LOG ("Load the document");
 
@@ -1261,8 +1009,6 @@ document_load(PSDocument * gs, const gchar * fname)
   }
 
   /* prepare this document */
-
-  /* default values: no dsc information available  */
   gs->structured_doc = FALSE;
   gs->send_filename_to_gs = TRUE;
   gs->current_page = 0;
@@ -1291,7 +1037,7 @@ document_load(PSDocument * gs, const gchar * fname)
     if(!file_readable(fname)) {
       gchar buf[1024];
       g_snprintf(buf, 1024, _("Cannot open file %s.\n"), fname);
-      ps_document_emit_error_msg(gs, buf);
+      interpreter_failed (gs, buf);
       gs->gs_status = _("File is not readable.");
     }
     else {
@@ -1299,12 +1045,13 @@ document_load(PSDocument * gs, const gchar * fname)
     }
 
     if(!filename || (gs->gs_psfile = fopen(filename, "r")) == NULL) {
+      interpreter_failed (gs, NULL);
       ps_document_cleanup(gs);
       return FALSE;
     }
 
     /* we grab the vital statistics!!! */
-    gs->doc = psscan(gs->gs_psfile, gs->respect_eof, filename);
+    gs->doc = psscan(gs->gs_psfile, TRUE, filename);
 
     g_object_notify (G_OBJECT (gs), "title");
 
@@ -1312,7 +1059,7 @@ document_load(PSDocument * gs, const gchar * fname)
       /* File does not seem to be a Postscript one */
       gchar buf[1024];
       g_snprintf(buf, 1024, _("Error while scanning file %s\n"), fname);
-      ps_document_emit_error_msg(gs, buf);
+      interpreter_failed (gs, buf);
       ps_document_cleanup(gs);
       gs->gs_status = _("The file is not a PostScript document.");
       return FALSE;
@@ -1323,12 +1070,9 @@ document_load(PSDocument * gs, const gchar * fname)
       gs->structured_doc = TRUE;
       gs->send_filename_to_gs = FALSE;
     }
-
-    /* We have to set up the orientation of the document */
-    gs->real_orientation = gs->doc->orientation;
   }
-  ps_document_set_page_size(gs, -1, gs->current_page);
   gs->loaded = TRUE;
+  compute_dimensions (gs, gs->current_page);
 
   gs->gs_status = _("Document loaded.");
 
@@ -1337,246 +1081,75 @@ document_load(PSDocument * gs, const gchar * fname)
 
 
 static gboolean
-ps_document_next_page(PSDocument * gs)
+ps_document_next_page (PSDocument *gs)
 {
-  XEvent event;
-
-  LOG ("Make ghostscript render next page");
-
-  g_return_val_if_fail(gs != NULL, FALSE);
-  g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
-
-  if(gs->interpreter_pid == 0) {    /* no interpreter active */
-    return FALSE;
-  }
-
-  if(gs->busy) {                /* interpreter is busy */
-    return FALSE;
-  }
-
-  gs->busy = TRUE;
-
-  event.xclient.type = ClientMessage;
-  event.xclient.display = gdk_display;
-  event.xclient.window = gs->message_window;
-  event.xclient.message_type = gdk_x11_atom_to_xatom(gs_class->next_atom);
-  event.xclient.format = 32;
-
-  gdk_error_trap_push();
-  XSendEvent(gdk_display, gs->message_window, FALSE, 0, &event);
-  gdk_flush();
-  gdk_error_trap_pop();
-
-  return TRUE;
-}
-
-static gboolean
-ps_document_goto_page(PSDocument * gs, gint page)
-{
-  g_return_val_if_fail(gs != NULL, FALSE);
-  g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
-
-  LOG ("Go to page %d", page);
-
-  if(!gs->gs_filename) {
-    return FALSE;
-  }
-
-  /* range checking... */
-  if(page < 0)
-    page = 0;
-
-  if(gs->structured_doc && gs->doc) {
-
-    LOG ("It's a structured document, let's send one page to gs");
-
-    if(page >= gs->doc->numpages)
-      page = gs->doc->numpages - 1;
-
-    if(page == gs->current_page && !gs->changed)
-      return TRUE;
-
-    gs->current_page = page;
-
-    if(gs->doc->pages[page].orientation != NONE &&
-       gs->doc->pages[page].orientation != gs->real_orientation) {
-      gs->real_orientation = gs->doc->pages[page].orientation;
-      gs->changed = TRUE;
-    }
-
-    ps_document_set_page_size(gs, -1, page);
+       XEvent event;
 
-    gs->changed = FALSE;
+       LOG ("Make ghostscript render next page");
 
-    if(is_interpreter_ready(gs)) {
-      ps_document_next_page(gs);
-    }
-    else {
-      ps_document_enable_interpreter(gs);
-      send_ps(gs, gs->doc->beginprolog, gs->doc->lenprolog, FALSE);
-      send_ps(gs, gs->doc->beginsetup, gs->doc->lensetup, FALSE);
-    }
+       g_return_val_if_fail (PS_IS_DOCUMENT(gs), FALSE);
+       g_return_val_if_fail (gs->interpreter_pid != 0, FALSE);
+       g_return_val_if_fail (gs->busy != TRUE, FALSE);
 
-    send_ps(gs, gs->doc->pages[gs->current_page].begin,
-            gs->doc->pages[gs->current_page].len, FALSE);
-  }
-  else {
-    /* Unstructured document */
-    /* In the case of non structured documents,
-       GS read the PS from the  actual file (via command
-       line. Hence, ggv only send a signal next page.
-       If ghostview is not running it is usually because
-       the last page of the file was displayed. In that
-       case, ggv restarts GS again and the first page is displayed.
-     */
+       gs->busy = TRUE;
 
-    LOG ("It's an unstructured document, gs will just read the file");
+       event.xclient.type = ClientMessage;
+       event.xclient.display = gdk_display;
+       event.xclient.window = gs->message_window;
+       event.xclient.message_type = gdk_x11_atom_to_xatom(gs_class->next_atom);
+       event.xclient.format = 32;
 
-    if(page == gs->current_page && !gs->changed)
-      return TRUE;
+       gdk_error_trap_push ();
+       XSendEvent (gdk_display, gs->message_window, FALSE, 0, &event);
+       gdk_flush ();
+       gdk_error_trap_pop ();
 
-    ps_document_set_page_size(gs, -1, page);
-
-    if(!is_interpreter_ready(gs))
-      ps_document_enable_interpreter(gs);
-
-    gs->current_page = page;
-
-    ps_document_next_page(gs);
-  }
-  return TRUE;
+       return TRUE;
 }
 
-/*
- * set pagesize sets the size from
- * if new_pagesize is -1, then it is set to either
- *  a) the default settings of pageid, if they exist, or if pageid != -1.
- *  b) the default setting of the document, if it exists.
- *  c) the default setting of the widget.
- * otherwise, the new_pagesize is used as the pagesize
- */
 static gboolean
-ps_document_set_page_size(PSDocument * gs, gint new_pagesize, gint pageid)
+render_page (PSDocument *gs)
 {
-  gint new_llx = 0;
-  gint new_lly = 0;
-  gint new_urx = 0;
-  gint new_ury = 0;
-  GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes();
-
-  LOG ("Set the page size");
-
-  g_return_val_if_fail(gs != NULL, FALSE);
-  g_return_val_if_fail(GTK_IS_GS(gs), FALSE);
-
-  if(new_pagesize == -1) {
-    if(gs->default_size > 0)
-      new_pagesize = gs->default_size;
-    if(gs->doc) {
-      /* If we have a document:
-         We use -- the page size (if specified)
-         or the doc. size (if specified)
-         or the page bbox (if specified)
-         or the bounding box
-       */
-      if((pageid >= 0) && (gs->doc->numpages > pageid) &&
-         (gs->doc->pages) && (gs->doc->pages[pageid].size)) {
-        new_pagesize = gs->doc->pages[pageid].size - gs->doc->size;
-      }
-      else if(gs->doc->default_page_size != NULL) {
-        new_pagesize = gs->doc->default_page_size - gs->doc->size;
-      }
-      else if((pageid >= 0) &&
-              (gs->doc->numpages > pageid) &&
-              (gs->doc->pages) &&
-              (gs->doc->pages[pageid].boundingbox[URX] >
-               gs->doc->pages[pageid].boundingbox[LLX]) &&
-              (gs->doc->pages[pageid].boundingbox[URY] >
-               gs->doc->pages[pageid].boundingbox[LLY])) {
-        new_pagesize = -1;
-      }
-      else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
-              (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
-        new_pagesize = -1;
-      }
-    }
-  }
+       g_return_val_if_fail(gs != NULL, FALSE);
+       g_return_val_if_fail(PS_IS_DOCUMENT(gs), FALSE);
 
-  /* Compute bounding box */
-  if(gs->doc && (gs->doc->epsf || new_pagesize == -1)) {    /* epsf or bbox */
-    if((pageid >= 0) &&
-       (gs->doc->pages) &&
-       (gs->doc->pages[pageid].boundingbox[URX] >
-        gs->doc->pages[pageid].boundingbox[LLX])
-       && (gs->doc->pages[pageid].boundingbox[URY] >
-           gs->doc->pages[pageid].boundingbox[LLY])) {
-      /* use page bbox */
-      new_llx = gs->doc->pages[pageid].boundingbox[LLX];
-      new_lly = gs->doc->pages[pageid].boundingbox[LLY];
-      new_urx = gs->doc->pages[pageid].boundingbox[URX];
-      new_ury = gs->doc->pages[pageid].boundingbox[URY];
-    }
-    else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) &&
-            (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) {
-      /* use doc bbox */
-      new_llx = gs->doc->boundingbox[LLX];
-      new_lly = gs->doc->boundingbox[LLY];
-      new_urx = gs->doc->boundingbox[URX];
-      new_ury = gs->doc->boundingbox[URY];
-    }
-  }
-  else {
-    if(new_pagesize < 0)
-      new_pagesize = gs->default_size;
-    new_llx = new_lly = 0;
-    if(gs->doc && gs->doc->size &&
-       (new_pagesize < gs->doc->numsizes)) {
-      new_urx = gs->doc->size[new_pagesize].width;
-      new_ury = gs->doc->size[new_pagesize].height;
-    }
-    else {
-      new_urx = papersizes[new_pagesize].width;
-      new_ury = papersizes[new_pagesize].height;
-    }
-  }
-
-  if(new_urx <= new_llx)
-    new_urx = papersizes[12].width;
-  if(new_ury <= new_lly)
-    new_ury = papersizes[12].height;
-
-  /* If bounding box changed, setup for new size. */
-  /* ps_document_disable_interpreter (gs); */
-  if((new_llx != gs->llx) || (new_lly != gs->lly) ||
-     (new_urx != gs->urx) || (new_ury != gs->ury)) {
-    gs->llx = new_llx;
-    gs->lly = new_lly;
-    gs->urx = new_urx;
-    gs->ury = new_ury;
-    gs->changed = TRUE;
-  }
-
-  if(gs->changed) {
-    set_up_page(gs);
-    return TRUE;
-  }
+       if(!gs->gs_filename) {
+               return FALSE;
+       }
 
-  return FALSE;
-}
+       if (gs->structured_doc && gs->doc) {
+               LOG ("It's a structured document, let's send one page to gs");
 
-static void
-ps_document_set_zoom (PSDocument * gs, gfloat zoom)
-{
-       g_return_if_fail (gs != NULL);
-
-       gs->zoom_factor = zoom;
+               if (is_interpreter_ready (gs)) {
+                       ps_document_next_page (gs);
+               } else {
+                       ps_document_enable_interpreter (gs);
+                       send_ps (gs, gs->doc->beginprolog, gs->doc->lenprolog, FALSE);
+                       send_ps (gs, gs->doc->beginsetup, gs->doc->lensetup, FALSE);
+               }
 
-       if (gs->pstarget != NULL) {
-               set_up_page(gs);
-               gs->changed = TRUE;
-               gs->scaling = TRUE;
-               ps_document_goto_page (gs, gs->current_page);
+               send_ps (gs, gs->doc->pages[gs->current_page].begin,
+                        gs->doc->pages[gs->current_page].len, FALSE);
+       } else {
+               /* Unstructured document
+                *
+                * In the case of non structured documents,
+                * GS read the PS from the  actual file (via command
+                * line. Hence, ggv only send a signal next page.
+                * If ghostview is not running it is usually because
+                * the last page of the file was displayed. In that
+                * case, ggv restarts GS again and the first page is displayed.
+                */
+
+               LOG ("It's an unstructured document, gs will just read the file");
+
+               if (!is_interpreter_ready (gs)) {
+                       ps_document_enable_interpreter(gs);
+               }
+               ps_document_next_page(gs);
        }
+
+       return TRUE;
 }
 
 static gboolean
@@ -1631,7 +1204,12 @@ static void
 ps_document_set_page (EvDocument  *document,
                       int          page)
 {
-       ps_document_goto_page (PS_DOCUMENT (document), page - 1);
+       PSDocument *gs = PS_DOCUMENT (document);
+
+       LOG ("Set document page %d\n", page);
+
+       gs->current_page = page - 1;
+       compute_dimensions (gs, page);
 }
 
 static int
@@ -1648,7 +1226,10 @@ static void
 ps_document_set_scale (EvDocument  *document,
                        double       scale)
 {
-       ps_document_set_zoom (PS_DOCUMENT (document), scale);
+       PSDocument *gs = PS_DOCUMENT (document);
+
+       gs->zoom_factor = scale;
+       compute_dimensions (gs, gs->current_page);
 }
 
 static void
@@ -1681,48 +1262,6 @@ ps_document_get_page_size (EvDocument   *document,
        }
 }
 
-static void
-ps_document_render (EvDocument  *document,
-                   int          clip_x,
-                   int          clip_y,
-                   int          clip_width,
-                   int          clip_height)
-{
-       PSDocument *gs = PS_DOCUMENT (document);
-       GdkRectangle page;
-       GdkRectangle draw;
-       GdkGC *gc;
-
-       if (gs->pstarget == NULL ||
-           gs->bpixmap == NULL) {
-               return;
-       }
-
-       page.x = gs->page_x_offset;
-       page.y = gs->page_y_offset;
-       page.width = gs->width;
-       page.height = gs->height;
-
-       draw.x = clip_x;
-       draw.y = clip_y;
-       draw.width = clip_width;
-       draw.height = clip_height;
-
-       gc = gdk_gc_new (gs->pstarget);
-
-       gdk_draw_drawable (gs->pstarget, gc,
-                          gs->bpixmap,
-                          draw.x - page.x, draw.y - page.y,
-                          draw.x, draw.y,
-                          draw.width, draw.height);
-
-       LOG ("Copy the internal pixmap: %d %d %d %d %d %d",
-             draw.x - page.x, draw.y - page.y,
-             draw.x, draw.y, draw.width, draw.height);
-
-       g_object_unref (gc);
-}
-
 static char *
 ps_document_get_text (EvDocument *document, GdkRectangle *rect)
 {
@@ -1738,6 +1277,56 @@ ps_document_get_link (EvDocument *document,
        return NULL;
 }
 
+static gboolean
+render_pixbuf_idle (EvDocument *document)
+{
+       PSDocument *gs = PS_DOCUMENT (document);
+
+       if (gs->pstarget == NULL) {
+               GtkWidget *widget;
+
+               widget = gtk_window_new (GTK_WINDOW_POPUP);
+               gtk_widget_realize (widget);
+               gs->pstarget = widget->window;
+
+               g_assert (gs->pstarget != NULL);
+
+               g_signal_connect (widget, "event",
+                                 G_CALLBACK (ps_document_widget_event),
+                                 gs);
+       }
+
+       if (gs->changed) {
+               stop_interpreter (gs);
+               setup_pixmap (gs);
+               setup_page (gs);
+               gs->changed = FALSE;
+       }
+
+       render_page (PS_DOCUMENT (document));
+
+       return FALSE;
+}
+
+static GdkPixbuf *
+ps_document_render_pixbuf (EvDocument *document)
+{
+       GdkPixbuf *pixbuf;
+
+       g_idle_add ((GSourceFunc)render_pixbuf_idle, document);
+
+       g_mutex_lock (pixbuf_mutex);
+       while (!current_pixbuf)
+               g_cond_wait (pixbuf_cond, pixbuf_mutex);
+       pixbuf = current_pixbuf;
+       current_pixbuf = NULL;
+       g_mutex_unlock (pixbuf_mutex);
+
+       LOG ("Pixbuf rendered %p\n", pixbuf);
+
+       return pixbuf;
+}
+
 static void
 ps_document_document_iface_init (EvDocumentIface *iface)
 {
@@ -1749,8 +1338,7 @@ 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_target = ps_document_set_target;
        iface->set_page_offset = ps_document_set_page_offset;
        iface->get_page_size = ps_document_get_page_size;
-       iface->render = ps_document_render;
+       iface->render_pixbuf = ps_document_render_pixbuf;
 }
index f7c8e92d6be94c0f7f1cc16ec602ed9c2857d831..1c6761bd6db21d85f0cf54b2d76942205301f676 100644 (file)
@@ -35,23 +35,18 @@ G_BEGIN_DECLS
 #define PS_TYPE_DOCUMENT         (ps_document_get_type())
 #define PS_DOCUMENT(obj)         GTK_CHECK_CAST (obj, ps_document_get_type (), PSDocument)
 #define PS_DOCUMENT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, ps_document_get_type (), PSDocumentClass)
-#define GTK_IS_GS(obj)           GTK_CHECK_TYPE (obj, ps_document_get_type())
+#define PS_IS_DOCUMENT(obj)      GTK_CHECK_TYPE (obj, ps_document_get_type())
 
 typedef struct _PSDocument PSDocument;
 typedef struct _PSDocumentClass PSDocumentClass;
 
 struct _PSDocument {
   GObject object;
-  GdkWindow *pstarget;          /* the window passed to gv
-                                 * it is a child of widget...
-                                 */
-  GdkGC *psgc;
-
-  GdkPixmap *bpixmap;           /* Backing pixmap */
 
+  GdkWindow *pstarget;
+  GdkPixmap *bpixmap;
   long message_window;          /* Used by ghostview to receive messages from app */
 
-  int disable_start;            /* Can the interpreter be started? */
   pid_t interpreter_pid;        /* PID of interpreter, -1 if none  */
   int interpreter_input;        /* stdin of interpreter            */
   int interpreter_output;       /* stdout of interpreter           */
@@ -60,22 +55,19 @@ struct _PSDocument {
   guint interpreter_output_id;
   guint interpreter_error_id;
 
+  gint width;                   /* Size of window at last setup()  */
   gint llx;
   gint lly;
   gint urx;
   gint ury;
-  gint left_margin;
-  gint right_margin;
-  gint top_margin;
-  gint bottom_margin;
-  gint width;                   /* Size of window at last setup()  */
   gint height;
+  gint orientation;
   gboolean busy;                /* Is gs busy drawing? */
-  gboolean changed;             /* Anything changed since setup */
   gfloat zoom_factor;
   gint current_page;
   gboolean structured_doc;
   gboolean loaded;
+  gboolean changed;
 
   struct record_list *ps_input;
   gchar *input_buffer_ptr;
@@ -84,30 +76,16 @@ struct _PSDocument {
 
   FILE *gs_psfile;              /* the currently loaded FILE */
   gchar *gs_filename;           /* the currently loaded filename */
-  gchar *gs_filename_dsc;       /* Used to browse PDF to PS */
   gchar *gs_filename_unc;       /* Uncompressed file */
   gchar *input_buffer;
-  gint gs_scanstyle;
   gboolean send_filename_to_gs; /* True if gs should read from file directly */
   gboolean reading_from_pipe;   /* True if ggv is reading input from pipe */
   struct document *doc;
 
-  /* User selected options... */
-  gboolean antialiased;         /* Using antialiased display */
-  gboolean respect_eof;         /* respect EOF comments? */
-  gint default_size;
-  gfloat xdpi, ydpi;
-  gint fallback_orientation;    /* Orientation to use if override */
-  gint real_orientation;        /* Real orientation from the document */
-
   const gchar *gs_status;       /* PSDocument status */
 
-  guint avail_w, avail_h;
-
   int page_x_offset;
   int page_y_offset;
-
-  gboolean scaling;
 };
 
 struct _PSDocumentClass {
index 0ae09583b0e319dbd6bf4fa6aebac595268beecd..a14f2a03d36530ab094971df0d879109939e20c3 100644 (file)
@@ -29,6 +29,8 @@ evince_SOURCES=                               \
        ev-password.c                   \
        ev-password-view.h              \
        ev-password-view.c              \
+       ev-pixbuf-cache.c               \
+       ev-pixbuf-cache.h               \
        ev-print-job.c                  \
        ev-print-job.h                  \
        ev-utils.c                      \
diff --git a/shell/ev-pixbuf-cache.c b/shell/ev-pixbuf-cache.c
new file mode 100644 (file)
index 0000000..7d076db
--- /dev/null
@@ -0,0 +1,525 @@
+#include "ev-pixbuf-cache.h"
+#include "ev-job-queue.h"
+
+
+typedef struct _CacheJobInfo
+{
+       EvJob *job;
+       GdkPixbuf *pixbuf;
+} CacheJobInfo;
+
+struct _EvPixbufCache
+{
+       GObject parent;
+
+       EvDocument  *document;
+       int start_page;
+       int end_page;
+
+       /* preload_cache_size is the number of pages prior to the current
+        * visible area that we cache.  It's normally 1, but could be 2 in the
+        * case of twin pages.
+        */
+       int preload_cache_size;
+       CacheJobInfo *prev_job;
+       CacheJobInfo *job_list;
+       CacheJobInfo *next_job;
+};
+
+struct _EvPixbufCacheClass
+{
+       GObjectClass parent_class;
+
+       void (* job_finished) (EvPixbufCache *pixbuf_cache);
+};
+
+
+enum
+{
+       JOB_FINISHED,
+       N_SIGNALS,
+};
+
+static guint signals[N_SIGNALS] = {0, };
+
+static void          ev_pixbuf_cache_init       (EvPixbufCache      *pixbuf_cache);
+static void          ev_pixbuf_cache_class_init (EvPixbufCacheClass *pixbuf_cache);
+static void          ev_pixbuf_cache_finalize   (GObject            *object);
+static void          ev_pixbuf_cache_dispose    (GObject            *object);
+static void          job_finished_cb            (EvJob              *job,
+                                                EvPixbufCache      *pixbuf_cache);
+static CacheJobInfo *find_job_cache             (EvPixbufCache      *pixbuf_cache,
+                                                int                 page);
+
+
+
+/* These are used for iterating through the prev and next arrays */
+#define FIRST_VISABLE_PREV(pixbuf_cache) \
+       (MAX (0, pixbuf_cache->preload_cache_size + 1 - pixbuf_cache->start_page))
+#define VISIBLE_NEXT_LEN(pixbuf_cache, page_cache) \
+       (MIN(pixbuf_cache->preload_cache_size, ev_page_cache_get_n_pages (page_cache) - pixbuf_cache->end_page))
+#define PAGE_CACHE_LEN(pixbuf_cache) \
+       ((pixbuf_cache->end_page - pixbuf_cache->start_page) + 1)
+
+G_DEFINE_TYPE (EvPixbufCache, ev_pixbuf_cache, G_TYPE_OBJECT)
+
+static void
+ev_pixbuf_cache_init (EvPixbufCache *pixbuf_cache)
+{
+       pixbuf_cache->start_page = 1;
+       pixbuf_cache->end_page = 1;
+       pixbuf_cache->job_list = g_new0 (CacheJobInfo, PAGE_CACHE_LEN (pixbuf_cache));
+
+       pixbuf_cache->preload_cache_size = 1;
+       pixbuf_cache->prev_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size);
+       pixbuf_cache->next_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size);
+}
+
+static void
+ev_pixbuf_cache_class_init (EvPixbufCacheClass *class)
+{
+       GObjectClass *object_class;
+
+       object_class = G_OBJECT_CLASS (class);
+
+       object_class->finalize = ev_pixbuf_cache_finalize;
+       object_class->dispose = ev_pixbuf_cache_dispose;
+
+       signals[JOB_FINISHED] = g_signal_new ("job-finished",
+                                           G_OBJECT_CLASS_TYPE (object_class),
+                                           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                                           G_STRUCT_OFFSET (EvPixbufCacheClass, job_finished),
+                                           NULL, NULL,
+                                           g_cclosure_marshal_VOID__VOID,
+                                           G_TYPE_NONE, 0);
+}
+
+static void
+ev_pixbuf_cache_finalize (GObject *object)
+{
+       EvPixbufCache *pixbuf_cache;
+
+       pixbuf_cache = EV_PIXBUF_CACHE (object);
+
+       g_free (pixbuf_cache->prev_job);
+       g_free (pixbuf_cache->job_list);
+       g_free (pixbuf_cache->next_job);
+}
+
+static void
+dispose_cache_job_info (CacheJobInfo *job_info,
+                       gpointer      data)
+{
+       if (job_info == NULL)
+               return;
+       if (job_info->job) {
+               g_signal_handlers_disconnect_by_func (job_info->job,
+                                                     G_CALLBACK (job_finished_cb),
+                                                     data);
+               g_object_unref (G_OBJECT (job_info->job));
+               job_info->job = NULL;
+       }
+       if (job_info->pixbuf) {
+               g_object_unref (G_OBJECT (job_info->pixbuf));
+               job_info->pixbuf = NULL;
+       }
+}
+
+static void
+ev_pixbuf_cache_dispose (GObject *object)
+{
+       EvPixbufCache *pixbuf_cache;
+       int i;
+
+       pixbuf_cache = EV_PIXBUF_CACHE (object);
+
+       for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
+               dispose_cache_job_info (pixbuf_cache->prev_job + i, pixbuf_cache);
+               dispose_cache_job_info (pixbuf_cache->next_job + i, pixbuf_cache);
+       }
+
+       for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
+               dispose_cache_job_info (pixbuf_cache->job_list + i, pixbuf_cache);
+       }
+}
+
+
+EvPixbufCache *
+ev_pixbuf_cache_new (EvDocument *document)
+{
+       EvPixbufCache *pixbuf_cache;
+
+       pixbuf_cache = (EvPixbufCache *) g_object_new (EV_TYPE_PIXBUF_CACHE, NULL);
+       pixbuf_cache->document = document;
+
+       return pixbuf_cache;
+}
+
+static void
+job_finished_cb (EvJob         *job,
+                EvPixbufCache *pixbuf_cache)
+{
+       CacheJobInfo *job_info;
+       EvJobRender *job_render = EV_JOB_RENDER (job);
+       GdkPixbuf *pixbuf;
+
+       /* If the job is outside of our interest, we silently discard it */
+       if ((job_render->page < (pixbuf_cache->start_page - pixbuf_cache->preload_cache_size)) ||
+           (job_render->page > (pixbuf_cache->end_page + pixbuf_cache->preload_cache_size))) {
+               g_object_unref (job);
+               return;
+       }
+       
+       job_info = find_job_cache (pixbuf_cache, job_render->page);
+
+       pixbuf = g_object_ref (job_render->pixbuf);
+       if (job_info->pixbuf)
+               g_object_unref (job_info->pixbuf);
+       job_info->pixbuf = pixbuf;
+
+       if (job_info->job == job)
+               job_info->job = NULL;
+       g_object_unref (job);
+
+       g_signal_emit (pixbuf_cache, signals[JOB_FINISHED], 0);
+}
+
+/* This checks a job to see if the job would generate the right sized pixbuf
+ * given a scale.  If it won't, it removes the job and clears it to NULL.
+ */
+static void
+check_job_size_and_unref (CacheJobInfo *job_info,
+                         EvPageCache  *page_cache,
+                         gfloat        scale)
+{
+       gint width;
+       gint height;
+
+       g_assert (job_info);
+
+       if (job_info->job == NULL)
+               return;
+
+       ev_page_cache_get_size (page_cache,
+                               EV_JOB_RENDER (job_info->job)->page,
+                               scale,
+                               &width, &height);
+                               
+       if (width == EV_JOB_RENDER (job_info->job)->target_width &&
+           height == EV_JOB_RENDER (job_info->job)->target_height)
+               return;
+
+       /* Try to remove the job.  If we can't, then the thread has already
+        * picked it up and we are going get a signal when it's done.  If we
+        * can, then the job is fully dead and will never rnu.. */
+       if (ev_job_queue_remove_job (job_info->job))
+               g_object_unref (job_info->job);
+
+       job_info->job = NULL;
+}
+
+/* Do all function that copies a job from an older cache to it's position in the
+ * new cache.  It clears the old job if it doesn't have a place.
+ */
+static void
+move_one_job (CacheJobInfo  *job_info,
+             EvPixbufCache *pixbuf_cache,
+             int            page,
+             CacheJobInfo  *new_job_list,
+             CacheJobInfo  *new_prev_job,
+             CacheJobInfo  *new_next_job,
+             int            start_page,
+             int            end_page,
+             EvJobPriority  priority)
+{
+       CacheJobInfo *target_page = NULL;
+       int page_offset;
+       EvJobPriority new_priority;
+
+       if (page < (start_page - pixbuf_cache->preload_cache_size) ||
+           page > (end_page + pixbuf_cache->preload_cache_size)) {
+               dispose_cache_job_info (job_info, pixbuf_cache);
+               return;
+       }
+
+       /* find the target page to copy it over to. */
+       if (page < start_page) {
+               page_offset = (page - (start_page - pixbuf_cache->preload_cache_size));
+
+               g_assert (page_offset >= 0 &&
+                         page_offset < pixbuf_cache->preload_cache_size);
+               target_page = new_prev_job + page_offset;
+               new_priority = EV_JOB_PRIORITY_LOW;
+       } else if (page > end_page) {
+               page_offset = (page - (end_page + 1));
+
+               g_assert (page_offset >= 0 &&
+                         page_offset < pixbuf_cache->preload_cache_size);
+               target_page = new_next_job + page_offset;
+               new_priority = EV_JOB_PRIORITY_LOW;
+       } else {
+               page_offset = page - start_page;
+               g_assert (page_offset >= 0 &&
+                         page_offset <= ((end_page - start_page) + 1));
+               new_priority = EV_JOB_PRIORITY_HIGH;
+               target_page = new_job_list + page_offset;
+       }
+
+       *target_page = *job_info;
+       job_info->job = NULL;
+       job_info->pixbuf = NULL;
+
+       if (new_priority != priority && target_page->job) {
+               g_print ("FIXME: update priority \n");
+       }
+}
+
+
+
+static void
+ev_pixbuf_cache_update_range (EvPixbufCache *pixbuf_cache,
+                             gint           start_page,
+                             gint           end_page)
+{
+       CacheJobInfo *new_job_list;
+       CacheJobInfo *new_prev_job;
+       CacheJobInfo *new_next_job;
+       EvPageCache *page_cache;
+       int i, page;
+
+       if (pixbuf_cache->start_page == start_page &&
+           pixbuf_cache->end_page == end_page)
+               return;
+
+       page_cache = ev_document_get_page_cache (pixbuf_cache->document);
+
+       new_job_list = g_new0 (CacheJobInfo, (end_page - start_page) + 1);
+       new_prev_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size);
+       new_next_job = g_new0 (CacheJobInfo, pixbuf_cache->preload_cache_size);
+
+       /* We go through each job in the old cache and either clear it or move
+        * it to a new location. */
+
+       /* Start with the prev cache. */
+       page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size;
+       for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
+               if (page < 1) {
+                       dispose_cache_job_info (pixbuf_cache->prev_job + i, pixbuf_cache);
+               } else {
+                       move_one_job (pixbuf_cache->prev_job + i,
+                                     pixbuf_cache, page,
+                                     new_job_list, new_prev_job, new_next_job,
+                                     start_page, end_page, EV_JOB_PRIORITY_LOW);
+               }
+               page ++;
+       }
+
+       page = pixbuf_cache->start_page;
+       for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
+               move_one_job (pixbuf_cache->job_list + i,
+                             pixbuf_cache, page,
+                             new_job_list, new_prev_job, new_next_job,
+                             start_page, end_page, EV_JOB_PRIORITY_HIGH);
+               page++;
+       }
+
+       for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
+               if (page > ev_page_cache_get_n_pages (page_cache)) {
+                       dispose_cache_job_info (pixbuf_cache->next_job + i, pixbuf_cache);
+               } else {
+                       move_one_job (pixbuf_cache->next_job + i,
+                                     pixbuf_cache, page,
+                                     new_job_list, new_prev_job, new_next_job,
+                                     start_page, end_page, EV_JOB_PRIORITY_LOW);
+               }
+               page ++;
+       }
+
+       g_free (pixbuf_cache->job_list);
+       g_free (pixbuf_cache->prev_job);
+       g_free (pixbuf_cache->next_job);
+
+       pixbuf_cache->job_list = new_job_list;
+       pixbuf_cache->prev_job = new_prev_job;
+       pixbuf_cache->next_job = new_next_job;
+
+       pixbuf_cache->start_page = start_page;
+       pixbuf_cache->end_page = end_page;
+}
+
+static CacheJobInfo *
+find_job_cache (EvPixbufCache *pixbuf_cache,
+               int            page)
+{
+       int page_offset;
+
+       if (page < (pixbuf_cache->start_page - pixbuf_cache->preload_cache_size) ||
+           page > (pixbuf_cache->end_page + pixbuf_cache->preload_cache_size))
+               return NULL;
+
+       if (page < pixbuf_cache->start_page) {
+               page_offset = (page - (pixbuf_cache->start_page - pixbuf_cache->preload_cache_size));
+
+               g_assert (page_offset >= 0 &&
+                         page_offset < pixbuf_cache->preload_cache_size);
+               return pixbuf_cache->prev_job + page_offset;
+       }
+
+       if (page > pixbuf_cache->end_page) {
+               page_offset = (page - (pixbuf_cache->end_page + 1));
+
+               g_assert (page_offset >= 0 &&
+                         page_offset < pixbuf_cache->preload_cache_size);
+               return pixbuf_cache->next_job + page_offset;
+       }
+
+       page_offset = page - pixbuf_cache->start_page;
+       g_assert (page_offset >= 0 &&
+                 page_offset <= PAGE_CACHE_LEN(pixbuf_cache));
+       return pixbuf_cache->job_list + page_offset;
+}
+
+static void
+ev_pixbuf_cache_clear_job_sizes (EvPixbufCache *pixbuf_cache,
+                                gfloat         scale)
+{
+       EvPageCache *page_cache;
+       int i;
+
+       page_cache = ev_document_get_page_cache (pixbuf_cache->document);
+
+       for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
+               check_job_size_and_unref (pixbuf_cache->job_list + i, page_cache, scale);
+       }
+
+       for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
+               check_job_size_and_unref (pixbuf_cache->prev_job + i, page_cache, scale);
+               check_job_size_and_unref (pixbuf_cache->next_job + i, page_cache, scale);
+       }
+}
+
+#define FIRST_VISABLE_PREV(pixbuf_cache) \
+       (MAX (0, pixbuf_cache->preload_cache_size + 1 - pixbuf_cache->start_page))
+
+static void
+add_job_if_needed (EvPixbufCache *pixbuf_cache,
+                  CacheJobInfo  *job_info,
+                  EvPageCache   *page_cache,
+                  gint           page,
+                  gfloat         scale,
+                  EvJobPriority  priority)
+{
+       int width, height;
+
+       if (job_info->job)
+               return;
+
+       ev_page_cache_get_size (page_cache,
+                               page, scale,
+                               &width, &height);
+
+       if (job_info->pixbuf &&
+           gdk_pixbuf_get_width (job_info->pixbuf) == width &&
+           gdk_pixbuf_get_height (job_info->pixbuf) == height)
+               return;
+
+       /* make a new job now */
+       job_info->job = ev_job_render_new (pixbuf_cache->document,
+                                          page, scale,
+                                          width, height);
+       ev_job_queue_add_job (job_info->job, priority);
+       g_signal_connect (job_info->job, "finished", G_CALLBACK (job_finished_cb), pixbuf_cache);
+}
+
+
+static void
+ev_pixbuf_cache_add_jobs_if_needed (EvPixbufCache *pixbuf_cache,
+                                   gfloat         scale)
+{
+       EvPageCache *page_cache;
+       CacheJobInfo *job_info;
+       int page;
+       int i;
+
+       page_cache = ev_document_get_page_cache (pixbuf_cache->document);
+
+       for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
+               job_info = (pixbuf_cache->job_list + i);
+               page = pixbuf_cache->start_page + i;
+
+               add_job_if_needed (pixbuf_cache, job_info,
+                                  page_cache, page, scale,
+                                  EV_JOB_PRIORITY_HIGH);
+       }
+
+       for (i = FIRST_VISABLE_PREV(pixbuf_cache); i < pixbuf_cache->preload_cache_size; i++) {
+               job_info = (pixbuf_cache->prev_job + i);
+               page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size + i;
+
+               add_job_if_needed (pixbuf_cache, job_info,
+                                  page_cache, page, scale,
+                                  EV_JOB_PRIORITY_LOW);
+       }
+
+       for (i = 0; i < VISIBLE_NEXT_LEN(pixbuf_cache, page_cache); i++) {
+               job_info = (pixbuf_cache->next_job + i);
+               page = pixbuf_cache->end_page + 1 + i;
+
+               add_job_if_needed (pixbuf_cache, job_info,
+                                  page_cache, page, scale,
+                                  EV_JOB_PRIORITY_LOW);
+       }
+
+}
+
+void
+ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache,
+                               gint           start_page,
+                               gint           end_page,
+                               gfloat         scale)
+{
+       EvPageCache *page_cache;
+
+       g_return_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache));
+
+       page_cache = ev_document_get_page_cache (pixbuf_cache->document);
+
+       g_return_if_fail (start_page > 0 && start_page <= ev_page_cache_get_n_pages (page_cache));
+       g_return_if_fail (end_page > 0 && end_page <= ev_page_cache_get_n_pages (page_cache));
+       g_return_if_fail (end_page >= start_page);
+
+       /* First, resize the page_range as needed.  We cull old pages
+        * mercilessly. */
+       ev_pixbuf_cache_update_range (pixbuf_cache, start_page, end_page);
+
+       /* Then, we update the current jobs to see if any of them are the wrong
+        * size, we remove them if we need to. */
+       ev_pixbuf_cache_clear_job_sizes (pixbuf_cache, scale);
+
+       /* Finally, we add the new jobs for all the sizes that don't have a
+        * pixbuf */
+       ev_pixbuf_cache_add_jobs_if_needed (pixbuf_cache, scale);
+}
+
+GdkPixbuf *
+ev_pixbuf_cache_get_pixbuf (EvPixbufCache *pixbuf_cache,
+                           gint           page)
+{
+       CacheJobInfo *job_info;
+
+       job_info = find_job_cache (pixbuf_cache, page);
+       if (job_info == NULL)
+               return NULL;
+
+       /* We don't need to wait for the idle to handle the callback */
+       if (job_info->job &&
+           EV_JOB (job_info->job)->finished) {
+               GdkPixbuf *pixbuf;
+
+               pixbuf = g_object_ref (EV_JOB_RENDER (job_info->job)->pixbuf);
+               dispose_cache_job_info (job_info, pixbuf_cache);
+               job_info->pixbuf = pixbuf;
+       }
+
+       return job_info->pixbuf;
+}
diff --git a/shell/ev-pixbuf-cache.h b/shell/ev-pixbuf-cache.h
new file mode 100644 (file)
index 0000000..e49faa0
--- /dev/null
@@ -0,0 +1,51 @@
+/* this file is part of evince, a gnome document viewer
+ *
+ *  Copyright (C) 2005 Red Hat, Inc
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EV_PIXBUF_CACHE_H__
+#define __EV_PIXBUF_CACHE_H__
+
+#include <gtk/gtkwidget.h>
+#include "ev-document.h"
+#include "ev-job-queue.h"
+
+G_BEGIN_DECLS
+
+#define EV_TYPE_PIXBUF_CACHE            (ev_pixbuf_cache_get_type ())
+#define EV_PIXBUF_CACHE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_PIXBUF_CACHE, EvPixbufCache))
+#define EV_IS_PIXBUF_CACHE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_PIXBUF_CACHE))
+
+/* This is basically an extention of ev-view.c, and is out here just to keep
+ * ev-view.c from exploding.
+ */
+
+typedef struct _EvPixbufCache       EvPixbufCache;
+typedef struct _EvPixbufCacheClass  EvPixbufCacheClass;
+
+GType          ev_pixbuf_cache_get_type       (void) G_GNUC_CONST;
+EvPixbufCache *ev_pixbuf_cache_new            (EvDocument    *document);
+void           ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache,
+                                              gint           start_page,
+                                              gint           end_page,
+                                              gfloat         scale);
+GdkPixbuf     *ev_pixbuf_cache_get_pixbuf     (EvPixbufCache *pixbuf_cache,
+                                              gint           page);
+
+G_END_DECLS
+
+#endif /* __EV_PIXBUF_CACHE_H__ */
index 0c66b81a2e175d1e67ad29352f14828e555a90c9..ba283ff77ffa9d36dc1bd0c21800375216b78b8d 100644 (file)
@@ -224,31 +224,40 @@ ev_print_job_use_print_dialog_settings (EvPrintJob *job, GnomePrintDialog *dialo
        gnome_print_config_get_page_size (print_config,
                                          &job->width, &job->height);
        gnome_print_config_get_boolean (print_config,
-                                       GNOME_PRINT_KEY_DUPLEX, &job->duplex);
+                                       (guchar *)GNOME_PRINT_KEY_DUPLEX, &job->duplex);
        gnome_print_config_unref (print_config);
 }
 
 static gboolean
 idle_print_handler (EvPrintJob *job)
 {
+       EvPageCache *page_cache;
+
        if (!job->printing) {
+               g_mutex_lock (EV_DOC_MUTEX);
                ev_ps_exporter_begin (EV_PS_EXPORTER (job->document),
                                      job->temp_file);
+               g_mutex_unlock (EV_DOC_MUTEX);
                job->next_page = 1; /* FIXME use 0-based page numbering? */
                job->printing = TRUE;
                return TRUE;
        }
 
-       if (job->next_page <= ev_document_get_n_pages (job->document)) {
+       page_cache = ev_document_get_page_cache (job->document);
+       if (job->next_page <= ev_page_cache_get_n_pages (page_cache)) {
 #if 0
                g_printerr ("Printing page %d\n", job->next_page);
 #endif
+               g_mutex_lock (EV_DOC_MUTEX);
                ev_ps_exporter_do_page (EV_PS_EXPORTER (job->document),
                                        job->next_page);
+               g_mutex_unlock (EV_DOC_MUTEX);
                job->next_page++;
                return TRUE;
        } else { /* no more pages */
+               g_mutex_lock (EV_DOC_MUTEX);
                ev_ps_exporter_end (EV_PS_EXPORTER (job->document));
+               g_mutex_unlock (EV_DOC_MUTEX);
 
                close (job->fd);
                job->fd = 0;
index 18f9e8f35ed6ced7efc6aae92dd5cc30f8517b4d..03ea9e97ca980533197757565bee4e891243efbd 100644 (file)
 #endif
 
 #include <string.h>
+#include <glib/gi18n.h>
 #include <gtk/gtk.h>
 
 #include "ev-sidebar-links.h"
+#include "ev-job-queue.h"
 #include "ev-document-links.h"
 #include "ev-window.h"
 
-/* Amount of time we devote to each iteration of the idle, in microseconds */
-#define IDLE_WORK_LENGTH 5000
-
-typedef struct {
-       EvDocumentLinksIter *links_iter;
-       GtkTreeIter *tree_iter;
-} IdleStackData;
-
 struct _EvSidebarLinksPrivate {
        GtkWidget *tree_view;
+
+       /* Keep these ids around for blocking */
+       guint selection_id;
+       guint page_changed_id;
+
+       EvJob *job;
        GtkTreeModel *model;
-       EvDocument *current_document;
-       GList *idle_stack;
-       guint idle_id;
+       EvDocument *document;
+       EvPageCache *page_cache;
 };
 
-enum {
-       LINKS_COLUMN_MARKUP,
-       LINKS_COLUMN_PAGE_NUM,
-       LINKS_COLUMN_PAGE_VALID,
-       LINKS_COLUMN_LINK,
-       LINKS_COLUMN_NUM_COLUMNS
-};
 
-static void links_page_num_func (GtkTreeViewColumn *tree_column,
-                                GtkCellRenderer   *cell,
-                                GtkTreeModel      *tree_model,
-                                GtkTreeIter       *iter,
-                                gpointer           data);
+static void links_page_num_func  (GtkTreeViewColumn *tree_column,
+                                 GtkCellRenderer   *cell,
+                                 GtkTreeModel      *tree_model,
+                                 GtkTreeIter       *iter,
+                                 gpointer           data);
+static void update_page_callback (EvPageCache       *page_cache,
+                                 gint               current_page,
+                                 EvSidebarLinks    *sidebar_links);
+
 
 G_DEFINE_TYPE (EvSidebarLinks, ev_sidebar_links, GTK_TYPE_VBOX)
 
@@ -72,7 +68,6 @@ ev_sidebar_links_destroy (GtkObject *object)
 {
        EvSidebarLinks *ev_sidebar_links = (EvSidebarLinks *) object;
 
-       g_print ("ev_sidebar_links_destroy!\n");
        ev_sidebar_links_clear_document (ev_sidebar_links);
 }
 
@@ -100,26 +95,48 @@ selection_changed_cb (GtkTreeSelection   *selection,
 
        g_return_if_fail (EV_IS_SIDEBAR_LINKS (ev_sidebar_links));
 
-       document = EV_DOCUMENT (ev_sidebar_links->priv->current_document);
-       g_return_if_fail (ev_sidebar_links->priv->current_document != NULL);
+       document = EV_DOCUMENT (ev_sidebar_links->priv->document);
+       g_return_if_fail (ev_sidebar_links->priv->document != NULL);
 
        if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
                EvLink *link;
-               GtkWidget *window;
-               GValue value = {0, };
 
-               gtk_tree_model_get_value (model, &iter,
-                                         LINKS_COLUMN_LINK, &value);
+               gtk_tree_model_get (model, &iter,
+                                   EV_DOCUMENT_LINKS_COLUMN_LINK, &link,
+                                   -1);
+               
+               if (link == NULL)
+                       return;
+
+               g_signal_handler_block (ev_sidebar_links->priv->page_cache,
+                                       ev_sidebar_links->priv->page_changed_id);
+               ev_page_cache_set_link (ev_sidebar_links->priv->page_cache, link);
+               g_signal_handler_unblock (ev_sidebar_links->priv->page_cache,
+                                         ev_sidebar_links->priv->page_changed_id);
+       }
+}
 
-               link = EV_LINK (g_value_get_object (&value));
-               g_return_if_fail (link != NULL);
+static GtkTreeModel *
+create_loading_model (void)
+{
+       GtkTreeModel *retval;
+       GtkTreeIter iter;
+       gchar *markup;
+
+       /* Creates a fake model to indicate that we're loading */
+       retval = (GtkTreeModel *)gtk_list_store_new (EV_DOCUMENT_LINKS_COLUMN_NUM_COLUMNS,
+                                                    G_TYPE_STRING,
+                                                    G_TYPE_BOOLEAN,
+                                                    G_TYPE_OBJECT);
+
+       gtk_list_store_append (GTK_LIST_STORE (retval), &iter);
+       markup = g_strdup_printf ("<span size=\"larger\" style=\"italic\">%s</span>", _("Loading..."));
+       gtk_list_store_set (GTK_LIST_STORE (retval), &iter,
+                           EV_DOCUMENT_LINKS_COLUMN_MARKUP, markup,
+                           -1);
+       g_free (markup);
 
-               window = gtk_widget_get_ancestor (GTK_WIDGET (ev_sidebar_links),
-                                                 EV_TYPE_WINDOW);
-               if (window) {
-                       ev_window_open_link (EV_WINDOW (window), link);
-               }
-       }
+       return retval;
 }
 
 static void
@@ -130,13 +147,9 @@ ev_sidebar_links_construct (EvSidebarLinks *ev_sidebar_links)
        GtkTreeViewColumn *column;
        GtkCellRenderer *renderer;
        GtkTreeSelection *selection;
+       GtkTreeModel *loading_model;
 
        priv = ev_sidebar_links->priv;
-       priv->model = (GtkTreeModel *) gtk_tree_store_new (LINKS_COLUMN_NUM_COLUMNS,
-                                                          G_TYPE_STRING,
-                                                          G_TYPE_INT,
-                                                          G_TYPE_BOOLEAN,
-                                                          G_TYPE_OBJECT);
 
        swindow = gtk_scrolled_window_new (NULL, NULL);
 
@@ -146,11 +159,14 @@ ev_sidebar_links_construct (EvSidebarLinks *ev_sidebar_links)
                                             GTK_SHADOW_IN);
 
        /* Create tree view */
-       priv->tree_view = gtk_tree_view_new_with_model (priv->model);
-       g_object_unref (priv->model);
+       loading_model = create_loading_model ();
+       priv->tree_view = gtk_tree_view_new_with_model (loading_model);
+       g_object_unref (loading_model);
+
+       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view));
+       gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE);
        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->tree_view), FALSE);
        gtk_container_add (GTK_CONTAINER (swindow), priv->tree_view);
-       gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (priv->tree_view), TRUE);
 
        gtk_box_pack_start (GTK_BOX (ev_sidebar_links), swindow, TRUE, TRUE, 0);
        gtk_widget_show_all (GTK_WIDGET (ev_sidebar_links));
@@ -165,20 +181,17 @@ ev_sidebar_links_construct (EvSidebarLinks *ev_sidebar_links)
                              NULL);
        gtk_tree_view_column_pack_start (GTK_TREE_VIEW_COLUMN (column), renderer, TRUE);
        gtk_tree_view_column_set_attributes (GTK_TREE_VIEW_COLUMN (column), renderer,
-                                            "markup", LINKS_COLUMN_MARKUP,
+                                            "markup", EV_DOCUMENT_LINKS_COLUMN_MARKUP,
                                             NULL);
 
+       
        renderer = gtk_cell_renderer_text_new ();
        gtk_tree_view_column_pack_end (GTK_TREE_VIEW_COLUMN (column), renderer, FALSE);
        gtk_tree_view_column_set_cell_data_func (GTK_TREE_VIEW_COLUMN (column), renderer,
                                                 (GtkTreeCellDataFunc) links_page_num_func,
                                                 NULL, NULL);
 
-
-       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view));
-       g_signal_connect (selection, "changed",
-                         G_CALLBACK (selection_changed_cb),
-                         ev_sidebar_links);
+       
 }
 
 static void
@@ -196,16 +209,15 @@ links_page_num_func (GtkTreeViewColumn *tree_column,
                     GtkTreeIter       *iter,
                     gpointer           data)
 {
-       int page_num;
-       gboolean page_valid;
+       EvLink *link;
 
        gtk_tree_model_get (tree_model, iter,
-                           LINKS_COLUMN_PAGE_NUM, &page_num,
-                           LINKS_COLUMN_PAGE_VALID, &page_valid,
+                           EV_DOCUMENT_LINKS_COLUMN_LINK, &link,
                            -1);
-
-       if (page_valid) {
-               gchar *markup = g_strdup_printf ("<i>%d</i>", page_num);
+       
+       if (link != NULL &&
+           ev_link_get_link_type (link) == EV_LINK_TYPE_PAGE) {
+               gchar *markup = g_strdup_printf ("<i>%d</i>", ev_link_get_page (link));
                g_object_set (cell,
                              "markup", markup,
                              "visible", TRUE,
@@ -230,139 +242,117 @@ ev_sidebar_links_new (void)
        return ev_sidebar_links;
 }
 
-static void
-stack_data_free (IdleStackData       *stack_data,
-                EvDocumentLinks     *document_links)
+void
+ev_sidebar_links_clear_document (EvSidebarLinks *sidebar_links)
 {
-       g_assert (stack_data);
+       EvSidebarLinksPrivate *priv;
 
-       if (stack_data->tree_iter)
-               gtk_tree_iter_free (stack_data->tree_iter);
-       if (stack_data->links_iter)
-               ev_document_links_free_iter (document_links, stack_data->links_iter);
-       g_free (stack_data);
+       g_return_if_fail (EV_IS_SIDEBAR_LINKS (sidebar_links));
+
+       priv = sidebar_links->priv;
+
+       if (priv->document) {
+               g_object_unref (priv->document);
+               priv->document = NULL;
+               priv->page_cache = NULL;
+       }
+
+       gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), NULL);
 }
 
 static gboolean
-do_one_iteration (EvSidebarLinks *ev_sidebar_links)
+update_page_callback_foreach (GtkTreeModel *model,
+                             GtkTreePath  *path,
+                             GtkTreeIter  *iter,
+                             gpointer      data)
 {
-       EvSidebarLinksPrivate *priv = ev_sidebar_links->priv;
+       EvSidebarLinks *sidebar_links = (data);
        EvLink *link;
-       IdleStackData *stack_data;
-       GtkTreeIter tree_iter;
-       EvDocumentLinksIter *child_iter;
-       EvLinkType link_type;
-       gint page;
-
-       g_assert (priv->idle_stack);
-
-       stack_data = (IdleStackData *) priv->idle_stack->data;
-
-       link = ev_document_links_get_link
-               (EV_DOCUMENT_LINKS (priv->current_document),
-                stack_data->links_iter);
-       if (link == NULL) {
-               g_warning ("mismatch in model.  No values available at current level.\n");
-               return FALSE;
-       }
 
-       page = ev_link_get_page (link);
-       link_type = ev_link_get_link_type (link);
-       gtk_tree_store_append (GTK_TREE_STORE (priv->model), &tree_iter, stack_data->tree_iter);
-       gtk_tree_store_set (GTK_TREE_STORE (priv->model), &tree_iter,
-                           LINKS_COLUMN_MARKUP, ev_link_get_title (link),
-                           LINKS_COLUMN_PAGE_NUM, page,
-                           LINKS_COLUMN_PAGE_VALID, (link_type == EV_LINK_TYPE_PAGE),
-                           LINKS_COLUMN_LINK, link,
+       gtk_tree_model_get (model, iter,
+                           EV_DOCUMENT_LINKS_COLUMN_LINK, &link,
                            -1);
-       g_object_unref (link);
-       
-       child_iter = ev_document_links_get_child (EV_DOCUMENT_LINKS (priv->current_document),
-                                                     stack_data->links_iter);
-       if (child_iter) {
-               IdleStackData *child_stack_data;
 
-               child_stack_data = g_new0 (IdleStackData, 1);
-               child_stack_data->tree_iter = gtk_tree_iter_copy (&tree_iter);
-               child_stack_data->links_iter = child_iter;
-               priv->idle_stack = g_list_prepend (priv->idle_stack, child_stack_data);
+       if (link && ev_link_get_link_type (link) == EV_LINK_TYPE_PAGE) {
+               int current_page;
 
-               return TRUE;
-       }
+               current_page = ev_page_cache_get_current_page (sidebar_links->priv->page_cache);
+               if (ev_link_get_page (link) == current_page) {
+                       GtkTreeSelection *selection;
 
-       /* We don't have children, so we need to walk to the next node */
-       while (TRUE) {
-               if (ev_document_links_next (EV_DOCUMENT_LINKS (priv->current_document),
-                                               stack_data->links_iter))
-                       return TRUE;
+                       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (sidebar_links->priv->tree_view));
+
+                       gtk_tree_selection_select_path (selection, path);
 
-               /* We're done with this level.  Pop it off the idle stack and go
-                * to the next level */
-               stack_data_free (stack_data, EV_DOCUMENT_LINKS (priv->current_document));
-               priv->idle_stack = g_list_delete_link (priv->idle_stack, priv->idle_stack);
-               if (priv->idle_stack == NULL)
-                       return FALSE;
-               stack_data = priv->idle_stack->data;
+                       return TRUE;
+               }
        }
+       
+       return FALSE;
 }
 
-static gboolean
-populate_links_idle (gpointer data)
+static void
+update_page_callback (EvPageCache    *page_cache,
+                     gint            current_page,
+                     EvSidebarLinks *sidebar_links)
 {
-       GTimer *timer;
-       gint i;
-       gulong microseconds = 0;
+       GtkTreeSelection *selection;
+       /* We go through the tree linearly looking for the first page that
+        * matches.  This is pretty inefficient.  We can do something neat with
+        * a GtkTreeModelSort here to make it faster, if it turns out to be
+        * slow.
+        */
 
-       EvSidebarLinks *ev_sidebar_links = (EvSidebarLinks *)data;
-       EvSidebarLinksPrivate *priv = ev_sidebar_links->priv;
+       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (sidebar_links->priv->tree_view));
 
-       if (priv->idle_stack == NULL) {
-               priv->idle_id = 0;
-               return FALSE;
-       }
+       g_signal_handler_block (selection, sidebar_links->priv->selection_id);
 
-       /* The amount of time that reading the next bookmark takes is wildly
-        * inconsistent, so we constrain it to IDLE_WORK_LENGTH microseconds per
-        * idle iteration. */
-       timer = g_timer_new ();
-       i = 0;
-       g_timer_start (timer);
-       while (do_one_iteration (ev_sidebar_links)) {
-               i++;
-               g_timer_elapsed (timer, &microseconds);
-               if (microseconds > IDLE_WORK_LENGTH)
-                       break;
-       }
-       g_timer_destroy (timer);
-#if 0
-       g_print ("%d rows done this idle in %d\n", i, (int)microseconds);
-#endif
-       return TRUE;
+       gtk_tree_selection_unselect_all (selection);
+       gtk_tree_model_foreach (sidebar_links->priv->model,
+                               update_page_callback_foreach,
+                               sidebar_links);
+
+       g_signal_handler_unblock (selection, sidebar_links->priv->selection_id);
 }
 
-void
-ev_sidebar_links_clear_document (EvSidebarLinks *sidebar_links)
+static void
+job_finished_cb (EvJobLinks     *job,
+                EvSidebarLinks *sidebar_links)
 {
        EvSidebarLinksPrivate *priv;
-
-       g_return_if_fail (EV_IS_SIDEBAR_LINKS (sidebar_links));
+       GtkTreeSelection *selection;
+       GtkTreeIter iter;
+       GtkTreePath *path;
+       gboolean result;
 
        priv = sidebar_links->priv;
 
-       /* Clear the idle */
-       if (priv->idle_id != 0) {
-               g_source_remove (priv->idle_id);
-               priv->idle_id = 0;
+       priv->model = g_object_ref (job->model);
+       gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), job->model);
+       g_object_unref (job);
+
+       /* Expand one level of the tree */
+       path = gtk_tree_path_new_first ();
+       for (result = gtk_tree_model_get_iter_first (priv->model, &iter);
+            result;
+            result = gtk_tree_model_iter_next (priv->model, &iter)) {
+               gtk_tree_view_expand_row (GTK_TREE_VIEW (priv->tree_view), path, FALSE);
+               gtk_tree_path_next (path);
        }
-       g_list_foreach (priv->idle_stack, (GFunc) stack_data_free, priv->current_document);
-       g_list_free (priv->idle_stack);
-       priv->idle_stack = NULL;
+       gtk_tree_path_free (path);
+       
+       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view));
+       gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+       priv->selection_id = g_signal_connect (selection, "changed",
+                                              G_CALLBACK (selection_changed_cb),
+                                              sidebar_links);
+       priv->page_changed_id = g_signal_connect (priv->page_cache, "page-changed",
+                                                 G_CALLBACK (update_page_callback),
+                                                 sidebar_links);
+       update_page_callback (priv->page_cache,
+                             ev_page_cache_get_current_page (priv->page_cache),
+                             sidebar_links);
 
-       if (priv->current_document) {
-               g_object_unref (priv->current_document);
-               priv->current_document = NULL;
-       }
-       gtk_tree_store_clear (GTK_TREE_STORE (priv->model));
 }
 
 void
@@ -370,7 +360,6 @@ ev_sidebar_links_set_document (EvSidebarLinks *sidebar_links,
                               EvDocument     *document)
 {
        EvSidebarLinksPrivate *priv;
-       EvDocumentLinksIter *links_iter;
 
        g_return_if_fail (EV_IS_SIDEBAR_LINKS (sidebar_links));
        g_return_if_fail (EV_IS_DOCUMENT (document));
@@ -378,19 +367,17 @@ ev_sidebar_links_set_document (EvSidebarLinks *sidebar_links,
        priv = sidebar_links->priv;
 
        g_object_ref (document);
-       ev_sidebar_links_clear_document (sidebar_links);
 
-       priv->current_document = document;
-       links_iter = ev_document_links_begin_read (EV_DOCUMENT_LINKS (document));
-       if (links_iter) {
-               IdleStackData *stack_data;
+       priv->document = document;
+       priv->page_cache = ev_document_get_page_cache (document);
 
-               stack_data = g_new0 (IdleStackData, 1);
-               stack_data->links_iter = links_iter;
-               stack_data->tree_iter = NULL;
+       priv->job = ev_job_links_new (document);
+       g_signal_connect (priv->job,
+                         "finished",
+                         G_CALLBACK (job_finished_cb),
+                         sidebar_links);
+       /* The priority doesn't matter for this job */
+       ev_job_queue_add_job (priv->job, EV_JOB_PRIORITY_LOW);
 
-               priv->idle_stack = g_list_prepend (priv->idle_stack, stack_data);
-               priv->idle_id = g_idle_add (populate_links_idle, sidebar_links);
-       }
 }
 
index b4622f6ebb9523d0975cfedf98226f87346bc3f0..c548e297fbc6b77fe9631076562830246e7d375e 100644 (file)
@@ -32,6 +32,7 @@
 #include "ev-sidebar-thumbnails.h"
 #include "ev-document-thumbnails.h"
 #include "ev-document-misc.h"
+#include "ev-job-queue.h"
 #include "ev-window.h"
 #include "ev-utils.h"
 
@@ -46,15 +47,14 @@ struct _EvSidebarThumbnailsPrivate {
        GtkListStore *list_store;
        EvDocument *document;
 
-       guint idle_id;
-       gint current_page, n_pages, pages_done;
-       GtkTreeIter current_page_iter;
+       gint n_pages, pages_done;
 };
 
 enum {
        COLUMN_PAGE_STRING,
        COLUMN_PIXBUF,
        COLUMN_THUMBNAIL_SET,
+       COLUMN_JOB,
        NUM_COLUMNS
 };
 
@@ -63,21 +63,6 @@ G_DEFINE_TYPE (EvSidebarThumbnails, ev_sidebar_thumbnails, GTK_TYPE_VBOX);
 #define EV_SIDEBAR_THUMBNAILS_GET_PRIVATE(object) \
        (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_SIDEBAR_THUMBNAILS, EvSidebarThumbnailsPrivate));
 
-static void
-ev_sidebar_thumbnails_destroy (GtkObject *object)
-{
-       EvSidebarThumbnails *ev_sidebar_thumbnails = EV_SIDEBAR_THUMBNAILS (object);
-       EvSidebarThumbnailsPrivate *priv = ev_sidebar_thumbnails->priv;
-
-       if (priv->idle_id != 0) {
-               g_source_remove (priv->idle_id);
-
-               priv->idle_id = 0;
-       }
-
-       GTK_OBJECT_CLASS (ev_sidebar_thumbnails_parent_class)->destroy (object);
-}
-
 static void
 ev_sidebar_thumbnails_class_init (EvSidebarThumbnailsClass *ev_sidebar_thumbnails_class)
 {
@@ -87,10 +72,7 @@ ev_sidebar_thumbnails_class_init (EvSidebarThumbnailsClass *ev_sidebar_thumbnail
        g_object_class = G_OBJECT_CLASS (ev_sidebar_thumbnails_class);
        gtk_object_class = GTK_OBJECT_CLASS (ev_sidebar_thumbnails_class);
 
-       gtk_object_class->destroy = ev_sidebar_thumbnails_destroy;
-
        g_type_class_add_private (g_object_class, sizeof (EvSidebarThumbnailsPrivate));
-
 }
 
 static void
@@ -111,19 +93,12 @@ adjustment_changed_cb (GtkAdjustment       *adjustment,
        if (!path)
                return;
 
-       page = gtk_tree_path_get_indices (path)[0] + 1;
-       if (page == priv->current_page)
-               return;
+       page = gtk_tree_path_get_indices (path)[0];
        gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->list_store),
                                 &iter, path);
        gtk_tree_model_get (GTK_TREE_MODEL (priv->list_store), &iter,
                            COLUMN_THUMBNAIL_SET, &thumbnail_set,
                            -1);
-       if (!thumbnail_set) {
-               priv->current_page = page;
-               priv->current_page_iter = iter;
-               
-       }
 }
 
 static void
@@ -131,28 +106,23 @@ ev_sidebar_tree_selection_changed (GtkTreeSelection *selection,
                                   EvSidebarThumbnails *ev_sidebar_thumbnails)
 {
        EvSidebarThumbnailsPrivate *priv;
-       GtkWidget *window;
+       EvPageCache *page_cache;
        GtkTreePath *path;
        GtkTreeIter iter;
        int page;
 
        priv = ev_sidebar_thumbnails->priv = EV_SIDEBAR_THUMBNAILS_GET_PRIVATE (ev_sidebar_thumbnails);
-  
+
        if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
                return;
-       
+
        path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->list_store),
                                        &iter);
-
        page = gtk_tree_path_get_indices (path)[0] + 1;
-
        gtk_tree_path_free (path);
 
-       window = gtk_widget_get_ancestor (GTK_WIDGET (ev_sidebar_thumbnails),
-                                         EV_TYPE_WINDOW);
-       if (window && ev_document_get_page (priv->document) != page) {
-               ev_window_open_page (EV_WINDOW (window), page);
-       }
+       page_cache = ev_document_get_page_cache (priv->document);
+       ev_page_cache_set_current_page (page_cache, page);
 }
 
 static void
@@ -164,10 +134,10 @@ ev_sidebar_thumbnails_init (EvSidebarThumbnails *ev_sidebar_thumbnails)
        GtkTreeSelection *selection;
 
        priv = ev_sidebar_thumbnails->priv = EV_SIDEBAR_THUMBNAILS_GET_PRIVATE (ev_sidebar_thumbnails);
-       
-       priv->list_store = gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN);
+
+       priv->list_store = gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN, EV_TYPE_JOB_THUMBNAIL);
        priv->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (priv->list_store));
-       
+
        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view));
        g_signal_connect (selection, "changed",
                          G_CALLBACK (ev_sidebar_tree_selection_changed), ev_sidebar_thumbnails);
@@ -211,126 +181,39 @@ ev_sidebar_thumbnails_new (void)
        return ev_sidebar_thumbnails;
 }
 
-static gboolean
-do_one_iteration (EvSidebarThumbnails *ev_sidebar_thumbnails)
-{
-       EvSidebarThumbnailsPrivate *priv = ev_sidebar_thumbnails->priv;
-       GdkPixbuf *pixbuf;
-       gboolean thumbnail_set;
-
-       gtk_tree_model_get (GTK_TREE_MODEL (priv->list_store),
-                           &(priv->current_page_iter),
-                           COLUMN_THUMBNAIL_SET, &thumbnail_set,
-                           -1);
-       if (!thumbnail_set) {
-               pixbuf = ev_document_thumbnails_get_thumbnail
-                               (EV_DOCUMENT_THUMBNAILS (priv->document),
-                                priv->current_page, THUMBNAIL_WIDTH, TRUE);
-
-               gtk_list_store_set (priv->list_store,
-                                   &(priv->current_page_iter),
-                                   COLUMN_PIXBUF, pixbuf,
-                                   COLUMN_THUMBNAIL_SET, TRUE,
-                                   -1);
-
-               g_object_unref (pixbuf);
-               priv->pages_done ++;
-       }
-
-       priv->current_page++;
-
-       if (priv->current_page > priv->n_pages) {
-               priv->current_page = 1;
-               gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->list_store),
-                                              &(priv->current_page_iter));
-       } else {
-               gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->list_store),
-                                         &(priv->current_page_iter));
-       }
-
-       if (priv->pages_done == priv->n_pages)
-               return FALSE;
-       else
-               return TRUE;
-}
-
-static gboolean
-populate_thumbnails_idle (gpointer data)
-{
-       GTimer *timer;
-       int i;
-       gdouble time_elapsed = 0;
-
-       EvSidebarThumbnails *ev_sidebar_thumbnails = EV_SIDEBAR_THUMBNAILS (data);
-       EvSidebarThumbnailsPrivate *priv = ev_sidebar_thumbnails->priv;
-
-#if PROFILE_THUMB == 1
-       static GTimer *total_timer;
-       static gboolean first_time = TRUE;
-
-       if (first_time) {
-               total_timer = g_timer_new ();
-               first_time = FALSE;
-               g_timer_start (total_timer);
-       }
-#endif
-
-       /* undo the thumbnailing idle and handler */
-       if (priv->pages_done == priv->n_pages) {
-               priv->idle_id = 0;
-               g_signal_handlers_disconnect_by_func (priv->vadjustment,
-                                                     adjustment_changed_cb,
-                                                     ev_sidebar_thumbnails);
-#if PROFILE_THUMB == 1
-               time_elapsed = g_timer_elapsed (total_timer, NULL);
-               g_timer_destroy (total_timer);
-               g_print ("%d rows done in %f seconds\n",
-                        gtk_tree_model_iter_n_children (GTK_TREE_MODEL (priv->list_store), NULL),
-                        time_elapsed);
-#endif
-               return FALSE;
-       }
-
-       timer = g_timer_new ();
-       i = 0;
-       g_timer_start (timer);
-       while (do_one_iteration (ev_sidebar_thumbnails)) {
-               i++;
-               time_elapsed = g_timer_elapsed (timer, NULL);
-               if (time_elapsed > IDLE_WORK_LENGTH/1000000)
-                       break;
-       }
-       g_timer_destroy (timer);
-#if PROFILE_THUMB == 2
-       g_print ("%d rows done this idle in %f seconds\n", i, time_elapsed);
-#endif
-
-       return TRUE;
-}
-
-void
-ev_sidebar_thumbnails_select_page (EvSidebarThumbnails *sidebar,
-                                  int                  page)
+static void
+page_changed_cb (EvPageCache         *page_cache,
+                int                  page,
+                EvSidebarThumbnails *sidebar)
 {
        GtkTreePath *path;
        GtkTreeSelection *selection;
 
-       /* if the EvSidebar's document can't provide thumbnails */
-       if (sidebar->priv->document == NULL) 
-               return;
-
        path = gtk_tree_path_new_from_indices (page - 1, -1);
        selection = gtk_tree_view_get_selection
                        (GTK_TREE_VIEW (sidebar->priv->tree_view));
 
-       if (path) {
-               gtk_tree_selection_select_path (selection, path);
-               gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (sidebar->priv->tree_view),
-                                             path, NULL, FALSE, 0.0, 0.0);
-               gtk_tree_path_free (path);      
-       }
+       gtk_tree_selection_select_path (selection, path);
+       gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (sidebar->priv->tree_view),
+                                     path, NULL, FALSE, 0.0, 0.0);
+       gtk_tree_path_free (path);
 }
 
+static void
+thumbnail_job_completed_callback (EvJobThumbnail      *job,
+                                 EvSidebarThumbnails *sidebar_thumbnails)
+{
+       EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
+       GtkTreeIter *iter;
+
+       iter = (GtkTreeIter *) g_object_get_data (G_OBJECT (job), "tree_iter");
+       gtk_list_store_set (priv->list_store,
+                           iter,
+                           COLUMN_PIXBUF, job->thumbnail,
+                           COLUMN_THUMBNAIL_SET, TRUE,
+                           COLUMN_JOB, NULL,
+                           -1);
+}
 
 void
 ev_sidebar_thumbnails_set_document (EvSidebarThumbnails *sidebar_thumbnails,
@@ -342,43 +225,56 @@ ev_sidebar_thumbnails_set_document (EvSidebarThumbnails *sidebar_thumbnails,
        gchar *page;
        gint width = THUMBNAIL_WIDTH;
        gint height = THUMBNAIL_WIDTH;
+       EvPageCache *page_cache;
 
        EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
 
        g_return_if_fail (EV_IS_DOCUMENT_THUMBNAILS (document));
 
-       if (priv->idle_id != 0) {
-               g_source_remove (priv->idle_id);
-       }
-       n_pages = ev_document_get_n_pages (document);
+       page_cache = ev_document_get_page_cache (document);
+       n_pages = ev_page_cache_get_n_pages (page_cache);
 
        priv->document = document;
-       priv->idle_id = g_idle_add (populate_thumbnails_idle, sidebar_thumbnails);
        priv->n_pages = n_pages;
 
        /* We get the dimensions of the first doc so that we can make a blank
         * icon.  */
+       g_mutex_lock (EV_DOC_MUTEX);
        ev_document_thumbnails_get_dimensions (EV_DOCUMENT_THUMBNAILS (priv->document),
                                               1, THUMBNAIL_WIDTH, &width, &height);
+       g_mutex_unlock (EV_DOC_MUTEX);
+
        loading_icon = ev_document_misc_get_thumbnail_frame (width, height, NULL);
 
        gtk_list_store_clear (priv->list_store);
-
        for (i = 1; i <= n_pages; i++) {
+               EvJob *job;
+
+               /* FIXME: Bah.  This is still -1 for some reason.  Need to track it down.. */
+               job = ev_job_thumbnail_new (priv->document, i - 1, THUMBNAIL_WIDTH);
                page = g_strdup_printf ("<i>%d</i>", i);
                gtk_list_store_append (priv->list_store, &iter);
                gtk_list_store_set (priv->list_store, &iter,
                                    COLUMN_PAGE_STRING, page,
                                    COLUMN_PIXBUF, loading_icon,
                                    COLUMN_THUMBNAIL_SET, FALSE,
+                                   COLUMN_JOB, job,
                                    -1);
                g_free (page);
+               ev_job_queue_add_job (job, EV_JOB_PRIORITY_LOW);
+               g_object_set_data_full (G_OBJECT (job), "tree_iter",
+                                       gtk_tree_iter_copy (&iter),
+                                       (GDestroyNotify) gtk_tree_iter_free);
+               g_signal_connect (job, "finished",
+                                 G_CALLBACK (thumbnail_job_completed_callback),
+                                 sidebar_thumbnails);
        }
 
        g_object_unref (loading_icon);
-       gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->list_store),
-                                      &(priv->current_page_iter));
-       priv->current_page = 1;
-       priv->pages_done = 0;
+
+       /* Connect to the signal and trigger a fake callback */
+       g_signal_connect (page_cache, "page-changed", G_CALLBACK (page_changed_cb), sidebar_thumbnails);
+       page_changed_cb (page_cache, ev_page_cache_get_current_page (page_cache), sidebar_thumbnails);
+
 }
 
index 0d7a4704d36a63146d9089f824f51b33dd7343c5..45f68fce2c69a3504ca33bae4293930d8c3ac2d3 100644 (file)
@@ -56,8 +56,6 @@ GtkWidget *ev_sidebar_thumbnails_new      (void);
 
 void ev_sidebar_thumbnails_set_document (EvSidebarThumbnails *sidebar_thumbnails,
                                         EvDocument          *document);
-void ev_sidebar_thumbnails_select_page  (EvSidebarThumbnails *sidebar_thumbnails,
-                                        int                  page);
 
 G_END_DECLS
 
index 202c249fa13c1e4449949bb1ebd1cc7d95e058d3..f28b5141aa857971886228ef35a0dca2e7ff935f 100644 (file)
@@ -402,8 +402,7 @@ ev_sidebar_set_document (EvSidebar   *sidebar,
                if (EV_IS_SIDEBAR_LINKS (widget)
                    && EV_IS_DOCUMENT_LINKS (document)
                    && ev_document_links_has_document_links (EV_DOCUMENT_LINKS (document))) {
-                      ev_sidebar_links_set_document
-                               (EV_SIDEBAR_LINKS (widget), document);
+                       ev_sidebar_links_set_document (EV_SIDEBAR_LINKS (widget), document);
                } else if (EV_IS_SIDEBAR_THUMBNAILS (widget) &&
                           EV_IS_DOCUMENT_THUMBNAILS (document)) {
                        ev_sidebar_thumbnails_set_document
index 372d4a362262e859d7a1d9117e33db2b6a5e8b7c..9921ed4590f8e3cc2b7426a43372a436512096d0 100644 (file)
@@ -31,6 +31,9 @@
 #include "ev-document-find.h"
 #include "ev-document-misc.h"
 #include "ev-debug.h"
+#include "ev-job-queue.h"
+#include "ev-page-cache.h"
+#include "ev-pixbuf-cache.h"
 
 #define EV_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_VIEW, EvViewClass))
 #define EV_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_VIEW))
@@ -92,6 +95,12 @@ struct _EvView {
        GtkAdjustment *hadjustment;
        GtkAdjustment *vadjustment;
 
+       EvPageCache *page_cache;
+       EvPixbufCache *pixbuf_cache;
+
+       gint current_page;
+       EvJobRender *current_job;
+
        int find_page;
        int find_result;
        int spacing;
@@ -111,11 +120,8 @@ struct _EvViewClass {
                                           GtkScrollType   scroll,
                                           gboolean        horizontal);
        
-       /* Should this be notify::page? */
-       void    (*page_changed)           (EvView         *view);
 };
 
-static guint page_changed_signal = 0;
 
 static void ev_view_set_scroll_adjustments (EvView         *view,
                                            GtkAdjustment  *hadjustment,
@@ -196,8 +202,6 @@ ev_view_finalize (GObject *object)
 
        LOG ("Finalize");
 
-       if (view->document)
-               g_object_unref (view->document);
 
        ev_view_set_scroll_adjustments (view, NULL, NULL);
 
@@ -209,6 +213,14 @@ ev_view_destroy (GtkObject *object)
 {
        EvView *view = EV_VIEW (object);
 
+       if (view->document) {
+               g_object_unref (view->document);
+               view->document = NULL;
+       }
+       if (view->pixbuf_cache) {
+               g_object_unref (view->pixbuf_cache);
+               view->pixbuf_cache = NULL;
+       }
        ev_view_set_scroll_adjustments (view, NULL, NULL);
   
        GTK_OBJECT_CLASS (ev_view_parent_class)->destroy (object);
@@ -224,7 +236,11 @@ ev_view_get_offsets (EvView *view, int *x_offset, int *y_offset)
 
        g_return_if_fail (EV_IS_DOCUMENT (document));
 
-       ev_document_get_page_size (document, -1, &width, &height);
+       ev_page_cache_get_size (view->page_cache,
+                               view->current_page,
+                               view->scale,
+                               &width, &height);
+
        ev_document_misc_get_page_border_size (width, height, &border);
        
        *x_offset = view->spacing;
@@ -259,6 +275,9 @@ doc_rect_to_view_rect (EvView *view, GdkRectangle *doc_rect, GdkRectangle *view_
        view_rect->height = doc_rect->height * view->scale;
 }
 
+
+/* Called by size_request to make sure we have appropriate jobs running.
+ */
 static void
 ev_view_size_request (GtkWidget      *widget,
                      GtkRequisition *requisition)
@@ -276,8 +295,15 @@ ev_view_size_request (GtkWidget      *widget,
                return;
        }
 
-       ev_document_get_page_size (view->document, -1,
-                                  &width, &height);
+       ev_page_cache_get_size (view->page_cache,
+                               view->current_page,
+                               view->scale,
+                               &width, &height);
+
+       ev_pixbuf_cache_set_page_range (view->pixbuf_cache,
+                                       view->current_page,
+                                       view->current_page,
+                                       view->scale);
        ev_document_misc_get_page_border_size (width, height, &border);
 
        if (view->width >= 0) {
@@ -366,8 +392,6 @@ ev_view_realize (GtkWidget *widget)
        gdk_window_set_background (view->bin_window, &widget->style->mid[widget->state]);
 
        if (view->document) {
-               ev_document_set_target (view->document, view->bin_window);
-
                /* We can't get page size without a target, so we have to
                 * queue a size request at realization. Could be fixed
                 * with EvDocument changes to allow setting a GdkScreen
@@ -382,9 +406,6 @@ ev_view_unrealize (GtkWidget *widget)
 {
        EvView *view = EV_VIEW (widget);
 
-       if (view->document)
-               ev_document_set_target (view->document, NULL);
-
        gdk_window_set_user_data (view->bin_window, NULL);
        gdk_window_destroy (view->bin_window);
        view->bin_window = NULL;
@@ -442,20 +463,26 @@ static void
 highlight_find_results (EvView *view)
 {
        EvDocumentFind *find;
-       int i, results;
+       int i, results = 0;
 
        g_return_if_fail (EV_IS_DOCUMENT_FIND (view->document));
 
        find = EV_DOCUMENT_FIND (view->document);
 
+#if 0
+       g_mutex_lock (EV_DOC_MUTEX);
        results = ev_document_find_get_n_results (find);
-
+       g_mutex_unlock (EV_DOC_MUTEX);
+#endif
+       
        for (i = 0; i < results; i++) {
                GdkRectangle rectangle;
                guchar alpha;
 
                alpha = (i == view->find_result) ? 0x90 : 0x20;
+               g_mutex_lock (EV_DOC_MUTEX);
                ev_document_find_get_result (find, i, &rectangle);
+               g_mutex_unlock (EV_DOC_MUTEX);
                draw_rubberband (GTK_WIDGET (view), view->bin_window,
                                 &rectangle, alpha);
         }
@@ -471,13 +498,18 @@ expose_bin_window (GtkWidget      *widget,
        gint width, height;
        GdkRectangle area;
        int x_offset, y_offset;
+       GdkPixbuf *scaled_image;
+       GdkPixbuf *current_pixbuf;
 
        if (view->document == NULL)
                return;
 
        ev_view_get_offsets (view, &x_offset, &y_offset); 
-       ev_document_get_page_size (view->document, -1,
-                                  &width, &height);
+       ev_page_cache_get_size (view->page_cache,
+                               view->current_page,
+                               view->scale,
+                               &width, &height);
+
        ev_document_misc_get_page_border_size (width, height, &border);
        
        /* Paint the frame */
@@ -488,18 +520,34 @@ expose_bin_window (GtkWidget      *widget,
        ev_document_misc_paint_one_page (view->bin_window, widget, &area, &border);
 
        /* Render the document itself */
-       ev_document_set_page_offset (view->document,
-                                    x_offset + border.left,
-                                    y_offset + border.top);
-
        LOG ("Render area %d %d %d %d - Offset %d %d",
             event->area.x, event->area.y,
              event->area.width, event->area.height,
             x_offset, y_offset);
 
-       ev_document_render (view->document,
-                           event->area.x, event->area.y,
-                           event->area.width, event->area.height);
+       current_pixbuf = ev_pixbuf_cache_get_pixbuf (view->pixbuf_cache, view->current_page);
+
+       if (current_pixbuf == NULL)
+               scaled_image = NULL;
+       else if (width == gdk_pixbuf_get_width (current_pixbuf) &&
+                height == gdk_pixbuf_get_height (current_pixbuf))
+               scaled_image = g_object_ref (current_pixbuf);
+       else
+               scaled_image = gdk_pixbuf_scale_simple (current_pixbuf,
+                                                       width, height,
+                                                       GDK_INTERP_NEAREST);
+       if (scaled_image) {
+               gdk_draw_pixbuf (view->bin_window,
+                                GTK_WIDGET (view)->style->fg_gc[GTK_STATE_NORMAL],
+                                scaled_image,
+                                0, 0,
+                                area.x + border.left,
+                                area.y + border.top,
+                                width, height,
+                                GDK_RGB_DITHER_NORMAL,
+                                0, 0);
+               g_object_unref (scaled_image);
+       }
 
        if (EV_IS_DOCUMENT_FIND (view->document)) {
                highlight_find_results (view);
@@ -541,8 +589,12 @@ ev_view_select_all (EvView *ev_view)
 
        g_return_if_fail (EV_IS_VIEW (ev_view));
 
+
        ev_view_get_offsets (ev_view, &x_offset, &y_offset);
-       ev_document_get_page_size (ev_view->document, -1, &width, &height);
+       ev_page_cache_get_size (ev_view->page_cache,
+                               ev_view->current_page,
+                               ev_view->scale,
+                               &width, &height);
        ev_document_misc_get_page_border_size (width, height, &border);
 
        ev_view->has_selection = TRUE;
@@ -563,7 +615,10 @@ ev_view_copy (EvView *ev_view)
        char *text;
 
        doc_rect_to_view_rect (ev_view, &ev_view->selection, &selection);
+       g_mutex_lock (EV_DOC_MUTEX);
        text = ev_document_get_text (ev_view->document, &selection);
+       g_mutex_unlock (EV_DOC_MUTEX);
+
        clipboard = gtk_widget_get_clipboard (GTK_WIDGET (ev_view),
                                              GDK_SELECTION_CLIPBOARD);
        gtk_clipboard_set_text (clipboard, text, -1);
@@ -581,7 +636,9 @@ ev_view_primary_get_cb (GtkClipboard     *clipboard,
        char *text;
 
        doc_rect_to_view_rect (ev_view, &ev_view->selection, &selection);
+       g_mutex_lock (EV_DOC_MUTEX);
        text = ev_document_get_text (ev_view->document, &selection);
+       g_mutex_unlock (EV_DOC_MUTEX);
        gtk_selection_data_set_text (selection_data, text, -1);
 }
 
@@ -697,7 +754,7 @@ ev_view_create_invisible_cursor(void)
 {
        GdkBitmap *empty;
        GdkColor black = { 0, 0, 0, 0 };
-       static unsigned char bits[] = { 0x00 };
+       static char bits[] = { 0x00 };
 
        empty = gdk_bitmap_create_from_data (NULL, bits, 1, 1);
 
@@ -759,10 +816,13 @@ ev_view_motion_notify_event (GtkWidget      *widget,
                view_rect_to_doc_rect (view, &selection, &view->selection);
 
                gtk_widget_queue_draw (widget);
-       } else if (view->document) {
+       } else if (FALSE && view->document) {
                EvLink *link;
 
+               g_mutex_lock (EV_DOC_MUTEX);
                link = ev_document_get_link (view->document, event->x, event->y);
+               g_mutex_unlock (EV_DOC_MUTEX);
+
                 if (link) {
                        char *msg;
 
@@ -796,9 +856,11 @@ ev_view_button_release_event (GtkWidget      *widget,
        } else if (view->document) {
                EvLink *link;
 
+               g_mutex_lock (EV_DOC_MUTEX);
                link = ev_document_get_link (view->document,
                                             event->x,
                                             event->y);
+               g_mutex_unlock (EV_DOC_MUTEX);
                if (link) {
                        ev_view_go_to_link (view, link);
                        g_object_unref (link);
@@ -881,9 +943,9 @@ ev_view_scroll_view (EvView *view,
                     gboolean horizontal)
 {
        if (scroll == GTK_SCROLL_PAGE_BACKWARD) {
-               ev_view_set_page (view, ev_view_get_page (view) - 1);
+               ev_page_cache_prev_page (view->page_cache);
        } else if (scroll == GTK_SCROLL_PAGE_FORWARD) {
-               ev_view_set_page (view, ev_view_get_page (view) + 1);
+               ev_page_cache_next_page (view->page_cache);
        } else {
                GtkAdjustment *adjustment;
                double value;
@@ -982,13 +1044,6 @@ ev_view_class_init (EvViewClass *class)
                                                                     G_TYPE_NONE, 2,
                                                                     GTK_TYPE_ADJUSTMENT,
                                                                     GTK_TYPE_ADJUSTMENT);
-       page_changed_signal = g_signal_new ("page-changed",
-                                           G_OBJECT_CLASS_TYPE (object_class),
-                                           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                                           G_STRUCT_OFFSET (EvViewClass, page_changed),
-                                           NULL, NULL,
-                                           ev_marshal_VOID__NONE,
-                                           G_TYPE_NONE, 0);
 
        g_signal_new ("scroll_view",
                      G_TYPE_FROM_CLASS (object_class),
@@ -1034,6 +1089,7 @@ ev_view_init (EvView *view)
 
        view->spacing = 10;
        view->scale = 1.0;
+       view->current_page = 1;
        view->pressed_button = -1;
        view->cursor = EV_VIEW_CURSOR_NORMAL;
 }
@@ -1043,12 +1099,14 @@ update_find_status_message (EvView *view)
 {
        char *message;
 
+//     g_mutex_lock (EV_DOC_MUTEX);
        if (ev_document_get_page (view->document) == view->find_page) {
                int results;
 
+//             g_mutex_lock (EV_DOC_MUTEX);
                results = ev_document_find_get_n_results
                                (EV_DOCUMENT_FIND (view->document));
-
+//             g_mutex_unlock (EV_DOC_MUTEX);
                /* TRANS: Sometimes this could be better translated as
                   "%d hit(s) on this page".  Therefore this string
                   contains plural cases. */
@@ -1058,10 +1116,11 @@ update_find_status_message (EvView *view)
                                           results);
        } else {
                double percent;
-               
+
+               g_mutex_lock (EV_DOC_MUTEX);
                percent = ev_document_find_get_progress
                                (EV_DOCUMENT_FIND (view->document));
-
+               g_mutex_unlock (EV_DOC_MUTEX);
                if (percent >= (1.0 - 1e-10)) {
                        message = g_strdup (_("Not found"));
                } else {
@@ -1070,57 +1129,10 @@ update_find_status_message (EvView *view)
                }
                
        }
+//     g_mutex_unlock (EV_DOC_MUTEX);
 
        ev_view_set_find_status (view, message);
-       g_free (message);
-}
-
-static void
-set_document_page (EvView *view, int new_page)
-{
-       int page;
-       int pages;
-
-       pages = ev_document_get_n_pages (view->document);
-       page = CLAMP (new_page, 1, pages);
-
-       if (view->document) {
-               int old_page = ev_document_get_page (view->document);
-               int old_width, old_height;
-
-               ev_document_get_page_size (view->document,
-                                          -1, 
-                                          &old_width, &old_height);
-
-               if (old_page != page) {
-                       if (view->cursor != EV_VIEW_CURSOR_HIDDEN) {
-                               ev_view_set_cursor (view, EV_VIEW_CURSOR_WAIT);
-                       }
-                       ev_document_set_page (view->document, page);
-               }
-
-               if (old_page != ev_document_get_page (view->document)) {
-                       int width, height;
-                       
-                       g_signal_emit (view, page_changed_signal, 0);
-
-                       view->has_selection = FALSE;
-                       ev_document_get_page_size (view->document,
-                                                  -1, 
-                                                  &width, &height);
-                       if (width != old_width || height != old_height)
-                               gtk_widget_queue_resize (GTK_WIDGET (view));
-
-                       gtk_adjustment_set_value (view->vadjustment,
-                                                 view->vadjustment->lower);
-               }
-
-               if (EV_IS_DOCUMENT_FIND (view->document)) {
-                       view->find_page = page;
-                       view->find_result = 0;
-                       update_find_status_message (view);
-               }
-       }
+//     g_free (message);
 }
 
 #define MARGIN 5
@@ -1164,11 +1176,16 @@ jump_to_find_result (EvView *view)
        GdkRectangle rect;
        int n_results;
 
+       g_mutex_lock (EV_DOC_MUTEX);
        n_results = ev_document_find_get_n_results (find);
+       g_mutex_unlock (EV_DOC_MUTEX);
 
        if (n_results > view->find_result) {
+               g_mutex_lock (EV_DOC_MUTEX);
                ev_document_find_get_result
                        (find, view->find_result, &rect);
+               g_mutex_unlock (EV_DOC_MUTEX);
+
                ensure_rectangle_is_visible (view, &rect);
        }
 }
@@ -1178,7 +1195,7 @@ jump_to_find_page (EvView *view)
 {
        int n_pages, i;
 
-       n_pages = ev_document_get_n_pages (view->document);
+       n_pages = ev_page_cache_get_n_pages (view->page_cache);
 
        for (i = 0; i <= n_pages; i++) {
                int has_results;
@@ -1189,13 +1206,14 @@ jump_to_find_page (EvView *view)
                        page = page - n_pages;
                }
 
+               g_mutex_lock (EV_DOC_MUTEX);
                has_results = ev_document_find_page_has_results
                                (EV_DOCUMENT_FIND (view->document), page);
                if (has_results == -1) {
                        view->find_page = page;
                        break;
                } else if (has_results == 1) {
-                       set_document_page (view, page);
+                       ev_page_cache_set_current_page (view->page_cache, page);
                        jump_to_find_result (view);
                        break;
                }
@@ -1209,39 +1227,75 @@ find_changed_cb (EvDocument *document, int page, EvView *view)
        jump_to_find_result (view);
        update_find_status_message (view);
 
+#if 0
+       /* FIXME: */
        if (ev_document_get_page (document) == page) {
                gtk_widget_queue_draw (GTK_WIDGET (view));
        }
+#endif
+}
+/*** Public API ***/       
+     
+GtkWidget*
+ev_view_new (void)
+{
+       return g_object_new (EV_TYPE_VIEW, NULL);
 }
 
 static void
-page_changed_callback (EvDocument *document,
-                          EvView     *view)
+job_finished_cb (EvPixbufCache *pixbuf_cache,
+                EvView        *view)
 {
-       LOG ("Page changed callback");
-
        gtk_widget_queue_draw (GTK_WIDGET (view));
-
-       if (view->cursor != EV_VIEW_CURSOR_HIDDEN) {
-               ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
-       }
 }
 
+
 static void
-scale_changed_callback (EvDocument *document,
-                       EvView     *view)
+page_changed_cb (EvPageCache *page_cache,
+                int          new_page,
+                EvView      *view)
 {
-       LOG ("Scale changed callback");
+       int old_page = view->current_page;
+       int old_width, old_height;
+       int new_width, new_height;
 
-       gtk_widget_queue_resize (GTK_WIDGET (view));
-}
+       if (old_page == new_page)
+               return;
 
-/*** Public API ***/       
-     
-GtkWidget*
-ev_view_new (void)
-{
-       return g_object_new (EV_TYPE_VIEW, NULL);
+       ev_page_cache_get_size (page_cache,
+                               old_page,
+                               view->scale,
+                               &old_width, &old_height);
+       ev_page_cache_get_size (page_cache,
+                               new_page,
+                               view->scale,
+                               &new_width, &new_height);
+
+       if (view->cursor != EV_VIEW_CURSOR_HIDDEN) {
+               //ev_view_set_cursor (view, EV_VIEW_CURSOR_WAIT);
+       }
+
+       view->current_page = new_page;
+       view->has_selection = FALSE;
+
+       ev_pixbuf_cache_set_page_range (view->pixbuf_cache,
+                                       view->current_page,
+                                       view->current_page,
+                                       view->scale);
+
+       if (new_width != old_width || new_height != old_height)
+               gtk_widget_queue_resize (GTK_WIDGET (view));
+       else
+               gtk_widget_queue_draw (GTK_WIDGET (view));
+       
+       gtk_adjustment_set_value (view->vadjustment,
+                                 view->vadjustment->lower);
+
+       if (EV_IS_DOCUMENT_FIND (view->document)) {
+               view->find_page = new_page;
+               view->find_result = 0;
+               update_find_status_message (view);
+       }
 }
 
 void
@@ -1256,6 +1310,8 @@ ev_view_set_document (EvView     *view,
                                                               find_changed_cb,
                                                               view);
                        g_object_unref (view->document);
+                       view->page_cache = NULL;
+                       
                 }
 
                view->document = document;
@@ -1270,22 +1326,13 @@ ev_view_set_document (EvView     *view,
                                                  G_CALLBACK (find_changed_cb),
                                                  view);
                        }
-                       g_signal_connect (view->document,
-                                         "page_changed",
-                                         G_CALLBACK (page_changed_callback),
-                                         view);
-                       g_signal_connect (view->document,
-                                         "scale_changed",
-                                         G_CALLBACK (scale_changed_callback),
-                                         view);
+                       view->page_cache = ev_document_get_page_cache (view->document);
+                       g_signal_connect (view->page_cache, "page-changed", G_CALLBACK (page_changed_cb), view);
+                       view->pixbuf_cache = ev_pixbuf_cache_new (view->document);
+                       g_signal_connect (view->pixbuf_cache, "job-finished", G_CALLBACK (job_finished_cb), view);
                 }
-
-               if (GTK_WIDGET_REALIZED (view))
-                       ev_document_set_target (view->document, view->bin_window);
                
                gtk_widget_queue_resize (GTK_WIDGET (view));
-               
-               g_signal_emit (view, page_changed_signal, 0);
        }
 }
 
@@ -1303,7 +1350,7 @@ go_to_link (EvView *view, EvLink *link)
                        break;
                case EV_LINK_TYPE_PAGE:
                        page = ev_link_get_page (link);
-                       set_document_page (view, page);
+                       ev_page_cache_set_current_page (view->page_cache, page);
                        break;
                case EV_LINK_TYPE_EXTERNAL_URI:
                        uri = ev_link_get_uri (link);
@@ -1318,24 +1365,6 @@ ev_view_go_to_link (EvView *view, EvLink *link)
        go_to_link (view, link);
 }
 
-void
-ev_view_set_page (EvView *view,
-                 int     page)
-{
-       g_return_if_fail (EV_IS_VIEW (view));
-
-       set_document_page (view, page);
-}
-
-int
-ev_view_get_page (EvView *view)
-{
-       if (view->document)
-               return ev_document_get_page (view->document);
-       else
-               return 1;
-}
-
 static void
 ev_view_zoom (EvView   *view,
              double    factor,
@@ -1351,8 +1380,7 @@ ev_view_zoom (EvView   *view,
        scale = CLAMP (scale, MIN_SCALE, MAX_SCALE);
 
        view->scale = scale;
-
-       ev_document_set_scale (view->document, view->scale);
+       gtk_widget_queue_resize (GTK_WIDGET (view));
 }
 
 void
@@ -1378,7 +1406,12 @@ size_to_zoom_factor (EvView *view, int width, int height)
 
        doc_width = doc_height = 0;
        scale = scale_w = scale_h = 1.0;
-       ev_document_get_page_size (view->document, -1, &doc_width, &doc_height);
+       ev_page_cache_get_size (view->page_cache,
+                               view->current_page,
+                               view->scale,
+                               &doc_width,
+                               &doc_height);
+
        /* FIXME: The border size isn't constant.  Ugh.  Still, if we have extra
         * space, we just cut it from the border */
        ev_document_misc_get_page_border_size (doc_width, doc_height, &border);
@@ -1415,16 +1448,16 @@ ev_view_set_size (EvView     *view,
 {
        double factor;
 
-       if (!view->document) {
+       if (!view->document)
                return;
-       }
 
        if (view->width != width ||
            view->height != height) {
                view->width = width;
                view->height = height;
                factor = size_to_zoom_factor (view, width, height);
-               ev_view_zoom (view, factor, FALSE); 
+               ev_view_zoom (view, factor, FALSE);
+               gtk_widget_queue_resize (GTK_WIDGET (view));
        }
 }
 
@@ -1447,11 +1480,16 @@ ev_view_get_find_status (EvView *view)
 void
 ev_view_find_next (EvView *view)
 {
+       EvPageCache *page_cache;
        int n_results, n_pages;
        EvDocumentFind *find = EV_DOCUMENT_FIND (view->document);
 
+       page_cache = ev_document_get_page_cache (view->document);
+       g_mutex_lock (EV_DOC_MUTEX);
        n_results = ev_document_find_get_n_results (find);
-       n_pages = ev_document_get_n_pages (view->document);
+       g_mutex_unlock (EV_DOC_MUTEX);
+
+       n_pages = ev_page_cache_get_n_pages (page_cache);
 
        view->find_result++;
 
@@ -1475,9 +1513,15 @@ ev_view_find_previous (EvView *view)
 {
        int n_results, n_pages;
        EvDocumentFind *find = EV_DOCUMENT_FIND (view->document);
+       EvPageCache *page_cache;
+
+       page_cache = ev_document_get_page_cache (view->document);
 
+       g_mutex_lock (EV_DOC_MUTEX);
        n_results = ev_document_find_get_n_results (find);
-       n_pages = ev_document_get_n_pages (view->document);
+       g_mutex_unlock (EV_DOC_MUTEX);
+
+       n_pages = ev_page_cache_get_n_pages (page_cache);
 
        view->find_result--;
 
index cc90fb8b2bc8ea9437d2fb96e97689cd8db552b6..00b92ea858c1db58e0c58259c4a7010b15111cfc 100644 (file)
@@ -44,15 +44,8 @@ void         ev_view_copy            (EvView     *view);
 void           ev_view_select_all      (EvView     *view);
 
 /* Navigation */
-gboolean       ev_view_can_go_back     (EvView     *view);
-void           ev_view_go_back         (EvView     *view);
-gboolean       ev_view_can_go_forward  (EvView     *view);
-void           ev_view_go_forward      (EvView     *view);
 void           ev_view_go_to_link      (EvView     *view,
                                         EvLink     *link);
-void           ev_view_set_page        (EvView     *view,
-                                        int         page);
-int            ev_view_get_page        (EvView     *view);
 
 /* Page size */
 void           ev_view_zoom_in         (EvView     *view);
index f1c41bb793700b018b79386e7772519b39fc2578..849adaf18c8d93c6f3f6c9ff2d4f593513efd6dc 100644 (file)
@@ -41,6 +41,7 @@
 #include "ev-document-links.h"
 #include "ev-document-find.h"
 #include "ev-document-security.h"
+#include "ev-job-queue.h"
 #include "eggfindbar.h"
 
 #include "pdf-document.h"
@@ -106,6 +107,7 @@ struct _EvWindowPrivate {
        char *uri;
 
        EvDocument *document;
+       EvPageCache *page_cache;
 
        EvWindowPageMode page_mode;
        /* These members are used temporarily when in PAGE_MODE_PASSWORD */
@@ -168,7 +170,6 @@ update_action_sensitivity (EvWindow *ev_window)
 
        document = ev_window->priv->document;
        page_mode = ev_window->priv->page_mode;
-
        view = EV_VIEW (ev_window->priv->view);
 
        /* File menu */
@@ -198,9 +199,8 @@ update_action_sensitivity (EvWindow *ev_window)
        if (document) {
                int n_pages;
                int page;
-
-               page = ev_view_get_page (EV_VIEW (ev_window->priv->view));
-               n_pages = ev_document_get_n_pages (document);
+               page = ev_page_cache_get_current_page (ev_window->priv->page_cache);
+               n_pages = ev_page_cache_get_n_pages (ev_window->priv->page_cache);
 
                set_action_sensitive (ev_window, "GoPreviousPage", page > 1);
                set_action_sensitive (ev_window, "GoNextPage", page < n_pages);
@@ -347,7 +347,8 @@ update_sizing_buttons (EvWindow *window)
 void
 ev_window_open_page (EvWindow *ev_window, int page)
 {
-       ev_view_set_page (EV_VIEW (ev_window->priv->view), page);
+       if (ev_window->priv->page_cache)
+               ev_page_cache_set_current_page (ev_window->priv->page_cache, page);
 }
 
 void
@@ -427,9 +428,8 @@ update_window_title (EvDocument *document, GParamSpec *pspec, EvWindow *ev_windo
        gboolean password_needed;
 
        password_needed = (ev_window->priv->password_document != NULL);
-
        if (document) {
-               doc_title = ev_document_get_title (document);
+               doc_title = ev_page_cache_get_title (ev_window->priv->page_cache);
 
                /* Make sure we get a valid title back */
                if (doc_title) {
@@ -485,9 +485,8 @@ update_total_pages (EvWindow *ev_window)
        GtkAction *action;
        int pages;
 
-       pages = ev_document_get_n_pages (ev_window->priv->document);
-       action = gtk_action_group_get_action
-               (ev_window->priv->action_group, PAGE_SELECTOR_ACTION);
+       pages = ev_page_cache_get_n_pages (ev_window->priv->page_cache);
+       action = gtk_action_group_get_action (ev_window->priv->action_group, PAGE_SELECTOR_ACTION);
        ev_page_action_set_total_pages (EV_PAGE_ACTION (action), pages);
 }
 
@@ -514,6 +513,21 @@ hide_sidebar_and_actions (EvWindow *ev_window)
 
 }
 
+static void
+page_changed_cb (EvPageCache *page_cache,
+                gint         page,
+                EvWindow    *ev_window)
+{
+       GtkAction *action;
+
+       action = gtk_action_group_get_action
+               (ev_window->priv->action_group, PAGE_SELECTOR_ACTION);
+
+       ev_page_action_set_current_page (EV_PAGE_ACTION (action), page);
+       update_action_sensitivity (ev_window);
+}
+
+
 static void
 ev_window_setup_document (EvWindow *ev_window)
 {
@@ -522,6 +536,8 @@ ev_window_setup_document (EvWindow *ev_window)
        EvSidebar *sidebar = EV_SIDEBAR (ev_window->priv->sidebar);
 
        document = ev_window->priv->document;
+       ev_window->priv->page_cache = ev_document_get_page_cache (ev_window->priv->document);
+       g_signal_connect (ev_window->priv->page_cache, "page-changed", G_CALLBACK (page_changed_cb), ev_window);
 
        g_signal_connect_object (G_OBJECT (document),
                                 "notify::title",
@@ -534,6 +550,7 @@ ev_window_setup_document (EvWindow *ev_window)
                ev_sidebar_set_document (sidebar, document);
        else
                hide_sidebar_and_actions (ev_window);
+
        ev_view_set_document (view, document);
 
        update_window_title (document, NULL, ev_window);
@@ -553,9 +570,12 @@ password_dialog_response (GtkWidget *password_dialog,
                gchar *uri;
 
                password = ev_password_dialog_get_password (password_dialog);
-               if (password)
+               if (password) {
+                       g_mutex_lock (EV_DOC_MUTEX);
                        ev_document_security_set_password (EV_DOCUMENT_SECURITY (ev_window->priv->password_document),
                                                           password);
+                       g_mutex_unlock (EV_DOC_MUTEX);
+               }
                g_free (password);
 
                document = ev_window->priv->password_document;
@@ -856,6 +876,7 @@ ev_window_cmd_save_as (GtkAction *action, EvWindow *ev_window)
        GtkWidget *fc;
        GtkFileFilter *pdf_filter, *all_filter;
        gchar *uri = NULL;
+       gboolean success;
 
        fc = gtk_file_chooser_dialog_new (
                _("Save a Copy"),
@@ -888,8 +909,12 @@ ev_window_cmd_save_as (GtkAction *action, EvWindow *ev_window)
                    !overwrite_existing_file (GTK_WINDOW (fc), uri))
                                continue;
 */
+               
+               g_mutex_lock (EV_DOC_MUTEX);
+               success = ev_document_save (ev_window->priv->document, uri, NULL);
+               g_mutex_unlock (EV_DOC_MUTEX);
 
-               if (ev_document_save (ev_window->priv->document, uri, NULL))
+               if (success)
                        break;
                else
                        save_error_dialog (GTK_WINDOW (fc), uri);
@@ -936,7 +961,7 @@ ev_window_print (EvWindow *ev_window)
        config = gnome_print_config_default ();
        job = gnome_print_job_new (config);
 
-       print_dialog = gnome_print_dialog_new (job, _("Print"),
+       print_dialog = gnome_print_dialog_new (job, (guchar *) _("Print"),
                                               (GNOME_PRINT_DIALOG_RANGE |
                                                GNOME_PRINT_DIALOG_COPIES));
        gtk_dialog_set_response_sensitive (GTK_DIALOG (print_dialog),
@@ -964,7 +989,7 @@ ev_window_print (EvWindow *ev_window)
                                GTK_MESSAGE_DIALOG (dialog),
                                _("You were trying to print to a printer using the \"%s\" driver. This program requires a PostScript printer driver."),
                                gnome_print_config_get (
-                                       config, "Settings.Engine.Backend.Driver"));
+                                       config, (guchar *)"Settings.Engine.Backend.Driver"));
                        gtk_dialog_run (GTK_DIALOG (dialog));
                        gtk_widget_destroy (dialog);
 
@@ -1465,8 +1490,7 @@ ev_window_cmd_go_previous_page (GtkAction *action, EvWindow *ev_window)
 {
         g_return_if_fail (EV_IS_WINDOW (ev_window));
 
-       ev_view_set_page (EV_VIEW (ev_window->priv->view),
-                         ev_view_get_page (EV_VIEW (ev_window->priv->view)) - 1);
+       ev_page_cache_prev_page (ev_window->priv->page_cache);
 }
 
 static void
@@ -1474,8 +1498,7 @@ ev_window_cmd_go_next_page (GtkAction *action, EvWindow *ev_window)
 {
         g_return_if_fail (EV_IS_WINDOW (ev_window));
 
-       ev_view_set_page (EV_VIEW (ev_window->priv->view),
-                         ev_view_get_page (EV_VIEW (ev_window->priv->view)) + 1);
+       ev_page_cache_next_page (ev_window->priv->page_cache);
 }
 
 static void
@@ -1483,15 +1506,18 @@ ev_window_cmd_go_first_page (GtkAction *action, EvWindow *ev_window)
 {
         g_return_if_fail (EV_IS_WINDOW (ev_window));
 
-       ev_view_set_page (EV_VIEW (ev_window->priv->view), 1);
+       ev_page_cache_set_current_page (ev_window->priv->page_cache, 1);
 }
 
 static void
 ev_window_cmd_go_last_page (GtkAction *action, EvWindow *ev_window)
 {
+       int n_pages;
+
         g_return_if_fail (EV_IS_WINDOW (ev_window));
 
-       ev_view_set_page (EV_VIEW (ev_window->priv->view), G_MAXINT);
+       n_pages = ev_page_cache_get_n_pages (ev_window->priv->page_cache);
+       ev_page_cache_set_current_page (ev_window->priv->page_cache, n_pages);
 }
 
 static void
@@ -1502,7 +1528,12 @@ ev_window_cmd_view_reload (GtkAction *action, EvWindow *ev_window)
 
        g_return_if_fail (EV_IS_WINDOW (ev_window));
 
-       page = ev_document_get_page (ev_window->priv->document);
+#if 0
+       /* FIXME: uncomment when this is written.*/
+       page = ev_page_cache_get_page (ev_window->priv->page_cache);
+#else
+       page = 1;
+#endif
        uri = g_strdup (ev_window->priv->uri);
 
        ev_window_open (ev_window, uri);
@@ -1766,32 +1797,6 @@ disconnect_proxy_cb (GtkUIManager *ui_manager, GtkAction *action,
        }
 }
 
-static void
-update_current_page (EvWindow *ev_window,
-                    EvView   *view)
-{
-       int page;
-       GtkAction *action;
-       EvSidebarThumbnails *thumbs;
-
-       thumbs = EV_SIDEBAR_THUMBNAILS (ev_window->priv->thumbs_sidebar);
-       ev_sidebar_thumbnails_select_page (thumbs, ev_view_get_page (view));
-
-       action = gtk_action_group_get_action
-               (ev_window->priv->action_group, PAGE_SELECTOR_ACTION);
-
-       page = ev_view_get_page (EV_VIEW (ev_window->priv->view));
-       ev_page_action_set_current_page (EV_PAGE_ACTION (action), page);
-}
-
-static void
-view_page_changed_cb (EvView   *view,
-                     EvWindow *ev_window)
-{
-       update_current_page (ev_window, view);
-       update_action_sensitivity (ev_window);
-}
-
 static void
 view_status_changed_cb (EvView     *view,
                        GParamSpec *pspec,
@@ -1885,9 +1890,14 @@ find_bar_search_changed_cb (EggFindBar *find_bar,
        if (ev_window->priv->document &&
            EV_IS_DOCUMENT_FIND (ev_window->priv->document)) {
                if (visible && search_string) {
+                       g_mutex_lock (EV_DOC_MUTEX);
                        ev_document_find_begin (EV_DOCUMENT_FIND (ev_window->priv->document), search_string, case_sensitive);
+                       g_mutex_unlock (EV_DOC_MUTEX);
                } else {
+                       g_mutex_lock (EV_DOC_MUTEX);
                        ev_document_find_cancel (EV_DOCUMENT_FIND (ev_window->priv->document));
+                       g_mutex_unlock (EV_DOC_MUTEX);
+
                        egg_find_bar_set_status_text (EGG_FIND_BAR (ev_window->priv->find_bar),
                                                      NULL);
                        gtk_widget_queue_draw (GTK_WIDGET (ev_window->priv->view));
@@ -2066,11 +2076,8 @@ static GtkRadioActionEntry page_view_entries[] = {
 static void
 goto_page_cb (GtkAction *action, int page_number, EvWindow *ev_window)
 {
-       EvView *view = EV_VIEW (ev_window->priv->view);
-
-       if (ev_view_get_page (view) != page_number) {
-               ev_view_set_page (view, page_number);
-       }
+       ev_page_cache_set_current_page (ev_window->priv->page_cache,
+                                       page_number);
 }
 
 static void
@@ -2352,10 +2359,6 @@ ev_window_init (EvWindow *ev_window)
 
        gtk_container_add (GTK_CONTAINER (ev_window->priv->scrolled_window),
                           ev_window->priv->view);
-       g_signal_connect (ev_window->priv->view,
-                         "page-changed",
-                         G_CALLBACK (view_page_changed_cb),
-                         ev_window);
        g_signal_connect (ev_window->priv->view,
                          "notify::find-status",
                          G_CALLBACK (view_find_status_changed_cb),
index 86450d4d85e6cf847dfb29645b97b3699a41bbe6..6cd14e882b1cdc55d42038177d30ae648871d948 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "ev-stock-icons.h"
 #include "ev-debug.h"
+#include "ev-job-queue.h"
 
 static struct poptOption popt_options[] =
 {
@@ -82,6 +83,7 @@ main (int argc, char *argv[])
                                      GNOME_PARAM_APP_DATADIR, DATADIR,
                                       NULL);
 
+       ev_job_queue_init ();
        g_set_application_name (_("Evince Document Viewer"));
 
        ev_debug_init ();