]> www.fi.muni.cz Git - evince.git/commitdiff
New function to canonicalize sizing/painting a border.
authorJonathan Blandford <jrb@redhat.com>
Wed, 16 Feb 2005 03:38:12 +0000 (03:38 +0000)
committerJonathan Blandford <jrb@src.gnome.org>
Wed, 16 Feb 2005 03:38:12 +0000 (03:38 +0000)
Tue Feb 15 22:27:13 2005  Jonathan Blandford  <jrb@redhat.com>

        * backend/ev-document-misc.h:
        * backend/ev-document-misc.c:
        (ev_document_misc_get_page_border_size),
        (ev_document_misc_paint_one_page): New function to canonicalize
        sizing/painting a border.

        * shell/Makefile.am: Remove ev-page-view.c entirely as it's not
        used.

        * pdf/xpdf/pdf-document.cc: use new function

        * shell/ev-view.c: (ev_view_size_request), (expose_bin_window),
        (ev_view_init), (ev_view_set_mode), (ev_view_zoom),
        (ev_view_best_fit), (ev_view_fit_width): * shell/ev-view.h: *
        shell/ev-window.c: (update_sizing_buttons),
        (ev_window_setup_document), (ev_window_cmd_view_zoom_in),
        (ev_window_cmd_view_zoom_out), (ev_window_cmd_view_best_fit),
        (ev_window_cmd_view_page_width), (size_allocate_cb),
        (ev_window_set_sizing_mode), (ev_window_init): make the "best fit"
        and "fit width" values act as toggle buttons so they stay
        toggled.  It's not 100% perfect, and it's a little slow, but it's
        good enough to commit I think.

ChangeLog
backend/ev-document-misc.c
backend/ev-document-misc.h
pdf/xpdf/pdf-document.cc
shell/Makefile.am
shell/ev-view.c
shell/ev-view.h
shell/ev-window.c

index a52b52f7c618a9902e76a96596cbd364bd334d10..9151621b1055a25f793a5ea9ab766ffaf2b07b2e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+Tue Feb 15 22:27:13 2005  Jonathan Blandford  <jrb@redhat.com>
+
+       * backend/ev-document-misc.h:
+       * backend/ev-document-misc.c:
+       (ev_document_misc_get_page_border_size),
+       (ev_document_misc_paint_one_page): New function to canonicalize
+       sizing/painting a border.
+
+       * shell/Makefile.am: Remove ev-page-view.c entirely as it's not
+       used.
+
+       * pdf/xpdf/pdf-document.cc: use new function
+
+       * shell/ev-view.c: (ev_view_size_request), (expose_bin_window),
+       (ev_view_init), (ev_view_set_mode), (ev_view_zoom),
+       (ev_view_best_fit), (ev_view_fit_width): * shell/ev-view.h: *
+       shell/ev-window.c: (update_sizing_buttons),
+       (ev_window_setup_document), (ev_window_cmd_view_zoom_in),
+       (ev_window_cmd_view_zoom_out), (ev_window_cmd_view_best_fit),
+       (ev_window_cmd_view_page_width), (size_allocate_cb),
+       (ev_window_set_sizing_mode), (ev_window_init): make the "best fit"
+       and "fit width" values act as toggle buttons so they stay
+       toggled.  It's not 100% perfect, and it's a little slow, but it's
+       good enough to commit I think.
+
 2005-02-15  David Lodge  <dave@cirt.net>
 
        * configure.ac (ALL_LINGUAS): Added "en_GB" (English (British)).
index 4145b8a3687cbb224c3aa3cfe3919da8abf20f2d..bb5eedbfe64eefae5afe66e0e6e4a78049cfa11a 100644 (file)
@@ -65,29 +65,60 @@ ev_document_misc_get_thumbnail_frame (int        width,
 }
 
 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)
+ev_document_misc_get_page_border_size (gint       page_width,
+                                      gint       page_height,
+                                      GtkBorder *border)
 {
-       g_assert (left_border);
-       g_assert (right_border);
-       g_assert (top_border);
-       g_assert (bottom_border);
+       g_assert (border);
 
-       *left_border = 1;
-       *top_border = 1;
+       border->left = 1;
+       border->top = 1;
        if (page_width < 100) {
-               *right_border = 2;
-               *bottom_border = 2;
+               border->right = 2;
+               border->bottom = 2;
        } else if (page_width < 500) {
-               *right_border = 3;
-               *left_border = 3;
+               border->right = 3;
+               border->bottom = 3;
        } else {
-               *right_border = 4;
-               *bottom_border = 4;
+               border->right = 4;
+               border->bottom = 4;
        }
 }
 
