]> www.fi.muni.cz Git - evince.git/commitdiff
New file with some random thoughts.
authorJonathan Blandford <jrb@redhat.com>
Wed, 2 Feb 2005 13:22:53 +0000 (13:22 +0000)
committerJonathan Blandford <jrb@src.gnome.org>
Wed, 2 Feb 2005 13:22:53 +0000 (13:22 +0000)
Wed Feb  2 21:13:11 2005  Jonathan Blandford  <jrb@redhat.com>

        * 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.

17 files changed:
ChangeLog
NOTES [new file with mode: 0644]
TODO
backend/ev-document-misc.c
backend/ev-document-misc.h
backend/ev-document.c
backend/ev-document.h
data/evince-ui.xml
pdf/xpdf/pdf-document.cc
pixbuf/pixbuf-document.c
ps/ps-document.c
shell/Makefile.am
shell/ev-page-view.c [new file with mode: 0644]
shell/ev-page-view.h [new file with mode: 0644]
shell/ev-sidebar-thumbnails.c
shell/ev-view.c
shell/ev-window.c

index 52bdc766bcd7b0afdfdd06467d32a6bfde23f993..e81b0e4888bbc81b877ca0f9ef84745b6938db6e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,41 @@
+Wed Feb  2 21:13:11 2005  Jonathan Blandford  <jrb@redhat.com>
+
+       * 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  <marco@gnome.org>
 
        * shell/ev-application.c: (ev_application_open):
diff --git a/NOTES b/NOTES
new file mode 100644 (file)
index 0000000..19b52b3
--- /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 82d61e54dc7165003b3b21607b291c55fcf1b601..65c5dd1f4039ad87433a6867ac940790fdb33cfd 100644 (file)
--- 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
index d7d4beb9285aad0b209b058e4b86d6e5d92777b0..4145b8a3687cbb224c3aa3cfe3919da8abf20f2d 100644 (file)
@@ -1,6 +1,7 @@
 
 #include "ev-document-misc.h"
 #include <string.h>
+#include <gtk/gtk.h>
 
 /* 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;
+       }
+}
+
index 1fae363360884e084aeb79a625f9e2404a8afbf5..a7ed645fd98864a10421a0599ce15b85dd5e85dc 100644 (file)
@@ -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 */
index 6f6a687eef0686f4345e88b9661b079f9e70423c..a53cbeafa6c1d4f082bc736600fe99c41b6fe72f 100644 (file)
@@ -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 *
index 5581cd713825df9385bc75f1e8cf7a3f9262b570..18819f41955a5db092cabeae1046a29605def54e 100644 (file)
@@ -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,
index c619e76e0526fe8a78a929fd0e7de9cef6baeb02..b1467c0339b078f47d83f235f413c6cae90e3e40 100644 (file)
     <toolitem action="ViewZoomOut"/>
     <toolitem action="ViewBestFit"/>
     <toolitem action="ViewPageWidth"/>
+<!--
+    <separator/>
+    <toolitem action="SinglePage"/>
+    <toolitem action="ContinuousPage"/>
+-->
   </toolbar>
 </ui>
index b913be852a9fec45a6c80fbf32fab1520d5a5fa2..1855222562df660d3f88a4fe77f4f9bdf4482865 100644 (file)
@@ -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())) {
index dc54e35c6c4d3bd347203df647045fc227fe406f..ab93f19b2c97d047295bff183f56da16dfe78755 100644 (file)
@@ -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)
 {
index fb1dd3d68e6a0a6befe41e38f57c549102c52dbb..fd6fc4a62d5785fcf250a806cda5b5e441f465d8 100644 (file)
@@ -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) {
index b43c25f48ade6749cb962b71083631e14b07ca8a..ad53afe1c096696b1fb9147a999f17c8b478fc07 100644 (file)
@@ -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 (file)
index 0000000..050e3cc
--- /dev/null
@@ -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 <gtk/gtk.h>
+
+/* 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 (file)
index 0000000..24b1930
--- /dev/null
@@ -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 <gtk/gtk.h>
+#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
index 4d54d1178cb4844ee1ac95995bd6853d61cbef95..2d7153985a23967ffa438c6408412136918001e4 100644 (file)
@@ -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 ("<i>%d</i>", i + 1);
+       for (i = 1; i <= n_pages; i++) {
+               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,
index 291b3c5d125d5e77d6f61f487593e6c4dfa701c9..a5fc7ce636a351d9f9bd6420cd724be0e706ddf2 100644 (file)
@@ -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)
index 9eadc5529a55f03ad462fc3f6c996caa1d50c7be..01c4f8a3ea9557876816afc0a6d0c6b9fe6a34ba 100644 (file)
@@ -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),