+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.
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:
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
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 \
#include "config.h"
#include "ev-document-links.h"
+#include "ev-job-queue.h"
GType
ev_document_links_get_type (void)
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;
}
#include <glib-object.h>
#include <glib.h>
-#include <gdk/gdk.h>
+#include <gtk/gtk.h>
#include "ev-document.h"
#include "ev-link.h"
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
#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);
};
static guint signals[LAST_SIGNAL] = { 0 };
+GMutex *ev_doc_mutex = NULL;
+
+#define LOG(x)
GType
ev_document_get_type (void)
{
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
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 *
{
char *title;
+ LOG ("ev_document_get_title");
g_object_get (document, "title", &title, NULL);
return title;
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
int page)
{
EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
+
+ LOG ("ev_document_set_page");
iface->set_page (document, page);
}
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
GdkDrawable *target)
{
EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
+
+ LOG ("ev_document_set_target");
iface->set_target (document, target);
}
double scale)
{
EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
+
+ LOG ("ev_document_set_scale");
iface->set_scale (document, scale);
}
int y)
{
EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
+
+ LOG ("ev_document_set_page_offset");
iface->set_page_offset (document, x, y);
}
int *height)
{
EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
+
+ LOG ("ev_document_get_page_size");
iface->get_page_size (document, page, width, height);
}
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 *
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
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)
{
ev_document_scale_changed (EvDocument *document)
{
g_signal_emit (G_OBJECT (document), signals[SCALE_CHANGED], 0);
-}
+}
#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
{
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,
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);
--- /dev/null
+#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;
+}
+
+
--- /dev/null
+/* 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__ */
--- /dev/null
+#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);
+}
--- /dev/null
+/* 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__ */
PROP_URI
};
+
+struct _EvLink {
+ GObject base_instance;
+ EvLinkPrivate *priv;
+};
+
+struct _EvLinkClass {
+ GObjectClass base_class;
+};
+
struct _EvLinkPrivate {
char *title;
char *uri;
{
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);
--- /dev/null
+#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;
+}
+
--- /dev/null
+/* 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__ */
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);
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,
{
{
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;
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);
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)
{
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) {
* 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... */
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++) {
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);
}
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 *
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 *
/* FIXME: Should I close all the nodes?? Free them? */
g_free (iter);
}
+#endif
static void
pdf_document_finalize (GObject *object)
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 {
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
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 */
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++;
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())) {
return GS_PATH;
}
-const gchar *
-gtk_gs_defaults_get_alpha_parameters (void)
-{
- return ALPHA_PARAMS;
-}
-
const gchar *
gtk_gs_defaults_get_ungzip_cmd (void)
{
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);
* 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>
#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>
# 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)
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,
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
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
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");
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
}
}
-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
}
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) {
}
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)
{
void (*oldsig) (int);
oldsig = signal(SIGPIPE, catchPipe);
+ LOG ("Input");
+
do {
if(gs->buffer_bytes_left == 0) {
/* Get a new section if required */
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 {
}
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
/* 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;
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);
}
}
-/*
- * 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");
}
/* prepare this document */
-
- /* default values: no dsc information available */
gs->structured_doc = FALSE;
gs->send_filename_to_gs = TRUE;
gs->current_page = 0;
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 {
}
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");
/* 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;
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.");
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
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
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
}
}
-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)
{
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)
{
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;
}
#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 */
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;
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 {
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 \
--- /dev/null
+#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;
+}
--- /dev/null
+/* 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__ */
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;
#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)
{
EvSidebarLinks *ev_sidebar_links = (EvSidebarLinks *) object;
- g_print ("ev_sidebar_links_destroy!\n");
ev_sidebar_links_clear_document (ev_sidebar_links);
}
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
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);
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));
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
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,
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, µseconds);
- 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
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));
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);
- }
}
#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"
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
};
#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)
{
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
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
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
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);
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,
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);
+
}
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
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
#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))
GtkAdjustment *hadjustment;
GtkAdjustment *vadjustment;
+ EvPageCache *page_cache;
+ EvPixbufCache *pixbuf_cache;
+
+ gint current_page;
+ EvJobRender *current_job;
+
int find_page;
int find_result;
int spacing;
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,
LOG ("Finalize");
- if (view->document)
- g_object_unref (view->document);
ev_view_set_scroll_adjustments (view, NULL, NULL);
{
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);
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;
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)
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) {
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
{
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;
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);
}
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 */
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);
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;
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);
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);
}
{
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);
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;
} 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);
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;
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),
view->spacing = 10;
view->scale = 1.0;
+ view->current_page = 1;
view->pressed_button = -1;
view->cursor = EV_VIEW_CURSOR_NORMAL;
}
{
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. */
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 {
}
}
+// 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
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);
}
}
{
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;
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;
}
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
find_changed_cb,
view);
g_object_unref (view->document);
+ view->page_cache = NULL;
+
}
view->document = document;
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);
}
}
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);
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,
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
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);
{
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));
}
}
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++;
{
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--;
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);
#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"
char *uri;
EvDocument *document;
+ EvPageCache *page_cache;
EvWindowPageMode page_mode;
/* These members are used temporarily when in PAGE_MODE_PASSWORD */
document = ev_window->priv->document;
page_mode = ev_window->priv->page_mode;
-
view = EV_VIEW (ev_window->priv->view);
/* File menu */
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);
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
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) {
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);
}
}
+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)
{
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",
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);
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;
GtkWidget *fc;
GtkFileFilter *pdf_filter, *all_filter;
gchar *uri = NULL;
+ gboolean success;
fc = gtk_file_chooser_dialog_new (
_("Save a Copy"),
!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);
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),
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);
{
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
{
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
{
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
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);
}
}
-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,
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));
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
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),
#include "ev-stock-icons.h"
#include "ev-debug.h"
+#include "ev-job-queue.h"
static struct poptOption popt_options[] =
{
GNOME_PARAM_APP_DATADIR, DATADIR,
NULL);
+ ev_job_queue_init ();
g_set_application_name (_("Evince Document Viewer"));
ev_debug_init ();