+
+void
+ev_document_misc_paint_one_page (GdkDrawable  *drawable,
+                                GtkWidget    *widget,
+                                GdkRectangle *area,
+                                GtkBorder    *border)
+{
+       gdk_draw_rectangle (drawable,
+                           widget->style->black_gc,
+                           TRUE,
+                           area->x,
+                           area->y,
+                           area->width,
+                           area->height);
+       gdk_draw_rectangle (drawable,
+                           widget->style->white_gc,
+                           TRUE,
+                           area->x + border->left,
+                           area->y + border->top,
+                           area->width - (border->left + border->right),
+                           area->height - (border->top + border->bottom));
+       gdk_draw_rectangle (drawable,
+                           widget->style->mid_gc[widget->state],
+                           TRUE,
+                           area->x,
+                           area->y + area->height - (border->bottom - border->top),
+                           border->bottom - border->top,
+                           border->bottom - border->top);
+       gdk_draw_rectangle (drawable,
+                           widget->style->mid_gc[widget->state],
+                           TRUE,
+                           area->x + area->width - (border->right - border->left),
+                           area->y,
+                           border->right - border->left,
+                           border->right - border->left);
+
+}
index a7ed645fd98864a10421a0599ce15b85dd5e85dc..05d7f6370601eb562337d986d130e4677f1d47ad 100644 (file)
 
 
 #include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gtk/gtkstyle.h>
 
 G_BEGIN_DECLS
 
 
-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);
+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,
+                                                 GtkBorder    *border);
+void       ev_document_misc_paint_one_page       (GdkDrawable  *drawable,
+                                                 GtkWidget    *widget,
+                                                 GdkRectangle *area,
+                                                 GtkBorder    *border);
 
 G_END_DECLS
 
index ccdf64b4ad8b9de352e8e8310440e26ceda4fd28..bb769cc9b21d804c7d1b1c6e32ff2101f6112a40 100644 (file)
@@ -23,9 +23,9 @@
 #include "pdf-document.h"
 #include "ev-ps-exporter.h"
 #include "ev-document-find.h"
+#include "ev-document-misc.h"
 #include "gpdf-g-switch.h"
 #include "ev-document-links.h"
-#include "ev-document-misc.h"
 #include "ev-document-security.h"
 #include "ev-document-thumbnails.h"
 
index 0d73ffe53e339e0a8d24c9ded01f79b9cbae1bab..40748c9848fe0d28bf9f581aa442ef609b707efe 100644 (file)
@@ -25,8 +25,6 @@ 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              \
index e3c81a05b5c85b4d256cf2d93a758fd91e446ba4..f8fc8bed19f2e75398922be0012e2f2f9a65c35b 100644 (file)
@@ -29,6 +29,7 @@
 #include "ev-marshal.h"
 #include "ev-view.h"
 #include "ev-document-find.h"
+#include "ev-document-misc.h"
 #include "ev-debug.h"
 
 #define EV_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_VIEW, EvViewClass))
@@ -62,6 +63,14 @@ typedef enum {
        EV_VIEW_CURSOR_WAIT
 } EvViewCursor;
 
