From: Jonathan Blandford Date: Wed, 2 Feb 2005 13:22:53 +0000 (+0000) Subject: New file with some random thoughts. X-Git-Tag: EVINCE_0_1_3~12 X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=commitdiff_plain;h=bebd9ceae1ec88ddee03bda8c7572c9cb06f6b77;p=evince.git New file with some random thoughts. Wed Feb 2 21:13:11 2005 Jonathan Blandford * NOTES: New file with some random thoughts. * TODO: Update. * backend/ev-document-misc.c: (ev_document_misc_get_page_border_size): New function to canonicalize shadow drawing sizes. Possibly goofy. * shell/ev-view.c: (ev_view_size_request), (set_document_page), (ev_view_best_fit), (ev_view_fit_width): * pdf/xpdf/pdf-document.cc: * pixbuf/pixbuf-document.c: (pixbuf_document_get_page_size): * ps/ps-document.c: (ps_document_get_page_size): * backend/ev-document-misc.h: * backend/ev-document.c: (ev_document_get_page_size): * backend/ev-document.h: get_page_size now takes a page number parameter. Made all the backends/frontends honor it. * data/evince-ui.xml: Added a multiple-page mode. Uncomment to see. Doesn't work yet. * shell/Makefile.am: * shell/ev-page-view.[ch]: New multi-page view. Really rough. Doesn't do anything yet. * shell/ev-sidebar-thumbnails.c: (ev_sidebar_thumbnails_set_document): [1..n_pages] instead of [0..n_pages-1] * shell/ev-window.c: (update_action_sensitivity), (ev_window_setup_document), (ev_window_set_page_mode), (ev_window_page_mode_cb), (ev_window_init): Clean up the view-swapping code a bit so we can have multiple views on a document. Add the multi-page view, though it can't be turned on yet. --- diff --git a/ChangeLog b/ChangeLog index 52bdc766..e81b0e48 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,41 @@ +Wed Feb 2 21:13:11 2005 Jonathan Blandford + + * NOTES: New file with some random thoughts. + + * TODO: Update. + + * backend/ev-document-misc.c: + (ev_document_misc_get_page_border_size): New function to + canonicalize shadow drawing sizes. Possibly goofy. + + * shell/ev-view.c: (ev_view_size_request), (set_document_page), + (ev_view_best_fit), (ev_view_fit_width): + * pdf/xpdf/pdf-document.cc: + * pixbuf/pixbuf-document.c: (pixbuf_document_get_page_size): + * ps/ps-document.c: (ps_document_get_page_size): + * backend/ev-document-misc.h: + * backend/ev-document.c: (ev_document_get_page_size): + * backend/ev-document.h: get_page_size now takes a page number + parameter. Made all the backends/frontends honor it. + + * data/evince-ui.xml: Added a multiple-page mode. Uncomment to + see. Doesn't work yet. + + * shell/Makefile.am: + * shell/ev-page-view.[ch]: New multi-page view. Really rough. + Doesn't do anything yet. + + * shell/ev-sidebar-thumbnails.c: + (ev_sidebar_thumbnails_set_document): [1..n_pages] instead of + [0..n_pages-1] + + * shell/ev-window.c: (update_action_sensitivity), + (ev_window_setup_document), (ev_window_set_page_mode), + (ev_window_page_mode_cb), (ev_window_init): Clean up the + view-swapping code a bit so we can have multiple views on a + document. Add the multi-page view, though it can't be turned on + yet. + 2005-02-01 Marco Pesenti Gritti * shell/ev-application.c: (ev_application_open): diff --git a/NOTES b/NOTES new file mode 100644 index 00000000..19b52b3e --- /dev/null +++ b/NOTES @@ -0,0 +1,30 @@ + +SOME RANDOM COMMENTS: +===================== + + * We assume that all documents can be broken down into a linear + collection of pages. + + * If a document type doesn't break down in such a way (like web pages) + then it's probably not a good fit for this application. + + * Each page has a natural page size in pixels. This is generally + ignored in favor of a scale-to-fit mode, but is occasionally + important for backends like the image backend. + + * Each page is not necessarily the same size. + + * We refer to pages by page number. This number ranges from 1 to + document->n_pages. A page index of -1 means the current set page, + and a page index of 0 is not used. + + +-- + +Thoughts on threading: + + * The primary thing we are trying to do is minimize switching pages, as + doing so is slow for backends. Additionally, some operations on the + backend are slow, leaving poor interactivity. This + +-- diff --git a/TODO b/TODO index 82d61e54..65c5dd1f 100644 --- a/TODO +++ b/TODO @@ -6,7 +6,13 @@ Improve Find system Display location of results in thumbnails? Only display thumbnails of pages found? -Implement multi-page view for continuous page scrolling +Move to three page views: + + * Single page (prolly default for some backends) + * Continuous scrolling + * Side-by-side continuous scrolling + +Sidebar improvements for ps/pixbuf, or PDF files without a TOC. Improve look of combobox Thumbnails/Index @@ -16,6 +22,16 @@ Document Properties Dialog for document meta-data Provide Desktop icon Thumbnailer for Documents +Make an object that handles the page count. + +Move to having three sizing types: + + * Free zooming + * constrain to width + * constrain to height + * also, maybe add a 1-1 button. Possibly dubious, though. + + ------- TODONE ------- (move finished TODO items here) Create a TODO list diff --git a/backend/ev-document-misc.c b/backend/ev-document-misc.c index d7d4beb9..4145b8a3 100644 --- a/backend/ev-document-misc.c +++ b/backend/ev-document-misc.c @@ -1,6 +1,7 @@ #include "ev-document-misc.h" #include +#include /* Returns a new GdkPixbuf that is suitable for placing in the thumbnail view. * It is four pixels wider and taller than the source. If source_pixbuf is not @@ -62,3 +63,31 @@ ev_document_misc_get_thumbnail_frame (int width, return retval; } + +void +ev_document_misc_get_page_border_size (gint page_width, + gint page_height, + gint *left_border, + gint *right_border, + gint *top_border, + gint *bottom_border) +{ + g_assert (left_border); + g_assert (right_border); + g_assert (top_border); + g_assert (bottom_border); + + *left_border = 1; + *top_border = 1; + if (page_width < 100) { + *right_border = 2; + *bottom_border = 2; + } else if (page_width < 500) { + *right_border = 3; + *left_border = 3; + } else { + *right_border = 4; + *bottom_border = 4; + } +} + diff --git a/backend/ev-document-misc.h b/backend/ev-document-misc.h index 1fae3633..a7ed645f 100644 --- a/backend/ev-document-misc.h +++ b/backend/ev-document-misc.h @@ -32,6 +32,13 @@ GdkPixbuf *ev_document_misc_get_thumbnail_frame (int width, int height, GdkPixbuf *source_pixbuf); +void ev_document_misc_get_page_border_size (gint page_width, + gint page_height, + gint *left_border, + gint *right_border, + gint *top_border, + gint *bottom_border); + G_END_DECLS #endif /* EV_DOCUMENT_MISC_H */ diff --git a/backend/ev-document.c b/backend/ev-document.c index 6f6a687e..a53cbeaf 100644 --- a/backend/ev-document.c +++ b/backend/ev-document.c @@ -164,11 +164,12 @@ ev_document_set_page_offset (EvDocument *document, void ev_document_get_page_size (EvDocument *document, + int page, int *width, int *height) { EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document); - iface->get_page_size (document, width, height); + iface->get_page_size (document, page, width, height); } char * diff --git a/backend/ev-document.h b/backend/ev-document.h index 5581cd71..18819f41 100644 --- a/backend/ev-document.h +++ b/backend/ev-document.h @@ -74,6 +74,7 @@ struct _EvDocumentIface int x, int y); void (* get_page_size) (EvDocument *document, + int page, int *width, int *height); char * (* get_text) (EvDocument *document, @@ -112,6 +113,7 @@ void ev_document_set_page_offset (EvDocument *document, int x, int y); void ev_document_get_page_size (EvDocument *document, + int page, int *width, int *height); char *ev_document_get_text (EvDocument *document, diff --git a/data/evince-ui.xml b/data/evince-ui.xml index c619e76e..b1467c03 100644 --- a/data/evince-ui.xml +++ b/data/evince-ui.xml @@ -56,5 +56,10 @@ + diff --git a/pdf/xpdf/pdf-document.cc b/pdf/xpdf/pdf-document.cc index b913be85..18552225 100644 --- a/pdf/xpdf/pdf-document.cc +++ b/pdf/xpdf/pdf-document.cc @@ -350,21 +350,32 @@ pdf_document_set_page_offset (EvDocument *document, static void pdf_document_get_page_size (EvDocument *document, + int page, int *width, int *height) { PdfDocument *pdf_document = PDF_DOCUMENT (document); + Page *the_page; + + /* set some default values */ + if (width) + *width = 1; + if (height) + *height = 1; - if (document_validate_page (pdf_document)) { + + if (page == -1 && document_validate_page (pdf_document)) { if (width) *width = pdf_document->out->getBitmapWidth(); if (height) *height = pdf_document->out->getBitmapHeight(); - } else { - if (width) - *width = 1; - if (height) - *height = 1; + return; + } + + the_page = pdf_document->doc->getCatalog ()->getPage (page); + if (the_page) { + *width = (int) the_page->getWidth (); + *height = (int) the_page->getHeight (); } } @@ -1244,8 +1255,7 @@ pdf_document_thumbnails_get_dimensions (EvDocumentThumbnails *document_thumbnail Thumb *thumb = NULL; gdouble page_ratio; - /* getPage seems to want page + 1 for some reason; */ - the_page = pdf_document->doc->getCatalog ()->getPage (page + 1); + the_page = pdf_document->doc->getCatalog ()->getPage (page); the_page->getThumb (&the_thumb); if (!(the_thumb.isNull () || the_thumb.isNone())) { diff --git a/pixbuf/pixbuf-document.c b/pixbuf/pixbuf-document.c index dc54e35c..ab93f19b 100644 --- a/pixbuf/pixbuf-document.c +++ b/pixbuf/pixbuf-document.c @@ -137,6 +137,7 @@ pixbuf_document_set_page_offset (EvDocument *document, static void pixbuf_document_get_page_size (EvDocument *document, + int page, int *width, int *height) { diff --git a/ps/ps-document.c b/ps/ps-document.c index fb1dd3d6..fd6fc4a6 100644 --- a/ps/ps-document.c +++ b/ps/ps-document.c @@ -1784,9 +1784,12 @@ ps_document_set_page_offset (EvDocument *document, static void ps_document_get_page_size (EvDocument *document, - int *width, - int *height) + int page, + int *width, + int *height) { + /* Post script documents never vary in size */ + PSDocument *gs = PS_DOCUMENT (document); if (width) { diff --git a/shell/Makefile.am b/shell/Makefile.am index b43c25f4..ad53afe1 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -25,6 +25,8 @@ evince_SOURCES= \ ev-marshal.h \ ev-page-action.c \ ev-page-action.h \ + ev-page-view.c \ + ev-page-view.h \ ev-password.h \ ev-password.c \ ev-password-view.h \ diff --git a/shell/ev-page-view.c b/shell/ev-page-view.c new file mode 100644 index 00000000..050e3cc8 --- /dev/null +++ b/shell/ev-page-view.c @@ -0,0 +1,678 @@ +/* + * Copyright (C) 2005 Jonathan Blandford + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ev-page-view.h" +#include "ev-marshal.h" +#include "ev-document-misc.h" +#include + +/* We keep a cached array of all the page sizes. The info is accessed via + * page_sizes [page - 1], as pages start at 1 */ +typedef struct _EvPageViewInfo +{ + gint width; + gint height; +} EvPageViewInfo; + +struct _EvPageViewPrivate +{ + gint width, height; + gint page_spacing; + + GdkWindow *bin_window; + EvDocument *document; + EvPageViewInfo *page_sizes; + + GtkAdjustment *hadjustment; + GtkAdjustment *vadjustment; + + gdouble scale; + + /* Page information*/ + gint n_pages; + gint max_page_width; + + /* these two are only set if uniform_page_size is set */ + gint uniform_page_width; + gint uniform_page_height; + guint uniform_page_size : 1; +}; + + +static void ev_page_view_init (EvPageView *page_view); +static void ev_page_view_class_init (EvPageViewClass *klass); +static void ev_page_view_set_scroll_adjustments (EvPageView *page_view, + GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment); +static void ev_page_view_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void ev_page_view_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gboolean ev_page_view_expose (GtkWidget *widget, + GdkEventExpose *expose); +static void ev_page_view_realize (GtkWidget *widget); +static void ev_page_view_unrealize (GtkWidget *widget); +static void ev_page_view_map (GtkWidget *widget); +static void ev_page_view_load (EvPageView *page_view); +static void ev_page_view_adjustment_changed (GtkAdjustment *adjustment, + EvPageView *page_view); +static void ev_page_view_update_size (EvPageView *page_view); + + +G_DEFINE_TYPE (EvPageView, ev_page_view, GTK_TYPE_WIDGET) + +#define EV_PAGE_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_PAGE_VIEW, EvPageViewPrivate)) + +static void +ev_page_view_init (EvPageView *page_view) +{ + page_view->priv = EV_PAGE_VIEW_GET_PRIVATE (page_view); + + page_view->priv->width = 1; + page_view->priv->height = 1; + page_view->priv->page_spacing = 10; + page_view->priv->scale = 1.0; + + /* Make some stuff up */ + page_view->priv->n_pages = 0; + page_view->priv->uniform_page_width = -1; + page_view->priv->uniform_page_height = -1; + page_view->priv->uniform_page_size = FALSE; +} + +static void +ev_page_view_class_init (EvPageViewClass *klass) +{ + GObjectClass *o_class; + GtkWidgetClass *widget_class; + + o_class = (GObjectClass *) klass; + widget_class = (GtkWidgetClass *) klass; + klass->set_scroll_adjustments = ev_page_view_set_scroll_adjustments; + + g_type_class_add_private (klass, sizeof (EvPageViewPrivate)); + widget_class->size_request = ev_page_view_size_request; + widget_class->size_allocate = ev_page_view_size_allocate; + widget_class->expose_event = ev_page_view_expose; + widget_class->realize = ev_page_view_realize; + widget_class->unrealize = ev_page_view_unrealize; + widget_class->map = ev_page_view_map; + + widget_class->set_scroll_adjustments_signal = + g_signal_new ("set_scroll_adjustments", + G_TYPE_FROM_CLASS (o_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EvPageViewClass, set_scroll_adjustments), + NULL, NULL, + ev_marshal_VOID__OBJECT_OBJECT, + G_TYPE_NONE, 2, + GTK_TYPE_ADJUSTMENT, + GTK_TYPE_ADJUSTMENT); + + +} + + +static void +ev_page_view_set_scroll_adjustments (EvPageView *page_view, + GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment) +{ + gboolean need_adjust = FALSE; + + if (hadjustment) + g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment)); + else + hadjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); + if (vadjustment) + g_return_if_fail (GTK_IS_ADJUSTMENT (vadjustment)); + else + vadjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); + + if (page_view->priv->hadjustment && (page_view->priv->hadjustment != hadjustment)) + { + g_signal_handlers_disconnect_matched (page_view->priv->hadjustment, G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, page_view); + g_object_unref (page_view->priv->hadjustment); + } + + if (page_view->priv->vadjustment && (page_view->priv->vadjustment != vadjustment)) + { + g_signal_handlers_disconnect_matched (page_view->priv->vadjustment, G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, page_view); + g_object_unref (page_view->priv->vadjustment); + } + + if (page_view->priv->hadjustment != hadjustment) + { + page_view->priv->hadjustment = hadjustment; + g_object_ref (page_view->priv->hadjustment); + gtk_object_sink (GTK_OBJECT (page_view->priv->hadjustment)); + + g_signal_connect (page_view->priv->hadjustment, "value_changed", + G_CALLBACK (ev_page_view_adjustment_changed), + page_view); + need_adjust = TRUE; + } + + if (page_view->priv->vadjustment != vadjustment) + { + page_view->priv->vadjustment = vadjustment; + g_object_ref (page_view->priv->vadjustment); + gtk_object_sink (GTK_OBJECT (page_view->priv->vadjustment)); + + g_signal_connect (page_view->priv->vadjustment, "value_changed", + G_CALLBACK (ev_page_view_adjustment_changed), + page_view); + need_adjust = TRUE; + } + + if (need_adjust) + ev_page_view_adjustment_changed (NULL, page_view); +} + +static void +ev_page_view_update_size (EvPageView *page_view) +{ + gint left_border; + gint right_border; + gint top_border; + gint bottom_border; + gint width, height; + + g_assert (page_view->priv->scale > 0.0); + + if (page_view->priv->uniform_page_size) { + width = (int) (page_view->priv->uniform_page_width * + page_view->priv->scale); + height = (int) (page_view->priv->uniform_page_height * + page_view->priv->scale); + + ev_document_misc_get_page_border_size (width, height, + & left_border, & right_border, + & top_border, & bottom_border); + + page_view->priv->width = width + + page_view->priv->page_spacing * 2 + + left_border + + right_border; + page_view->priv->height = + ((height + + page_view->priv->page_spacing + + top_border + + bottom_border) + * page_view->priv->n_pages) + + page_view->priv->page_spacing; + } else { + int i; + + page_view->priv->width = 0; + page_view->priv->height = page_view->priv->page_spacing; + + for (i = 0; i < page_view->priv->n_pages; i++) { + width = page_view->priv->page_sizes[i].width * + page_view->priv->scale; + height = page_view->priv->page_sizes[i].height * + page_view->priv->scale; + + ev_document_misc_get_page_border_size (width, height, + & left_border, & right_border, + & top_border, & bottom_border); + + width = width + + page_view->priv->page_spacing * 2 + + left_border + + right_border; + height = height + + page_view->priv->page_spacing + + top_border + + bottom_border; + + page_view->priv->width = MAX (width, page_view->priv->width); + page_view->priv->height += height; + } + } + +} + +static void +ev_page_view_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + EvPageView *page_view; + + page_view = EV_PAGE_VIEW (widget); + + ev_page_view_update_size (page_view); + + requisition->width = page_view->priv->width; + requisition->height = page_view->priv->height; +} + +static void +ev_page_view_paint_one_page (EvPageView *page_view, + GdkRectangle *area, + gint left_border, + gint right_border, + gint top_border, + gint bottom_border) +{ + GtkWidget *widget; + + widget = GTK_WIDGET (page_view); + + g_print ("paint one page (%d,%d) %dx%d\n", + area->x, area->y, + area->width, + area->height); + gdk_draw_rectangle (page_view->priv->bin_window, + widget->style->black_gc, + TRUE, + area->x, + area->y, + area->width, + area->height); + gdk_draw_rectangle (page_view->priv->bin_window, + widget->style->white_gc, + TRUE, + area->x + left_border, + area->y + top_border, + area->width - (left_border + right_border), + area->height - (top_border + bottom_border)); + gdk_draw_rectangle (page_view->priv->bin_window, + widget->style->mid_gc[widget->state], + TRUE, + area->x, + area->y + area->height - (bottom_border - top_border), + bottom_border - top_border, + bottom_border - top_border); + gdk_draw_rectangle (page_view->priv->bin_window, + widget->style->mid_gc[widget->state], + TRUE, + area->x + area->width - (right_border - left_border), + area->y, + right_border - left_border, + right_border - left_border); +} + +static void +ev_page_view_expose_uniform (GtkWidget *widget, + GdkEventExpose *expose) +{ + EvPageView *page_view; + gint left_border; + gint right_border; + gint top_border; + gint bottom_border; + int x_offset = 0; + GdkRectangle rectangle; + gint width, height; + int i; + + page_view = EV_PAGE_VIEW (widget); + + width = (int) (page_view->priv->uniform_page_width * + page_view->priv->scale); + height = (int) (page_view->priv->uniform_page_height * + page_view->priv->scale); + + if (widget->allocation.width > page_view->priv->width) + x_offset = (widget->allocation.width - page_view->priv->width)/2; + + ev_document_misc_get_page_border_size (width, height, + & left_border, + & right_border, + & top_border, + & bottom_border); + + rectangle.x = page_view->priv->page_spacing + x_offset; + rectangle.y = page_view->priv->page_spacing; + rectangle.width = width + + left_border + + right_border; + rectangle.height = height + + top_border + + bottom_border; + for (i = 0; i < page_view->priv->n_pages; i++) { + GdkRectangle unused; + + if (gdk_rectangle_intersect (&rectangle, + &expose->area, + &unused)) + ev_page_view_paint_one_page (page_view, + & rectangle, + left_border, right_border, + top_border, bottom_border); + rectangle.y += rectangle.height + + page_view->priv->page_spacing; + + } +} + +static void +ev_page_view_expose_pages (GtkWidget *widget, + GdkEventExpose *expose) +{ + EvPageView *page_view; + gint left_border; + gint right_border; + gint top_border; + gint bottom_border; + int x_offset = 0; + GdkRectangle rectangle; + gint width, height; + int i; + + page_view = EV_PAGE_VIEW (widget); + + width = (int) (page_view->priv->uniform_page_width * + page_view->priv->scale); + height = (int) (page_view->priv->uniform_page_height * + page_view->priv->scale); + + if (widget->allocation.width > page_view->priv->width) + x_offset = (widget->allocation.width - page_view->priv->width)/2; + + ev_document_misc_get_page_border_size (width, height, + & left_border, + & right_border, + & top_border, + & bottom_border); + + rectangle.x = page_view->priv->page_spacing + x_offset; + rectangle.y = page_view->priv->page_spacing; + rectangle.width = width + + left_border + + right_border; + rectangle.height = height + + top_border + + bottom_border; + for (i = 0; i < page_view->priv->n_pages; i++) { + GdkRectangle unused; + + if (gdk_rectangle_intersect (&rectangle, + &expose->area, + &unused)) + ev_page_view_paint_one_page (page_view, + & rectangle, + left_border, right_border, + top_border, bottom_border); + rectangle.y += rectangle.height + + page_view->priv->page_spacing; + + } +} + +static gboolean +ev_page_view_expose (GtkWidget *widget, + GdkEventExpose *expose) +{ + EvPageView *page_view; + + page_view = EV_PAGE_VIEW (widget); + + if (expose->window != page_view->priv->bin_window) + return FALSE; + + if (page_view->priv->uniform_page_size) { + ev_page_view_expose_uniform (widget, expose); + } else { + ev_page_view_expose_pages (widget, expose); + } + + return TRUE; +} + +static void +ev_page_view_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + EvPageView *page_view; + + widget->allocation = *allocation; + + page_view = EV_PAGE_VIEW (widget); + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + gdk_window_resize (page_view->priv->bin_window, + MAX (page_view->priv->width, allocation->width), + MAX (page_view->priv->height, allocation->height)); + } + + page_view->priv->hadjustment->page_size = allocation->width; + page_view->priv->hadjustment->page_increment = allocation->width * 0.9; + page_view->priv->hadjustment->step_increment = allocation->width * 0.1; + page_view->priv->hadjustment->lower = 0; + page_view->priv->hadjustment->upper = MAX (allocation->width, page_view->priv->width); + gtk_adjustment_changed (page_view->priv->hadjustment); + + page_view->priv->vadjustment->page_size = allocation->height; + page_view->priv->vadjustment->page_increment = allocation->height * 0.9; + page_view->priv->vadjustment->step_increment = allocation->width * 0.1; + page_view->priv->vadjustment->lower = 0; + page_view->priv->vadjustment->upper = MAX (allocation->height, page_view->priv->height); + gtk_adjustment_changed (page_view->priv->vadjustment); +} + +static void +ev_page_view_adjustment_changed (GtkAdjustment *adjustment, + EvPageView *page_view) +{ + if (GTK_WIDGET_REALIZED (page_view)) { + gdk_window_move (page_view->priv->bin_window, + - page_view->priv->hadjustment->value, + - page_view->priv->vadjustment->value); + + gdk_window_process_updates (page_view->priv->bin_window, TRUE); + } +} + +static void +ev_page_view_realize_document (EvPageView *page_view) +{ + if (page_view->priv->document == NULL) + return; + + ev_document_set_target (page_view->priv->document, + page_view->priv->bin_window); + ev_page_view_load (page_view); + gtk_widget_queue_resize (GTK_WIDGET (page_view)); +} + + +static void +ev_page_view_realize (GtkWidget *widget) +{ + EvPageView *page_view; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (EV_IS_PAGE_VIEW (widget)); + + page_view = EV_PAGE_VIEW (widget); + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + /* Make the main, clipping window */ + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + /* Make the window for the page view */ + attributes.x = 0; + attributes.y = 0; + attributes.width = MAX (page_view->priv->width, widget->allocation.width); + attributes.height = MAX (page_view->priv->height, widget->allocation.height); + attributes.event_mask = (GDK_EXPOSURE_MASK | + GDK_SCROLL_MASK | + GDK_POINTER_MOTION_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_KEY_PRESS_MASK | + GDK_KEY_RELEASE_MASK) | + gtk_widget_get_events (widget); + + page_view->priv->bin_window = gdk_window_new (widget->window, + &attributes, attributes_mask); + gdk_window_set_user_data (page_view->priv->bin_window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gdk_window_set_background (page_view->priv->bin_window, &widget->style->mid[widget->state]); + gdk_window_set_background (widget->window, &widget->style->mid[widget->state]); + + ev_page_view_realize_document (page_view); +} + + +static void +ev_page_view_unrealize (GtkWidget *widget) +{ + EvPageView *page_view; + + page_view = EV_PAGE_VIEW (widget); + + gdk_window_set_user_data (page_view->priv->bin_window, NULL); + gdk_window_destroy (page_view->priv->bin_window); + page_view->priv->bin_window = NULL; + + /* GtkWidget::unrealize destroys children and widget->window */ + if (GTK_WIDGET_CLASS (ev_page_view_parent_class)->unrealize) + (* GTK_WIDGET_CLASS (ev_page_view_parent_class)->unrealize) (widget); +} + +static void +ev_page_view_map (GtkWidget *widget) +{ + EvPageView *page_view; + + page_view = EV_PAGE_VIEW (widget); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + + gdk_window_show (page_view->priv->bin_window); + gdk_window_show (widget->window); +} + +static void +ev_page_view_load (EvPageView *page_view) +{ + int i; + gboolean uniform_page_size = TRUE; + int width = 0, height = 0; + + page_view->priv->n_pages = + ev_document_get_n_pages (page_view->priv->document); + + for (i = 1; i <= page_view->priv->n_pages; i++) { + EvPageViewInfo *info; + gint page_width = 0; + gint page_height = 0; + + ev_document_set_scale (page_view->priv->document, page_view->priv->scale); + ev_document_get_page_size (page_view->priv->document, + i, + &page_width, &page_height); + + if (i == 1) { + width = page_width; + height = page_height; + } else if (width != page_width || height != page_height) { + /* It's a different page size. Backfill the array. */ + int j; + + uniform_page_size = FALSE; + + page_view->priv->page_sizes = + g_new0 (EvPageViewInfo, page_view->priv->n_pages); + + for (j = 1; j < i; j++) { + + info = &(page_view->priv->page_sizes[j - 1]); + info->width = width; + info->height = height; + } + } + + if (! uniform_page_size) { + info = &(page_view->priv->page_sizes[i - 1]); + + info->width = page_width; + info->height = page_height; + } + } + + page_view->priv->uniform_page_size = uniform_page_size; + + if (uniform_page_size) { + page_view->priv->uniform_page_width = width; + page_view->priv->uniform_page_height = height; + } + + ev_page_view_update_size (page_view); + + gtk_widget_queue_resize (GTK_WIDGET (page_view)); +} + +/* Public functions */ +GtkWidget * +ev_page_view_new (void) +{ + return g_object_new (EV_TYPE_PAGE_VIEW, NULL); +} + +void +ev_page_view_set_document (EvPageView *page_view, + EvDocument *document) +{ + g_return_if_fail (EV_IS_PAGE_VIEW (page_view)); + + if (document != page_view->priv->document) { + if (page_view->priv->document) { + g_object_unref (page_view->priv->document); + } + + page_view->priv->document = document; + + if (page_view->priv->document) { + g_object_ref (page_view->priv->document); + } + + if (GTK_WIDGET_REALIZED (page_view)) { + ev_page_view_realize_document (page_view); + } + } + +} + diff --git a/shell/ev-page-view.h b/shell/ev-page-view.h new file mode 100644 index 00000000..24b1930c --- /dev/null +++ b/shell/ev-page-view.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2004 Jonathan Blandforde + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EV_PAGE_VIEW_H +#define EV_PAGE_VIEW_H + +#include +#include "ev-document.h" + +G_BEGIN_DECLS + +#define EV_TYPE_PAGE_VIEW (ev_page_view_get_type ()) +#define EV_PAGE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_PAGE_VIEW, EvPageView)) +#define EV_PAGE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_PAGE_VIEW, EvPageViewClass)) +#define EV_IS_PAGE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_PAGE_VIEW)) +#define EV_IS_PAGE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EV_TYPE_PAGE_VIEW)) +#define EV_PAGE_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EV_TYPE_PAGE_VIEW, EvPageViewClass)) + +typedef struct _EvPageView EvPageView; +typedef struct _EvPageViewPrivate EvPageViewPrivate; +typedef struct _EvPageViewClass EvPageViewClass; + +struct _EvPageView +{ + GtkWidget parent; + + /*< private >*/ + EvPageViewPrivate *priv; +}; + +struct _EvPageViewClass +{ + GtkWidgetClass parent_class; + + void (* set_scroll_adjustments) (EvPageView *page_view, + GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment); +}; + +GType ev_page_view_get_type (void); +GtkWidget *ev_page_view_new (void); +void ev_page_view_set_document (EvPageView *page_view, + EvDocument *document); + + +G_END_DECLS + +#endif diff --git a/shell/ev-sidebar-thumbnails.c b/shell/ev-sidebar-thumbnails.c index 4d54d117..2d715398 100644 --- a/shell/ev-sidebar-thumbnails.c +++ b/shell/ev-sidebar-thumbnails.c @@ -352,11 +352,11 @@ ev_sidebar_thumbnails_set_document (EvSidebarThumbnails *sidebar_thumbnails, /* We get the dimensions of the first doc so that we can make a blank * icon. */ ev_document_thumbnails_get_dimensions (EV_DOCUMENT_THUMBNAILS (priv->document), - 0, THUMBNAIL_WIDTH, &width, &height); + 1, THUMBNAIL_WIDTH, &width, &height); loading_icon = ev_document_misc_get_thumbnail_frame (width, height, NULL); - for (i = 0; i < n_pages; i++) { - page = g_strdup_printf ("%d", i + 1); + for (i = 1; i <= n_pages; i++) { + page = g_strdup_printf ("%d", i); gtk_list_store_append (priv->list_store, &iter); gtk_list_store_set (priv->list_store, &iter, COLUMN_PAGE_STRING, page, diff --git a/shell/ev-view.c b/shell/ev-view.c index 291b3c5d..a5fc7ce6 100644 --- a/shell/ev-view.c +++ b/shell/ev-view.c @@ -209,6 +209,7 @@ ev_view_size_request (GtkWidget *widget, if (GTK_WIDGET_REALIZED (widget)) { if (view->document) { ev_document_get_page_size (view->document, + -1, &requisition->width, &requisition->height); } else { @@ -950,6 +951,7 @@ set_document_page (EvView *view, int page) int old_width, old_height; ev_document_get_page_size (view->document, + -1, &old_width, &old_height); if (old_page != page) { @@ -964,6 +966,7 @@ set_document_page (EvView *view, int page) 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)); @@ -1216,7 +1219,7 @@ ev_view_best_fit (EvView *view) int width, height; width = height = 0; - ev_document_get_page_size (view->document, &width, &height); + ev_document_get_page_size (view->document, -1, &width, &height); scale = 1.0; if (width != 0 && height != 0) { @@ -1238,7 +1241,7 @@ ev_view_fit_width (EvView *view) int width; width = 0; - ev_document_get_page_size (view->document, &width, NULL); + ev_document_get_page_size (view->document, -1, &width, NULL); scale = 1.0; if (width != 0) diff --git a/shell/ev-window.c b/shell/ev-window.c index 9eadc552..01c4f8a3 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -34,6 +34,7 @@ #include "ev-sidebar-links.h" #include "ev-sidebar-thumbnails.h" #include "ev-view.h" +#include "ev-page-view.h" #include "ev-password.h" #include "ev-password-view.h" #include "ev-print-job.h" @@ -70,6 +71,7 @@ struct _EvWindowPrivate { GtkWidget *find_bar; GtkWidget *scrolled_window; GtkWidget *view; + GtkWidget *page_view; GtkWidget *password_view; GtkActionGroup *action_group; GtkUIManager *ui_manager; @@ -81,6 +83,7 @@ struct _EvWindowPrivate { EvDocument *document; + EvWindowPageMode page_mode; /* These members are used temporarily when in PAGE_MODE_PASSWORD */ EvDocument *password_document; GtkWidget *password_dialog; @@ -119,9 +122,11 @@ static void update_action_sensitivity (EvWindow *ev_window) { EvDocument *document; + EvWindowPageMode page_mode; EvView *view; document = ev_window->priv->document; + page_mode = ev_window->priv->page_mode; view = EV_VIEW (ev_window->priv->view); @@ -160,12 +165,20 @@ update_action_sensitivity (EvWindow *ev_window) set_action_sensitive (ev_window, "GoFirstPage", page > 1); set_action_sensitive (ev_window, "GoLastPage", page < n_pages); } else { - set_action_sensitive (ev_window, "GoFirstPage", FALSE); + set_action_sensitive (ev_window, "GoFirstPage", FALSE); set_action_sensitive (ev_window, "GoPageUp", FALSE); set_action_sensitive (ev_window, "GoPageDown", FALSE); set_action_sensitive (ev_window, "GoLastPage", FALSE); } + /* Page View radio group */ + if (document) { + set_action_sensitive (ev_window, "SinglePage", page_mode != PAGE_MODE_PASSWORD); + set_action_sensitive (ev_window, "ContinuousPage", page_mode != PAGE_MODE_PASSWORD); + } else { + set_action_sensitive (ev_window, "SinglePage", FALSE); + set_action_sensitive (ev_window, "ContinuousPage", FALSE); + } /* Help menu */ /* "HelpContents": always sensitive */ /* "HelpAbout": always sensitive */ @@ -313,6 +326,7 @@ ev_window_setup_document (EvWindow *ev_window) { EvDocument *document; EvView *view = EV_VIEW (ev_window->priv->view); + EvPageView *page_view = EV_PAGE_VIEW (ev_window->priv->page_view); EvSidebar *sidebar = EV_SIDEBAR (ev_window->priv->sidebar); document = ev_window->priv->document; @@ -326,8 +340,9 @@ ev_window_setup_document (EvWindow *ev_window) ev_sidebar_set_document (sidebar, document); ev_view_set_document (view, document); + ev_page_view_set_document (page_view, document); - update_window_title (ev_window->priv->document, NULL, ev_window); + update_window_title (document, NULL, ev_window); update_total_pages (ev_window); update_action_sensitivity (ev_window); } @@ -991,6 +1006,11 @@ ev_window_set_page_mode (EvWindow *window, GtkWidget *child = NULL; GtkWidget *real_child; + if (window->priv->page_mode == page_mode) + return; + + window->priv->page_mode = page_mode; + switch (page_mode) { case PAGE_MODE_SINGLE_PAGE: child = window->priv->view; @@ -998,10 +1018,13 @@ ev_window_set_page_mode (EvWindow *window, case PAGE_MODE_PASSWORD: child = window->priv->password_view; break; + case PAGE_MODE_CONTINUOUS_PAGE: + child = window->priv->page_view; + break; default: - g_warning ("page_mode not implemented yet\n"); g_assert_not_reached (); } + real_child = gtk_bin_get_child (GTK_BIN (window->priv->scrolled_window)); if (child != real_child) { gtk_container_remove (GTK_CONTAINER (window->priv->scrolled_window), @@ -1009,6 +1032,7 @@ ev_window_set_page_mode (EvWindow *window, gtk_container_add (GTK_CONTAINER (window->priv->scrolled_window), child); } + update_action_sensitivity (window); } static void @@ -1312,6 +1336,21 @@ find_bar_close_cb (EggFindBar *find_bar, ev_window_update_fullscreen_popup (ev_window); } +static void +ev_window_page_mode_cb (GtkRadioAction *action, + GtkRadioAction *activated_action, + EvWindow *window) +{ + int mode; + + mode = gtk_radio_action_get_current_value (action); + + g_assert (mode == PAGE_MODE_CONTINUOUS_PAGE || + mode == PAGE_MODE_SINGLE_PAGE); + + ev_window_set_page_mode (window, (EvWindowPageMode) mode); +} + static void find_bar_search_changed_cb (EggFindBar *find_bar, GParamSpec *param, @@ -1489,6 +1528,15 @@ static GtkToggleActionEntry toggle_entries[] = { G_CALLBACK (ev_window_cmd_view_fullscreen) }, }; +static GtkRadioActionEntry page_view_entries[] = { + { "SinglePage", GTK_STOCK_DND, N_("Single"), NULL, + N_("Show the document one page at a time"), + PAGE_MODE_SINGLE_PAGE }, + { "ContinuousPage", GTK_STOCK_DND_MULTIPLE, N_("Multi"), NULL, + N_("Show the full document at once"), + PAGE_MODE_CONTINUOUS_PAGE } +}; + static void goto_page_cb (GtkAction *action, int page_number, EvWindow *ev_window) { @@ -1540,6 +1588,7 @@ ev_window_init (EvWindow *ev_window) ev_window->priv = EV_WINDOW_GET_PRIVATE (ev_window); + ev_window->priv->page_mode = PAGE_MODE_SINGLE_PAGE; update_window_title (NULL, NULL, ev_window); ev_window->priv->main_box = gtk_vbox_new (FALSE, 0); @@ -1554,6 +1603,11 @@ ev_window_init (EvWindow *ev_window) gtk_action_group_add_toggle_actions (action_group, toggle_entries, G_N_ELEMENTS (toggle_entries), ev_window); + gtk_action_group_add_radio_actions (action_group, page_view_entries, + G_N_ELEMENTS (page_view_entries), + ev_window->priv->page_mode, + G_CALLBACK (ev_window_page_mode_cb), + ev_window); set_short_labels (action_group); register_custom_actions (ev_window, action_group); @@ -1625,15 +1679,19 @@ ev_window_init (EvWindow *ev_window) ev_window->priv->scrolled_window); ev_window->priv->view = ev_view_new (); + ev_window->priv->page_view = ev_page_view_new (); ev_window->priv->password_view = ev_password_view_new (); g_signal_connect_swapped (ev_window->priv->password_view, "unlock", G_CALLBACK (ev_window_popup_password_dialog), ev_window); gtk_widget_show (ev_window->priv->view); + gtk_widget_show (ev_window->priv->page_view); gtk_widget_show (ev_window->priv->password_view); + /* We own a ref on these widgets, as we can swap them in and out */ g_object_ref (ev_window->priv->view); + g_object_ref (ev_window->priv->page_view); g_object_ref (ev_window->priv->password_view); gtk_container_add (GTK_CONTAINER (ev_window->priv->scrolled_window),