From bca369672136e5ff831ece9832afd42085808fba Mon Sep 17 00:00:00 2001 From: Nickolay V. Shmyrev Date: Tue, 07 Jun 2005 23:28:54 +0000 Subject: PageCache and EvJobs are moved from backend to shell. Two new jobs to load document in background and a statusbar to display this process. FileChooser now can select multiple uris. --- (limited to 'shell/ev-page-cache.c') diff --git a/shell/ev-page-cache.c b/shell/ev-page-cache.c new file mode 100644 index 0000000..6c44c9f --- /dev/null +++ b/shell/ev-page-cache.c @@ -0,0 +1,485 @@ +#include "ev-page-cache.h" +#include "ev-job-queue.h" +#include +#include + +typedef struct _EvPageCacheInfo +{ + double width; + double height; +} +EvPageCacheInfo; + + +struct _EvPageCache +{ + GObject parent; + + gint current_page; + int n_pages; + char *title; + char **page_labels; + + gint max_label_chars; + gboolean has_labels; + gboolean uniform; + + double uniform_width; + double uniform_height; + + double max_width; + double max_height; + double* height_to_page; + double* dual_height_to_page; + + EvPageCacheInfo *size_cache; + EvDocumentInfo *page_info; +}; + +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; + page_cache->max_label_chars = 0; +} + +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); + g_free (page_cache->height_to_page); + g_free (page_cache->dual_height_to_page); + + ev_document_info_free (page_cache->page_info); +} + +EvPageCache * +ev_page_cache_new (EvDocument *document) +{ + EvPageCache *page_cache; + EvPageCacheInfo *info; + gint i; + double saved_height; + + page_cache = (EvPageCache *) g_object_new (EV_TYPE_PAGE_CACHE, NULL); + + ev_document_doc_mutex_lock (); + + /* We read page information out of the document */ + + /* Assume all pages are the same size until proven otherwise */ + page_cache->uniform = TRUE; + page_cache->has_labels = FALSE; + page_cache->n_pages = ev_document_get_n_pages (document); + page_cache->page_labels = g_new0 (char *, page_cache->n_pages); + page_cache->max_width = 0; + page_cache->max_height = 0; + page_cache->page_info = ev_document_get_info (document); + + if (page_cache->page_info->fields_mask & EV_DOCUMENT_INFO_TITLE) { + page_cache->title = g_strdup (page_cache->page_info->title); + } else { + page_cache->title = NULL; + } + + for (i = 0; i < page_cache->n_pages; i++) { + double page_width = 0; + double page_height = 0; + + ev_document_get_page_size (document, i, &page_width, &page_height); + + page_cache->page_labels[i] = ev_document_get_page_label (document, i); + + if (page_cache->page_labels[i] != NULL) { + + page_cache->max_label_chars = MAX(page_cache->max_label_chars, + g_utf8_strlen (page_cache->page_labels[i], 256)); + if (!page_cache->has_labels) { + gchar *expected_label; + + expected_label = g_strdup_printf ("%d", i + 1); + if (strcmp (expected_label, page_cache->page_labels[i])) + page_cache->has_labels = TRUE; + g_free (expected_label); + } + } + + if (page_width > page_cache->max_width) { + page_cache->max_width = page_width; + } + + if (page_height > page_cache->max_height) { + page_cache->max_height = page_height; + } + + if (i == 0) { + 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 = 0; j < i; j++) { + info = &(page_cache->size_cache [j]); + info->width = page_cache->uniform_width; + info->height = page_cache->uniform_height; + } + page_cache->uniform = FALSE; + + } + + if (! page_cache->uniform) { + info = &(page_cache->size_cache [i]); + + info->width = page_width; + info->height = page_height; + } + } + + page_cache->height_to_page = g_new0(double, page_cache->n_pages); + page_cache->dual_height_to_page = g_new0(double, page_cache->n_pages / 2 + 1); + + saved_height = 0; + for (i = 0; i < page_cache->n_pages; i++) { + + if (page_cache->uniform) { + page_cache->height_to_page [i] = (i + 1) * page_cache->uniform_height; + } else { + page_cache->height_to_page [i] = saved_height + page_cache->size_cache [i].height; + saved_height = page_cache->height_to_page [i]; + } + } + + saved_height = 0; + for (i = 0; i < page_cache->n_pages; i += 2) { + + if (page_cache->uniform) { + page_cache->dual_height_to_page [i / 2] = (i / 2 + 1) * page_cache->uniform_height; + } else { + if (i == page_cache->n_pages - 1) { + page_cache->dual_height_to_page [i / 2] = + saved_height + page_cache->size_cache [i].height; + } + else { + page_cache->dual_height_to_page [i / 2] = saved_height + + MAX(page_cache->size_cache [i].height, + page_cache->size_cache [i + 1].height); + saved_height = page_cache->dual_height_to_page [i / 2]; + } + } + } + + /* make some sanity check assertions */ + 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); + + ev_document_doc_mutex_unlock (); + + if (page_cache->n_pages > 0) + ev_page_cache_set_current_page (page_cache, 0); + + 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); +} + +gboolean +ev_page_cache_set_page_label (EvPageCache *page_cache, + const char *page_label) +{ + gint i, page; + long value; + char *endptr = NULL; + + g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE); + g_return_val_if_fail (page_label != NULL, FALSE); + + /* First, look for a literal label match */ + for (i = 0; i < page_cache->n_pages; i ++) { + if (page_cache->page_labels[i] != NULL && + ! strcmp (page_label, page_cache->page_labels[i])) { + ev_page_cache_set_current_page (page_cache, i); + return TRUE; + } + } + + /* Next, parse the label, and see if the number fits */ + value = strtol (page_label, &endptr, 10); + if (endptr[0] == '\0') { + /* Page number is an integer */ + page = MIN (G_MAXINT, value); + + /* convert from a page label to a page offset */ + page --; + if (page >= 0 && + page < page_cache->n_pages && + page_cache->page_labels[page] == NULL) { + ev_page_cache_set_current_page (page_cache, page); + return TRUE; + } + } + + return FALSE; +} + +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)); +} + +const 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]); + + if (width) + *width = info->width; + if (height) + *height = info->height; + } + + if (width) + *width = (int) ((*width) * scale + 0.5); + if (width) + *height = (int) ((*height) * scale + 0.5); + +} + + +void +ev_page_cache_get_max_width (EvPageCache *page_cache, + gfloat scale, + gint *width) +{ + g_return_if_fail (EV_IS_PAGE_CACHE (page_cache)); + + if (width) + *width = page_cache->max_width * scale; +} + +void +ev_page_cache_get_max_height (EvPageCache *page_cache, + gfloat scale, + gint *height) +{ + g_return_if_fail (EV_IS_PAGE_CACHE (page_cache)); + + if (height) + *height = page_cache->max_height * scale; +} + +void +ev_page_cache_get_height_to_page (EvPageCache *page_cache, + gint page, + gfloat scale, + gint *height, + gint *dual_height) +{ + double result = 0.0; + double dual_result = 0.0; + + g_return_if_fail (EV_IS_PAGE_CACHE (page_cache)); + + if (page > 0) + result = page_cache->height_to_page [page - 1]; + + if (height) + *height = result * scale; + + if (page > 1) + dual_result = page_cache->dual_height_to_page [page / 2 - 1]; + + if (dual_height) + *dual_height = dual_result * scale; +} + +gint +ev_page_cache_get_max_label_chars (EvPageCache *page_cache) +{ + g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), 0); + + return page_cache->max_label_chars; +} + +gchar * +ev_page_cache_get_page_label (EvPageCache *page_cache, + gint page) +{ + g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), NULL); + g_return_val_if_fail (page >= 0 && page < page_cache->n_pages, NULL); + + if (page_cache->page_labels[page] == NULL) + return g_strdup_printf ("%d", page + 1); + + return g_strdup (page_cache->page_labels[page]); +} + +gboolean +ev_page_cache_has_nonnumeric_page_labels (EvPageCache *page_cache) +{ + g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), FALSE); + return page_cache->has_labels; +} + +const EvDocumentInfo * +ev_page_cache_get_info (EvPageCache *page_cache) +{ + g_return_val_if_fail (EV_IS_PAGE_CACHE (page_cache), NULL); + + return page_cache->page_info; +} + + +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 - 1) + 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 <= 0) + return FALSE; + + ev_page_cache_set_current_page (page_cache, page_cache->current_page - 1); + return TRUE; +} + +#define PAGE_CACHE_STRING "ev-page-cache" + +EvPageCache * +ev_page_cache_get (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; +} + + -- cgit v0.9.1