+#define ZOOM_IN_FACTOR  1.2
+#define ZOOM_OUT_FACTOR (1.0/ZOOM_IN_FACTOR)
+
+#define MIN_SCALE 0.05409
+#define MAX_SCALE 18.4884
+#define ZOOM_EPSILON 1e-10
+
+
 struct _EvView {
        GtkWidget parent_instance;
 
@@ -86,8 +95,10 @@ struct _EvView {
 
        int find_page;
        int find_result;
+       int spacing;
 
        double scale;
+       EvSizingMode sizing_mode;
 };
 
 struct _EvViewClass {
@@ -208,22 +219,39 @@ ev_view_size_request (GtkWidget      *widget,
                      GtkRequisition *requisition)
 {
        EvView *view = EV_VIEW (widget);
+       GtkBorder border;
+       gint width, height;
 
-       if (GTK_WIDGET_REALIZED (widget)) {
-               if (view->document) {
-                       ev_document_get_page_size (view->document,
-                                                  -1,
-                                                  &requisition->width,
-                                                  &requisition->height);
-               } else {
-                       requisition->width = 10;
-                       requisition->height = 10;
-               }
+       if (! GTK_WIDGET_REALIZED (widget))
+               return;
 
-               requisition->width += 2;
-               requisition->height += 2;
+       if (! view->document) {
+               requisition->width = 1;
+               requisition->height = 1;
+               return;
+       }
+
+       ev_document_get_page_size (view->document, -1,
+                                  &width, &height);
+       ev_document_misc_get_page_border_size (width, height, &border);
+
+       switch (view->sizing_mode) {
+       case EV_SIZING_BEST_FIT:
+               requisition->width = MIN_SCALE * ((float) width) / view->scale;
+               requisition->height = MIN_SCALE * ((float) height) / view->scale;
+               break;
+       case EV_SIZING_FIT_WIDTH:
+               requisition->width = MIN_SCALE * ((float) width) / view->scale;
+               requisition->height = height + border.top + border.bottom;
+               requisition->height += view->spacing * 2;
+               break;
+       case EV_SIZING_FREE:
+               requisition->width = width + border.left + border.right;
+               requisition->height = height + border.top + border.bottom;
+               requisition->width += view->spacing * 2;
+               requisition->height += view->spacing * 2;
+               break;
        }
-  
 }
 
 static void
@@ -385,31 +413,44 @@ highlight_find_results (EvView *view)
         }
 }
 
+
 static void
 expose_bin_window (GtkWidget      *widget,
                   GdkEventExpose *event)
 {
        EvView *view = EV_VIEW (widget);
        int x_offset, y_offset;
-
+       GtkBorder border;
+       gint width, height;
+       GdkRectangle area;
+       int target_width, target_height;
+                       
        if (view->document == NULL)
                return;
 
-       x_offset = MAX (0, (widget->allocation.width -
-                           widget->requisition.width) / 2);
-       y_offset = MAX (0, (widget->allocation.height -
-                           widget->requisition.height) / 2);
-       gdk_draw_rectangle (view->bin_window,
-                            widget->style->black_gc,
-                            FALSE,
-                            x_offset,
-                           y_offset,
-                            widget->requisition.width - 1,
-                           widget->requisition.height - 1);
-
+       ev_document_get_page_size (view->document, -1,
+                                  &width, &height);
+       ev_document_misc_get_page_border_size (width, height, &border);
+       
+       x_offset = view->spacing;
+       y_offset = view->spacing;
+       target_width = width + border.left + border.right + view->spacing * 2;
+       target_height = height + border.top + border.bottom + view->spacing * 2;
+
+       x_offset += MAX (0, (widget->allocation.width - target_width) / 2);
+       y_offset += MAX (0, (widget->allocation.height - target_height) / 2);
+
+       /* Paint the frame */
+       area.x = x_offset;
+       area.y = y_offset;
+       area.width = width + border.left + border.right;
+       area.height = height + border.top + border.bottom;
+       ev_document_misc_paint_one_page (view->bin_window, widget, &area, &border);
+
+       /* Render the document itself */
        ev_document_set_page_offset (view->document,
-                                    x_offset + 1,
-                                    y_offset + 1);
+                                    x_offset + border.left,
+                                    y_offset + border.top);
 
        LOG ("Render area %d %d %d %d", event->area.x, event->area.y,
              event->area.width, event->area.height);
@@ -912,9 +953,11 @@ ev_view_init (EvView *view)
 {
        GTK_WIDGET_SET_FLAGS (view, GTK_CAN_FOCUS);
 
+       view->spacing = 10;
        view->scale = 1.0;
        view->pressed_button = -1;
        view->cursor = EV_VIEW_CURSOR_NORMAL;
+       view->sizing_mode = EV_SIZING_BEST_FIT;
 }
 
 static void
@@ -1143,6 +1186,17 @@ ev_view_set_document (EvView     *view,
        }
 }
 
+void
+ev_view_set_mode (EvView       *view,
+                 EvSizingMode  sizing_mode)
+{
+       if (view->sizing_mode == sizing_mode)
+               return;
+
+       view->sizing_mode = sizing_mode;
+       gtk_widget_queue_resize (GTK_WIDGET (view));
+}
+
 static void
 go_to_link (EvView *view, EvLink *link)
 {
@@ -1190,12 +1244,6 @@ ev_view_get_page (EvView *view)
                return 1;
 }
 
-#define ZOOM_IN_FACTOR  1.2
-#define ZOOM_OUT_FACTOR (1.0/ZOOM_IN_FACTOR)
-
-#define MIN_SCALE 0.05409
-#define MAX_SCALE 18.4884
-
 static void
 ev_view_zoom (EvView   *view,
              double    factor,
@@ -1208,7 +1256,12 @@ ev_view_zoom (EvView   *view,
        else
                scale = factor;
 
-       view->scale = CLAMP (scale, MIN_SCALE, MAX_SCALE);
+       scale = CLAMP (scale, MIN_SCALE, MAX_SCALE);
+
+       if (ABS (scale - view->scale) < ZOOM_EPSILON)
+               return;
+
+       view->scale = scale;
 
        ev_document_set_scale (view->document, view->scale);
 
@@ -1234,64 +1287,72 @@ ev_view_normal_size (EvView *view)
 }
 
 /* Unfortunately this is not idempotent (!) (numerical stability
- * issues because width and height are rounded)
- *
- * One more reason to make this a toggle and not a command */
+ * issues because width and height are rounded) */
 void
 ev_view_best_fit (EvView *view, int allocation_width, int allocation_height)
 {
-       double scale;
-       int available_width, available_height;
+       int target_width, target_height;
        int width, height;
+       GtkBorder border;
+
+       if (view->document == NULL)
+               return;
 
        width = height = 0;
        /* This is the bad part. You could make it stable by doing
         * ev_document_set_scale 1.0. But at least with pdf this means
         * redrawing the whole page */
        ev_document_get_page_size (view->document, -1, &width, &height);
+       /* FIXME: The border size isn't constant.  Ugh.  Still, if we have extra
+        * space, we just cut it from the border */
+       ev_document_misc_get_page_border_size (width, height, &border);
+
+       target_width = allocation_width - (view->spacing * 2 + border.left + border.right);
+       target_height = allocation_height - (view->spacing * 2 + border.top + border.bottom);
 
        LOG ("Best fit %d %d", allocation_width, allocation_height);
 
-       scale = 1.0;
        if (width != 0 && height != 0) {
+               double scale;
                double scale_w, scale_h;
 
-               available_width = MAX (1, allocation_width - 2); /* 1 px border left and right */
-               available_height = MAX (1, allocation_height - 2); /* 1 px border above and below */
-
-               scale_w = (double)available_width * view->scale / (width + 0.5);
-               scale_h = (double)available_height * view->scale / (height + 0.5);
+               scale_w = (double)target_width * view->scale / width;
+               scale_h = (double)target_height * view->scale / height;
 
                scale = (scale_w < scale_h) ? scale_w : scale_h;
+
+               ev_view_zoom (view, scale, FALSE);
        }
 
-       ev_view_zoom (view, scale, FALSE);
 }
 
 void
 ev_view_fit_width (EvView *view, int allocation_width, int allocation_height,
                   int vsb_width)
 {
-       int available_width, available_height;
+       int target_width, target_height;
        int width, height;
-       double scale = 1.0;
+       GtkBorder border;
+
+       if (view->document == NULL)
+               return;
 
        width = height = 0;
        ev_document_get_page_size (view->document, -1, &width, &height);
+       ev_document_misc_get_page_border_size (width, height, &border);
 
-       scale = 1.0;
-       if (width != 0) {
-               available_width = MAX (1, allocation_width - 2); /* 1px border */
-               available_height = MAX (1, allocation_height - 2); /* 1px border */
+       target_width = allocation_width - (view->spacing * 2 + border.left + border.right);
+       target_height = allocation_height - (view->spacing * 2 + border.top + border.bottom);
 
-               scale = (double)available_width * view->scale / (width + 0.5);
+       if (width) {
+               double scale;
+               scale = (double)target_width * view->scale / width;
 
-               if ((height + 0.5) * scale / view->scale > available_height)
-                       scale = ((double)(available_width - vsb_width) * view->scale /
-                                (width + 0.5));
-       }
+               if (height * scale / view->scale > target_height)
+                       scale = ((double)(target_width - vsb_width) * view->scale / width);
 
-       ev_view_zoom (view, scale, FALSE);
+               ev_view_zoom (view, scale, FALSE);
+       }
 }
 
 const char *
index f108f9f505fa51d7051500184b012e53c4f16319..5feb0f718f31b485c6f3fbe18e307ed31aea8ca2 100644 (file)
@@ -31,6 +31,13 @@ G_BEGIN_DECLS
 #define EV_VIEW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_VIEW, EvView))
 #define EV_IS_VIEW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_VIEW))
 
+
+typedef enum {
+       EV_SIZING_BEST_FIT,
+       EV_SIZING_FIT_WIDTH,
+       EV_SIZING_FREE,
+} EvSizingMode;
+
 typedef struct _EvView       EvView;
 typedef struct _EvViewClass  EvViewClass;
 
@@ -38,6 +45,8 @@ GType         ev_view_get_type        (void) G_GNUC_CONST;
 GtkWidget*     ev_view_new             (void);
 void           ev_view_set_document    (EvView     *view,
                                         EvDocument *document);
+void            ev_view_set_mode        (EvView       *view,
+                                        EvSizingMode  mode);
 
 /* Clipboard */
 void           ev_view_copy            (EvView     *view);
index 49b5a9911d90c5ae2c2b8dda8c2f93de45b6998f..27a6f60f21871f11215ad8d40d935410e889a4e4 100644 (file)
@@ -107,6 +107,7 @@ struct _EvWindowPrivate {
 
        EvChrome chrome;
        gboolean fullscreen_mode;
+       EvSizingMode sizing_mode;
 };
 
 static GtkTargetEntry ev_drop_types[] = {
@@ -129,7 +130,8 @@ static void     ev_window_set_page_mode           (EvWindow         *window,
 static gboolean start_loading_document            (EvWindow         *ev_window,
                                                   EvDocument       *document,
                                                   const char       *uri);
-
+static void     ev_window_set_sizing_mode         (EvWindow         *ev_window,
+                                                  EvSizingMode      sizing_mode);
 
 G_DEFINE_TYPE (EvWindow, ev_window, GTK_TYPE_WINDOW)
 
@@ -258,6 +260,33 @@ update_chrome_flag (EvWindow *window, EvChrome flag, const char *pref, gboolean
        update_chrome_visibility (window);
 }
 
+static void
+update_sizing_buttons (EvWindow *ev_window)
+{
+       GtkWidget *best_fit;
+       GtkWidget *fit_width;
+
+       best_fit = gtk_ui_manager_get_widget (ev_window->priv->ui_manager,
+                                             "/ToolBar/ViewBestFit");
+       fit_width = gtk_ui_manager_get_widget (ev_window->priv->ui_manager,
+                                             "/ToolBar/ViewPageWidth");
+
+       switch (ev_window->priv->sizing_mode) {
+       case EV_SIZING_BEST_FIT:
+               gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (best_fit), TRUE);
+               gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (fit_width), FALSE);
+               break;
+       case EV_SIZING_FIT_WIDTH:
+               gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (best_fit), FALSE);
+               gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (fit_width), TRUE);
+               break;
+       case EV_SIZING_FREE:
+               gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (best_fit), FALSE);
+               gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (fit_width), FALSE);
+               break;
+       }
+}
+
 void
 ev_window_open_page (EvWindow *ev_window, int page)
 {
@@ -408,7 +437,6 @@ 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;
@@ -422,7 +450,6 @@ 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 (document, NULL, ev_window);
        update_total_pages (ev_window);
@@ -1186,6 +1213,8 @@ ev_window_cmd_view_zoom_in (GtkAction *action, EvWindow *ev_window)
 {
         g_return_if_fail (EV_IS_WINDOW (ev_window));
 
+       ev_window_set_sizing_mode (ev_window, EV_SIZING_FREE);
+
        ev_view_zoom_in (EV_VIEW (ev_window->priv->view));
 }
 
@@ -1194,6 +1223,8 @@ ev_window_cmd_view_zoom_out (GtkAction *action, EvWindow *ev_window)
 {
         g_return_if_fail (EV_IS_WINDOW (ev_window));
 
+       ev_window_set_sizing_mode (ev_window, EV_SIZING_FREE);
+
        ev_view_zoom_out (EV_VIEW (ev_window->priv->view));
 }
 
@@ -1209,31 +1240,33 @@ static void
 ev_window_cmd_view_best_fit (GtkAction *action, EvWindow *ev_window)
 {
        EvWindowPrivate *priv = ev_window->priv;
-       int width, height;
+       GtkWidget *button;
 
         g_return_if_fail (EV_IS_WINDOW (ev_window));
 
-       width = priv->scrolled_window->allocation.width;
-       height = priv->scrolled_window->allocation.height;
-
-       /* the scrolled window has a GTK_SHADOW_IN */
-       width -= 2 * priv->view->style->xthickness;
-       height -= 2 * priv->view->style->ythickness;
+       button = gtk_ui_manager_get_widget (priv->ui_manager, "/ToolBar/ViewBestFit");
+       if (! gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (button)))
+               return;
 
-       ev_view_best_fit (EV_VIEW (priv->view),
-                         MAX (1, width), MAX (1, height));
+       ev_window_set_sizing_mode (ev_window, EV_SIZING_BEST_FIT);
 }
 
 static void
 ev_window_cmd_view_page_width (GtkAction *action, EvWindow *ev_window)
 {
        EvWindowPrivate *priv = ev_window->priv;
+       GtkWidget *button;
        int width, height;
        GtkRequisition vsb_requisition;
        int scrollbar_spacing;
 
         g_return_if_fail (EV_IS_WINDOW (ev_window));
 
+       button = gtk_ui_manager_get_widget (priv->ui_manager, "/ToolBar/ViewPageWidth");
+       if (! gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (button)))
+               return;
+
+
        width = priv->scrolled_window->allocation.width;
        height = priv->scrolled_window->allocation.height;
 
@@ -1248,6 +1281,8 @@ ev_window_cmd_view_page_width (GtkAction *action, EvWindow *ev_window)
                              "scrollbar_spacing", &scrollbar_spacing,
                              NULL);
 
+       ev_window_set_sizing_mode (ev_window, EV_SIZING_FIT_WIDTH);
+
        ev_view_fit_width (EV_VIEW (ev_window->priv->view),
                           width, height,
                           vsb_requisition.width + scrollbar_spacing);
@@ -1301,6 +1336,82 @@ ev_window_cmd_leave_fullscreen (GtkAction *action, EvWindow *window)
        gtk_window_unfullscreen (GTK_WINDOW (window));
 }
 
+static void
+size_allocate_cb (GtkWidget     *scrolled_window,
+                 GtkAllocation *allocation,
+                 EvWindow      *ev_window)
+{
+       int width, height;
+       GtkRequisition vsb_requisition;
+       int scrollbar_spacing;
+
+       width = ev_window->priv->scrolled_window->allocation.width;
+       height = ev_window->priv->scrolled_window->allocation.height;
+
+       /* the scrolled window has a GTK_SHADOW_IN */
+       width -= 2 * ev_window->priv->view->style->xthickness;
+       height -= 2 * ev_window->priv->view->style->ythickness;
+
+       if (ev_window->priv->sizing_mode == EV_SIZING_BEST_FIT) {
+               ev_view_best_fit (EV_VIEW (ev_window->priv->view),
+                                 MAX (1, width), MAX (1, height));
+       } else if (ev_window->priv->sizing_mode == EV_SIZING_FIT_WIDTH) {
+               gtk_widget_size_request (GTK_SCROLLED_WINDOW (ev_window->priv->scrolled_window)->vscrollbar,
+                                        &vsb_requisition);
+               gtk_widget_style_get (ev_window->priv->scrolled_window,
+                                     "scrollbar_spacing", &scrollbar_spacing,
+                                     NULL);
+               ev_view_fit_width (EV_VIEW (ev_window->priv->view),
+                                  width, height,
+                                  vsb_requisition.width + scrollbar_spacing);
+       }
+}
+
+static void
+ev_window_set_sizing_mode (EvWindow     *ev_window,
+                          EvSizingMode  sizing_mode)
+{
+       GtkWidget *scrolled_window;
+
+       if (ev_window->priv->sizing_mode == sizing_mode)
+               return;
+
+       scrolled_window = ev_window->priv->scrolled_window;
+       ev_window->priv->sizing_mode = sizing_mode;
+
+       g_signal_handlers_disconnect_by_func (scrolled_window, size_allocate_cb, ev_window);
+
+       switch (sizing_mode) {
+       case EV_SIZING_BEST_FIT:
+               g_object_set (G_OBJECT (scrolled_window),
+                             "hscrollbar-policy", GTK_POLICY_NEVER,
+                             "vscrollbar-policy", GTK_POLICY_NEVER,
+                             NULL);
+               g_signal_connect (scrolled_window, "size-allocate",
+                                 G_CALLBACK (size_allocate_cb),
+                                 ev_window);
+               break;
+       case EV_SIZING_FIT_WIDTH:
+               g_object_set (G_OBJECT (scrolled_window),
+                             "hscrollbar-policy", GTK_POLICY_NEVER,
+                             "vscrollbar-policy", GTK_POLICY_AUTOMATIC,
+                             NULL);
+               g_signal_connect (scrolled_window, "size-allocate",
+                                 G_CALLBACK (size_allocate_cb),
+                                 ev_window);
+               break;
+       case EV_SIZING_FREE:
+               g_object_set (G_OBJECT (scrolled_window),
+                             "hscrollbar-policy", GTK_POLICY_AUTOMATIC,
+                             "vscrollbar-policy", GTK_POLICY_AUTOMATIC,
+                             NULL);
+               break;
+       }
+
+       ev_view_set_mode (EV_VIEW (ev_window->priv->view), sizing_mode);
+       update_sizing_buttons (ev_window);
+}
+
 static void
 ev_window_cmd_help_about (GtkAction *action, EvWindow *ev_window)
 {
@@ -1665,12 +1776,6 @@ static GtkActionEntry entries[] = {
         { "ViewNormalSize", GTK_STOCK_ZOOM_100, NULL, "<control>0",
           N_("Reset the zoom level to the default value"),
           G_CALLBACK (ev_window_cmd_view_normal_size) },
-        { "ViewBestFit", EV_STOCK_ZOOM_PAGE, N_("_Best Fit"), NULL,
-          N_("Make the current document fill the window"),
-          G_CALLBACK (ev_window_cmd_view_best_fit) },
-        { "ViewPageWidth", EV_STOCK_ZOOM_WIDTH, N_("Fit Page _Width"), NULL,
-          N_("Make the current document fill the window width"),
-          G_CALLBACK (ev_window_cmd_view_page_width) },
 
         /* Go menu */
         { "GoPreviousPage", GTK_STOCK_GO_BACK, N_("_Previous Page"), "Page_Up",
@@ -1716,6 +1821,12 @@ static GtkToggleActionEntry toggle_entries[] = {
         { "ViewFullscreen", NULL, N_("_Fullscreen"), "F11",
           N_("Expand the window to fill the screen"),
           G_CALLBACK (ev_window_cmd_view_fullscreen) },
+        { "ViewBestFit", EV_STOCK_ZOOM_PAGE, N_("_Best Fit"), NULL,
+          N_("Make the current document fill the window"),
+          G_CALLBACK (ev_window_cmd_view_best_fit) },
+        { "ViewPageWidth", EV_STOCK_ZOOM_WIDTH, N_("Fit Page _Width"), NULL,
+          N_("Make the current document fill the window width"),
+          G_CALLBACK (ev_window_cmd_view_page_width) },
 };
 
 static GtkRadioActionEntry page_view_entries[] = {
@@ -1977,8 +2088,6 @@ ev_window_init (EvWindow *ev_window)
 
        ev_window->priv->scrolled_window =
                GTK_WIDGET (g_object_new (GTK_TYPE_SCROLLED_WINDOW,
-                                         "hscrollbar-policy", GTK_POLICY_AUTOMATIC,
-                                         "vscrollbar-policy", GTK_POLICY_AUTOMATIC,
                                          "shadow-type", GTK_SHADOW_IN,
                                          NULL));
        gtk_widget_show (ev_window->priv->scrolled_window);
@@ -2076,5 +2185,8 @@ ev_window_init (EvWindow *ev_window)
        g_signal_connect (G_OBJECT (ev_window), "drag_data_received",
                          G_CALLBACK (drag_data_received_cb), NULL);
 
+       /* Set it to something random to force a change */
+       ev_window->priv->sizing_mode = EV_SIZING_FREE;
+       ev_window_set_sizing_mode (ev_window, EV_SIZING_BEST_FIT);
        update_action_sensitivity (ev_window);
 }