sizing patch



Hi guys,

I redid the sizing.  Some comments:

 * I added 5 properties to ev-view.c, including 'continuous',
   'dual-page', 'presentation', 'fullscreen', and an enum,
   'sizing-mode'.  I moved these out of EvWindow, because it turned out
   hard to do sizing without knowing this information.

 * I added both 'presentation' and 'fullscreen' in the expectation that
   these are subtly different.  fullscreen can also be 'continuous',
   'dual-page', etc -- we just draw it a little bit different.
   'presentation', on the other hand, is single page only, and always
   fits the screen.  It will also have all the transitional effects.

 * I don't have the sizing quite right with continuous.  In particular,
   I always assume the vertical scrollbar exists.  It's actually often
   the right thing, as most continuous docs are taller than they're
   wider, but we should fix it.

 * I didn't hook up ev-window.c at all.  Instead, you'll need to copy in
   prop-editor.[ch] from gtk+/tests/ in order to test it.  We can hook
   it up, but I want to confirm w/ the design guys as to how we do so.
   There are (2*2*2*3 + 1) = 25 possible configurations of the page --
   potentially a pretty ugly interface.

 * The current_page variable is now really confusing.  What's the
   current page in dual mode?

 * Scrolling sometimes gets confused.  I'm investigating.

 * I (yet again) broke links and searching.  It should be much easier to
   fix this, but I haven't done so yet. 

Anyway, I'm not going to commit it until we do another release.  I don't
think this is going to be nearly as destabilizing as the thread changes
were, but there are a lot of small details that will need tuning to it.

Here's a screenshot to whet your appetite (sporting an already fixed
sizing bug):
http://www.gnome.org/~jrb/files/evince-dual.png

Thanks,
-Jonathan

? shell/continuous-scrolling-todo
? shell/prop-editor.c
? shell/prop-editor.h
Index: TODO
===================================================================
RCS file: /cvs/gnome/evince/TODO,v
retrieving revision 1.10
diff -u -p -r1.10 TODO
--- TODO	23 Mar 2005 11:07:30 -0000	1.10
+++ TODO	21 Apr 2005 04:07:01 -0000
@@ -29,6 +29,11 @@ Move to having three sizing types:
  * also, maybe add a 1-1 button.  Possibly dubious, though.
 
 
+Add some code to sanity check documents, including:
+
+ * n_pages > 0
+ * size of each page > (0,0)
+
 -------  TODONE -------  (move finished TODO items here)
 
 Create a TODO list
Index: backend/ev-page-cache.c
===================================================================
RCS file: /cvs/gnome/evince/backend/ev-page-cache.c,v
retrieving revision 1.12
diff -u -p -r1.12 ev-page-cache.c
--- backend/ev-page-cache.c	19 Apr 2005 16:40:31 -0000	1.12
+++ backend/ev-page-cache.c	21 Apr 2005 04:07:01 -0000
@@ -24,6 +24,11 @@ struct _EvPageCache
 	double uniform_width;
 	double uniform_height;
 
+	double max_width_page_width;
+	double max_width_page_height;
+	double max_height_page_width;
+	double max_height_page_height;
+
 	EvPageCacheInfo *size_cache;
 };
 
@@ -104,6 +109,10 @@ _ev_page_cache_new (EvDocument *document
 	page_cache->uniform = TRUE;
 	page_cache->n_pages = ev_document_get_n_pages (document);
 	page_cache->page_labels = g_new0 (char *, page_cache->n_pages);
+	page_cache->max_width_page_width = 0;
+	page_cache->max_width_page_height = 0;
+	page_cache->max_height_page_width = 0;
+	page_cache->max_height_page_height = 0;
 
 	doc_info = ev_document_get_info (document);
 	if (doc_info->fields_mask & EV_DOCUMENT_INFO_TITLE) {
@@ -120,6 +129,16 @@ _ev_page_cache_new (EvDocument *document
 		ev_document_get_page_size (document, i, &page_width, &page_height);
 		page_cache->page_labels[i] = ev_document_get_page_label (document, i);
 
+		if (page_width > page_cache->max_width_page_width) {
+			page_cache->max_width_page_width = page_width;
+			page_cache->max_width_page_height = page_height;
+		}
+
+		if (page_height > page_cache->max_height_page_height) {
+			page_cache->max_height_page_width = page_width;
+			page_cache->max_height_page_height = page_height;
+		}
+
 		if (i == 0) {
 			page_cache->uniform_width = page_width;
 			page_cache->uniform_height = page_height;
@@ -151,6 +170,8 @@ _ev_page_cache_new (EvDocument *document
 	/* make some sanity check assertions */
 	if (! page_cache->uniform)
 		g_assert (page_cache->size_cache != NULL);
+	if (page_cache->uniform)
+		g_assert (page_cache->uniform_width > 0 && page_cache->uniform_height > 0);
 
 	g_mutex_unlock (EV_DOC_MUTEX);
 
@@ -279,6 +300,39 @@ ev_page_cache_get_size (EvPageCache *pag
 		*height = (*height) * scale;
 
 }
+
+
+/* Note that these aren't necessarily from the same page.
+ */
+void
+ev_page_cache_get_max_width_size (EvPageCache *page_cache,
+				  gfloat       scale,
+				  gint        *width,
+				  gint        *height)
+{
+	g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
+
+	if (width)
+		*width = page_cache->max_width_page_width * scale;
+	if (height)
+		*height = page_cache->max_width_page_height * scale;
+}
+
+void
+ev_page_cache_get_max_height_size (EvPageCache *page_cache,
+				   gfloat       scale,
+				   gint        *width,
+				   gint        *height)
+{
+	g_return_if_fail (EV_IS_PAGE_CACHE (page_cache));
+
+	if (width)
+		*width = page_cache->max_height_page_width * scale;
+	if (height)
+		*height = page_cache->max_height_page_height * scale;
+}
+
+
 gchar *
 ev_page_cache_get_page_label (EvPageCache *page_cache,
 			      gint         page)
Index: backend/ev-page-cache.h
===================================================================
RCS file: /cvs/gnome/evince/backend/ev-page-cache.h,v
retrieving revision 1.4
diff -u -p -r1.4 ev-page-cache.h
--- backend/ev-page-cache.h	1 Apr 2005 07:03:05 -0000	1.4
+++ backend/ev-page-cache.h	21 Apr 2005 04:07:01 -0000
@@ -28,29 +28,39 @@ G_BEGIN_DECLS
 #define EV_PAGE_CACHE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_PAGE_CACHE, EvPageCache))
 #define EV_IS_PAGE_CACHE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_PAGE_CACHE))
 
-GType          ev_page_cache_get_type         (void) G_GNUC_CONST;
+GType          ev_page_cache_get_type            (void) G_GNUC_CONST;
+
 /* Used by ev-document.c only */
-EvPageCache   *_ev_page_cache_new             (EvDocument  *document);
+EvPageCache   *_ev_page_cache_new                (EvDocument  *document);
+gint           ev_page_cache_get_n_pages         (EvPageCache *page_cache);
+char          *ev_page_cache_get_title           (EvPageCache *page_cache);
+void           ev_page_cache_get_size            (EvPageCache *page_cache,
+						  gint         page,
+						  gfloat       scale,
+						  gint        *width,
+						  gint        *height);
+void           ev_page_cache_get_max_width_size  (EvPageCache *page_cache,
+						  gfloat       scale,
+						  gint        *width,
+						  gint        *height);
+void           ev_page_cache_get_max_height_size (EvPageCache *page_cache,
+						  gfloat       scale,
+						  gint        *width,
+						  gint        *height);
+char          *ev_page_cache_get_page_label      (EvPageCache *page_cache,
+						  gint         page);
 
-gint           ev_page_cache_get_n_pages      (EvPageCache *page_cache);
-char          *ev_page_cache_get_title        (EvPageCache *page_cache);
-void           ev_page_cache_get_size         (EvPageCache *page_cache,
-					       gint         page,
-					       gfloat       scale,
-					       gint        *width,
-					       gint        *height);
-char          *ev_page_cache_get_page_label  (EvPageCache  *page_cache,
-					      gint          page);
 /* Navigation */
-gint           ev_page_cache_get_current_page (EvPageCache *page_cache);
-void           ev_page_cache_set_current_page (EvPageCache *page_cache,
-					       int          page);
-gboolean       ev_page_cache_set_page_label   (EvPageCache *page_cache,
-					       const char  *page_label);
-void           ev_page_cache_set_link         (EvPageCache *page_cache,
-					       EvLink      *link);
-gboolean       ev_page_cache_next_page        (EvPageCache *page_cache);         
-gboolean       ev_page_cache_prev_page        (EvPageCache *page_cache);         
+gint           ev_page_cache_get_current_page    (EvPageCache *page_cache);
+void           ev_page_cache_set_current_page    (EvPageCache *page_cache,
+						  int          page);
+gboolean       ev_page_cache_set_page_label      (EvPageCache *page_cache,
+						  const char  *page_label);
+void           ev_page_cache_set_link            (EvPageCache *page_cache,
+						  EvLink      *link);
+gboolean       ev_page_cache_next_page           (EvPageCache *page_cache);
+gboolean       ev_page_cache_prev_page           (EvPageCache *page_cache);
+         
 
 G_END_DECLS
 
Index: shell/Makefile.am
===================================================================
RCS file: /cvs/gnome/evince/shell/Makefile.am,v
retrieving revision 1.31
diff -u -p -r1.31 Makefile.am
--- shell/Makefile.am	19 Apr 2005 08:57:50 -0000	1.31
+++ shell/Makefile.am	21 Apr 2005 04:07:01 -0000
@@ -81,6 +81,8 @@ evince_SOURCES=				\
 	ev-sidebar-thumbnails.h		\
 	ev-stock-icons.c		\
 	ev-stock-icons.h		\
+	prop-editor.c			\
+	prop-editor.h			\
 	main.c				\
 	$(NULL)
 
Index: shell/ev-view.c
===================================================================
RCS file: /cvs/gnome/evince/shell/ev-view.c,v
retrieving revision 1.80
diff -u -p -r1.80 ev-view.c
--- shell/ev-view.c	16 Apr 2005 22:54:22 -0000	1.80
+++ shell/ev-view.c	21 Apr 2005 04:07:02 -0000
@@ -36,6 +36,8 @@
 #include "ev-page-cache.h"
 #include "ev-pixbuf-cache.h"
 
+#include "prop-editor.h"
+
 #define EV_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_VIEW, EvViewClass))
 #define EV_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_VIEW))
 #define EV_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_VIEW, EvViewClass))
@@ -43,7 +45,12 @@
 enum {
 	PROP_0,
 	PROP_STATUS,
-	PROP_FIND_STATUS
+	PROP_FIND_STATUS,
+	PROP_CONTINUOUS,
+	PROP_DUAL_PAGE,
+	PROP_FULL_SCREEN,
+	PROP_PRESENTATION,
+	PROP_SIZING_MODE,
 };
 
 enum {
@@ -104,7 +111,10 @@ struct _EvView {
 	EvPageCache *page_cache;
 	EvPixbufCache *pixbuf_cache;
 
+	gint start_page;
+	gint end_page;
 	gint current_page;
+
 	EvJobRender *current_job;
 
 	int find_page;
@@ -112,10 +122,14 @@ struct _EvView {
 	int spacing;
 
 	double scale;
-	int width;
-	int height;
 	GtkBorder border;
 	gboolean show_border;
+
+	gboolean continuous;
+	gboolean dual_page;
+	gboolean full_screen;
+	gboolean presentation;
+	EvSizingMode sizing_mode;
 };
 
 struct _EvViewClass {
@@ -131,9 +145,14 @@ struct _EvViewClass {
 };
 
 
-static void ev_view_set_scroll_adjustments (EvView         *view,
-					    GtkAdjustment  *hadjustment,
-					    GtkAdjustment  *vadjustment);
+static void ev_view_set_scroll_adjustments     (EvView        *view,
+						GtkAdjustment *hadjustment,
+						GtkAdjustment *vadjustment);
+static void get_bounding_box_size              (EvView        *view,
+						int           *max_width,
+						int           *max_height);
+static void view_update_range_and_current_page (EvView        *view);
+
 
 G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_WIDGET)
 
@@ -160,6 +179,9 @@ view_update_adjustments (EvView *view)
 		gdk_window_move (view->bin_window, - view->scroll_x, - view->scroll_y);
 		gdk_window_process_updates (view->bin_window, TRUE);
 	}
+
+	if (view->document)
+		view_update_range_and_current_page (view);
 }
 
 static void
@@ -201,6 +223,71 @@ view_set_adjustment_values (EvView      
 		gtk_adjustment_value_changed (adjustment);
 }
 
+static void
+view_update_range_and_current_page (EvView *view)
+{
+
+	/* Presentation trumps all other modes */
+	if (view->presentation) {
+		view->start_page = view->current_page;
+		view->end_page = view->current_page;
+	} else if (view->continuous) {
+		GdkRectangle current_area, unused, page_area;
+		gboolean found = FALSE;
+		int i;
+
+		current_area.x = view->hadjustment->value;
+		current_area.width = view->hadjustment->page_size;
+		current_area.y = view->vadjustment->value;
+		current_area.height = view->vadjustment->page_size;
+
+		get_bounding_box_size (view, &(page_area.width), &(page_area.height));
+		page_area.x = view->spacing;
+		page_area.y = view->spacing;
+
+		for (i = 0; i < ev_page_cache_get_n_pages (view->page_cache); i++) {
+			if (gdk_rectangle_intersect (&current_area, &page_area, &unused)) {
+				if (! found) {
+					view->start_page = i;
+					found = TRUE;
+				}
+				view->end_page = i;
+			} else if (found) {
+				break;
+			}
+			if (view->dual_page) {
+				if (i % 2 == 0) {
+					page_area.x += page_area.width + view->spacing;
+				} else {
+					page_area.x = view->spacing;
+					page_area.y += page_area.height + view->spacing;
+				}
+			} else {
+				page_area.y += page_area.height + view->spacing;
+			}
+		}
+	} else {
+		if (view->dual_page) {
+			if (view->current_page % 2 == 0) {
+				view->start_page = view->current_page;
+				if (view->current_page + 1 < ev_page_cache_get_n_pages (view->page_cache))
+					view->end_page = view->start_page + 1;
+			} else {
+				view->start_page = view->current_page - 1;
+				view->end_page = view->current_page;
+			}
+		} else {
+			view->start_page = view->current_page;
+			view->end_page = view->current_page;
+		}
+	}
+
+	ev_pixbuf_cache_set_page_range (view->pixbuf_cache,
+					view->start_page,
+					view->end_page,
+					view->scale);
+}
+
 /*** Virtual function implementations ***/
 
 static void
@@ -296,98 +383,170 @@ compute_border (EvView *view, int width,
 }
 
 static void
-compute_zoom_factor (EvView *view)
+get_bounding_box_size (EvView *view, int *max_width, int *max_height)
 {
-	int doc_width, doc_height;
-	double scale, scale_w, scale_h;
 	GtkBorder border;
+	int width, height;
 
-	if (view->width <= 0 && view->height <= 0) {
-		return;
+	if (max_width) {
+		ev_page_cache_get_max_width_size (view->page_cache,
+						  view->scale,
+						  &width, &height);
+		compute_border (view, width, height, &border);
+		*max_width = width + border.left + border.right;
 	}
 
-	doc_width = doc_height = 0;
-	scale = scale_w = scale_h = 1.0;
-	ev_page_cache_get_size (view->page_cache,
-				view->current_page,
-				1.0,
-				&doc_width,
-				&doc_height);
 
-	compute_border (view, doc_width, doc_height, &border);
-
-	if (doc_width == 0 || doc_height == 0) {
-		return;
+	if (max_height) {
+		ev_page_cache_get_max_height_size (view->page_cache,
+						   view->scale,
+						   &width, &height);
+		compute_border (view, width, height, &border);
+		*max_height = height + border.top + border.bottom;
 	}
+}
 
-	if (view->width >= 0) {
-		int target_width;
 
-		target_width = view->width - (view->spacing * 2 + view->border.left +
-					      view->border.right);
-		scale = scale_w = (double)target_width / doc_width;
-	}
+static void
+ev_view_size_request_continuous_and_dual_page (EvView         *view,
+					       GtkRequisition *requisition)
+{
+	int max_width, max_height;
+	int n_rows;
 
-	if (view->height >= 0) {
-		int target_height;
+	get_bounding_box_size (view, &max_width, &max_height);
 
-		target_height = view->height - (view->spacing * 2 + view->border.top +
-						view->border.bottom);
-		scale = scale_h = (double)target_height / doc_height;
-	}
+	n_rows = (1 + ev_page_cache_get_n_pages (view->page_cache)) / 2;
+
+	requisition->width = (max_width * 2) + (view->spacing * 3);
+	requisition->height = max_height * n_rows + (view->spacing * (n_rows + 1));
 
-	if (view->width >= 0 && view->height >= 0) {
-		scale = (scale_w < scale_h) ? scale_w : scale_h;
+	if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
+		requisition->width = 1;
+	} else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
+		requisition->width = 1;
+		/* FIXME: This could actually be set on one page docs or docs
+		 * with a strange aspect ratio. */
+		/* requisition->height = 1;*/
 	}
+}
 
-	view->scale = scale;
+static void
+ev_view_size_request_continuous (EvView         *view,
+				 GtkRequisition *requisition)
+{
+	int max_width, max_height;
+	int n_pages;
+
+	get_bounding_box_size (view, &max_width, &max_height);
+
+	n_pages = ev_page_cache_get_n_pages (view->page_cache);
+
+	requisition->width = max_width + (view->spacing * 2);
+	requisition->height = max_height * n_pages + (view->spacing * (n_pages + 1));
+
+	if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
+		requisition->width = 1;
+	} else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
+		requisition->width = 1;
+		/* FIXME: This could actually be set on one page docs or docs
+		 * with a strange aspect ratio. */
+		/* requisition->height = 1;*/
+	}
 }
 
-/* Called by size_request to make sure we have appropriate jobs running.
- */
 static void
-ev_view_size_request (GtkWidget      *widget,
-		      GtkRequisition *requisition)
+ev_view_size_request_dual_page (EvView         *view,
+				GtkRequisition *requisition)
 {
-	EvView *view = EV_VIEW (widget);
+	GtkBorder border;
 	gint width, height;
 
-	if (!GTK_WIDGET_REALIZED (widget))
-		return;
+	/* Find the largest of the two. */
+	ev_page_cache_get_size (view->page_cache,
+				view->current_page,
+				view->scale,
+				&width, &height);
+	if (view->current_page + 1 < ev_page_cache_get_n_pages (view->page_cache)) {
+		gint width_2, height_2;
+		ev_page_cache_get_size (view->page_cache,
+					view->current_page + 1,
+					view->scale,
+					&width_2, &height_2);
+		if (width_2 > width) {
+			width = width_2;
+			height = height_2;
+		}
+	}
+	compute_border (view, width, height, &border);
 
-	if (!view->document) {
+	requisition->width = ((width + border.left + border.right) * 2) +
+		(view->spacing * 3);
+	requisition->height = (height + border.top + border.bottom) +
+		(view->spacing * 2);
+
+	if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
+		requisition->width = 1;
+	} else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
 		requisition->width = 1;
 		requisition->height = 1;
-		return;
 	}
+}
 
-	compute_zoom_factor (view);
+static void
+ev_view_size_request_single_page (EvView         *view,
+				  GtkRequisition *requisition)
+{
+	GtkBorder border;
+	gint width, height;
 
 	ev_page_cache_get_size (view->page_cache,
 				view->current_page,
 				view->scale,
 				&width, &height);
+	compute_border (view, width, height, &border);
 
-	compute_border (view, width, height, &(view->border));
+	requisition->width = width + border.left + border.right + (2 * view->spacing);
+	requisition->height = height + border.top + border.bottom + (2 * view->spacing);
 
-	ev_pixbuf_cache_set_page_range (view->pixbuf_cache,
-					view->current_page,
-					view->current_page,
-					view->scale);
+	if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
+		requisition->width = 1;
+		requisition->height = height + border.top + border.bottom + (2 * view->spacing);
+	} else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
+		requisition->width = 1;
+		requisition->height = 1;
+	}
+}
 
-	if (view->width >= 0) {
-		requisition->width = 0;
-	} else {
-		requisition->width = width + view->border.left +
-				     view->border.right + view->spacing * 2;
+static void
+ev_view_size_request (GtkWidget      *widget,
+		      GtkRequisition *requisition)
+{
+	EvView *view = EV_VIEW (widget);
+
+	if (!GTK_WIDGET_REALIZED (widget))
+		return;
+
+	if (view->document == NULL) {
+		requisition->width = 1;
+		requisition->height = 1;
+		return;
 	}
 
-	if (view->height >= 0) {
-		requisition->height = 0;
-	} else {
-		requisition->height = height + view->border.top +
-				      view->border.bottom + view->spacing * 2;
+	if (view->presentation) {
+		requisition->width = 1;
+		requisition->height = 1;
+		return;
 	}
+
+	if (view->continuous && view->dual_page)
+		ev_view_size_request_continuous_and_dual_page (view, requisition);
+	else if (view->continuous)
+		ev_view_size_request_continuous (view, requisition);
+	else if (view->dual_page)
+		ev_view_size_request_dual_page (view, requisition);
+	else
+		ev_view_size_request_single_page (view, requisition);
 }
 
 static void
@@ -406,6 +565,9 @@ ev_view_size_allocate (GtkWidget      *w
 				   MAX (widget->allocation.width, widget->requisition.width),
 				   MAX (widget->allocation.height, widget->requisition.height));
 	}
+
+	if (view->document)
+		view_update_range_and_current_page (view);
 }
 
 static void
@@ -482,6 +644,7 @@ ev_view_unrealize (GtkWidget *widget)
 	GTK_WIDGET_CLASS (ev_view_parent_class)->unrealize (widget);
 }
 
+#if 0
 static guint32
 ev_gdk_color_to_rgb (const GdkColor *color)
 {
@@ -528,6 +691,7 @@ draw_rubberband (GtkWidget *widget, GdkW
 	gdk_color_free (fill_color_gdk);
 }
 
+
 static void
 highlight_find_results (EvView *view)
 {
@@ -557,47 +721,159 @@ highlight_find_results (EvView *view)
 				 &view_rectangle, alpha);
         }
 }
+#endif
+
+
+static gboolean
+get_page_extents (EvView       *view,
+		  gint          page,
+		  GdkRectangle *page_area,
+		  GtkBorder    *border)
+{
+	GtkWidget *widget;
+	int width, height;
+
+	widget = GTK_WIDGET (view);
+
+	/* Quick sanity check */
+	if (view->presentation) {
+		if (view->current_page != page)
+			return FALSE;
+	} else if (view->continuous) {
+		if (page < view->start_page ||
+		    page > view->end_page)
+			return FALSE;
+	} else if (view->dual_page) {
+		if (ABS (page - view->current_page) > 1)
+			return FALSE;
+	} else {
+		if (view->current_page != page)
+			return FALSE;
+	}
+
+	/* Get the size of the page */
+	ev_page_cache_get_size (view->page_cache, page,
+				view->scale,
+				&width, &height);
+	compute_border (view, width, height, border);
+	page_area->width = width + border->left + border->right;
+	page_area->height = height + border->top + border->bottom;
+
+	if (view->presentation) {
+		page_area->x = (MAX (0, widget->allocation.width - width))/2;
+		page_area->y = (MAX (0, widget->allocation.height - height))/2;
+	} else if (view->continuous) {
+		gint max_width, max_height;
+		gint x, y;
+
+		get_bounding_box_size (view, &max_width, &max_height);
+		/* Get the location of the bounding box */
+		if (view->dual_page) {
+			x = view->spacing + (page % 2) * (max_width + view->spacing);
+			y = view->spacing + (page / 2) * (max_height + view->spacing);
+			x = x + MAX (0, widget->allocation.width - (max_width * 2 + view->spacing * 3))/2;
+		} else {
+			x = view->spacing;
+			y = view->spacing + page * (max_height + view->spacing);
+			x = x + MAX (0, widget->allocation.width - (max_width + view->spacing * 2))/2;
+		}
+		page_area->x = x;
+		page_area->y = y;
+	} else {
+		gint x, y;
+		if (view->dual_page) {
+			gint width_2, height_2;
+			gint max_width = width;
+			gint max_height = height;
+			GtkBorder overall_border;
+			gint other_page;
+
+			other_page = page ^ 1;
+
+			/* First, we get the bounding box of the two pages */
+			if (other_page < ev_page_cache_get_n_pages (view->page_cache)) {
+				ev_page_cache_get_size (view->page_cache,
+							page + 1,
+							view->scale,
+							&width_2, &height_2);
+				if (width_2 > width)
+					max_width = width_2;
+				if (height_2 > height)
+					max_height = height_2;
+			}
+			compute_border (view, max_width, max_height, &overall_border);
+
+			/* Find the offsets */
+			x = view->spacing;
+			y = view->spacing;
+
+			/* Adjust for being the left or right page */
+			if (page % 2 == 0)
+				x = x + max_width - width;
+			else
+				x = x + (max_width + overall_border.left + overall_border.right) + view->spacing;
+
+			y = y + (max_height - height)/2;
+
+			/* Adjust for extra allocation */
+			x = x + MAX (0, widget->allocation.width -
+				     ((max_width + overall_border.left + overall_border.right) * 2 + view->spacing * 3))/2;
+			y = y + MAX (0, widget->allocation.height - (height + view->spacing * 2))/2;
+		} else {
+			x = view->spacing;
+			y = view->spacing;
+
+			/* Adjust for extra allocation */
+			x = x + MAX (0, widget->allocation.width - (width + view->spacing * 2))/2;
+			y = y + MAX (0, widget->allocation.height - (height + view->spacing * 2))/2;
+		}
+
+		page_area->x = x;
+		page_area->y = y;
+	}
 
+	return TRUE;
+}
 
 static void
-expose_bin_window (GtkWidget      *widget,
-		   GdkEventExpose *event)
+draw_one_page (EvView       *view,
+	       gint          page,
+	       GdkRectangle *page_area,
+	       GtkBorder    *border,
+	       GdkRectangle *expose_area)
 {
-	EvView *view = EV_VIEW (widget);
 	gint width, height;
-	GdkRectangle area;
-	int x_offset, y_offset;
 	GdkPixbuf *scaled_image;
 	GdkPixbuf *current_pixbuf;
+	GdkRectangle overlap;
+	GdkRectangle real_page_area;
 
-	if (view->document == NULL)
+	g_assert (view->document);
+
+	if (! gdk_rectangle_intersect (page_area, expose_area, &overlap))
 		return;
 
-	ev_view_get_offsets (view, &x_offset, &y_offset);
 	ev_page_cache_get_size (view->page_cache,
-				view->current_page,
-				view->scale,
+				page, view->scale,
 				&width, &height);
 
-	/* Paint the frame */
-	area.x = x_offset;
-	area.y = y_offset;
-	area.width = width + view->border.left + view->border.right;
-	area.height = height + view->border.top + view->border.bottom;
-
-	if (view->show_border) {
-		ev_document_misc_paint_one_page (view->bin_window, widget, &area,
-						 &(view->border));
-	}
+	if (view->show_border)
+		ev_document_misc_paint_one_page (view->bin_window,
+						 GTK_WIDGET (view),
+						 page_area, border);
 
 	/* Render the document itself */
-	LOG ("Render area %d %d %d %d - Offset %d %d",
-	     event->area.x, event->area.y,
-             event->area.width, event->area.height,
-	     x_offset, y_offset);
+	real_page_area = *page_area;
 
-	current_pixbuf = ev_pixbuf_cache_get_pixbuf (view->pixbuf_cache, view->current_page);
+	real_page_area.x += border->left;
+	real_page_area.y += border->top;
+	real_page_area.width -= (border->left + border->right);
+	real_page_area.height -= (border->top + border->bottom);
+
+	if (! gdk_rectangle_intersect (&real_page_area, expose_area, &overlap))
+		return;
 
+	current_pixbuf = ev_pixbuf_cache_get_pixbuf (view->pixbuf_cache, page);
 	if (current_pixbuf == NULL)
 		scaled_image = NULL;
 	else if (width == gdk_pixbuf_get_width (current_pixbuf) &&
@@ -607,19 +883,40 @@ expose_bin_window (GtkWidget      *widge
 		scaled_image = gdk_pixbuf_scale_simple (current_pixbuf,
 							width, height,
 							GDK_INTERP_NEAREST);
+
 	if (scaled_image) {
 		gdk_draw_pixbuf (view->bin_window,
 				 GTK_WIDGET (view)->style->fg_gc[GTK_STATE_NORMAL],
 				 scaled_image,
-				 0, 0,
-				 area.x + view->border.left,
-				 area.y + view->border.top,
-				 width, height,
+				 overlap.x - real_page_area.x,
+				 overlap.y - real_page_area.y,
+				 overlap.x, overlap.y,
+				 overlap.width, overlap.height,
 				 GDK_RGB_DITHER_NORMAL,
 				 0, 0);
 		g_object_unref (scaled_image);
 	}
+}
+
+static void
+ev_view_bin_expose (EvView         *view,
+		    GdkEventExpose *event)
+{
+	int i;
 
+	if (view->document == NULL)
+		return;
+
+	for (i = view->start_page; i <= view->end_page; i++) {
+		GdkRectangle page_area;
+		GtkBorder border;
+
+		if (! get_page_extents (view, i, &page_area, &border))
+			continue;
+		draw_one_page (view, i, &page_area, &border, &(event->area));
+	}
+
+#if 0
 	if (EV_IS_DOCUMENT_FIND (view->document)) {
 		highlight_find_results (view);
 	}
@@ -629,10 +926,11 @@ expose_bin_window (GtkWidget      *widge
 
 		doc_rect_to_view_rect (view, &view->selection, &rubberband);
 		if (rubberband.width > 0 && rubberband.height > 0) {
-			draw_rubberband (widget, view->bin_window,
+			draw_rubberband (GTK_WIDGET (view), view->bin_window,
 					 &rubberband, 0x40);
 		}
 	}
+#endif
 }
 
 static gboolean
@@ -642,7 +940,7 @@ ev_view_expose_event (GtkWidget      *wi
 	EvView *view = EV_VIEW (widget);
 
 	if (event->window == view->bin_window)
-		expose_bin_window (widget, event);
+		ev_view_bin_expose (view, event);
 	else
 		return GTK_WIDGET_CLASS (ev_view_parent_class)->expose_event (widget, event);
 
@@ -1202,17 +1500,32 @@ ev_view_scroll_view (EvView *view,
 }
 
 static void
-ev_view_set_property (GObject *object,
-		      guint prop_id,
+ev_view_set_property (GObject      *object,
+		      guint         prop_id,
 		      const GValue *value,
-		      GParamSpec *pspec)
+		      GParamSpec   *pspec)
 {
+	EvView *view = EV_VIEW (object);
+
 	switch (prop_id)
 	{
-		/* Read only */
-		case PROP_STATUS:
-		case PROP_FIND_STATUS:
-			break;
+	case PROP_CONTINUOUS:
+		ev_view_set_continuous (view, g_value_get_boolean (value));
+		break;
+	case PROP_DUAL_PAGE:
+		ev_view_set_dual_page (view, g_value_get_boolean (value));
+		break;
+	case PROP_FULL_SCREEN:
+		ev_view_set_full_screen (view, g_value_get_boolean (value));
+		break;
+	case PROP_PRESENTATION:
+		ev_view_set_presentation (view, g_value_get_boolean (value));
+		break;
+	case PROP_SIZING_MODE:
+		ev_view_set_sizing_mode (view, g_value_get_enum (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 	}
 }
 
@@ -1226,12 +1539,29 @@ ev_view_get_property (GObject *object,
 
 	switch (prop_id)
 	{
-		case PROP_STATUS:
-			g_value_set_string (value, view->status);
-			break;
-		case PROP_FIND_STATUS:
-			g_value_set_string (value, view->status);
-			break;
+	case PROP_STATUS:
+		g_value_set_string (value, view->status);
+		break;
+	case PROP_FIND_STATUS:
+		g_value_set_string (value, view->status);
+		break;
+	case PROP_CONTINUOUS:
+		g_value_set_boolean (value, view->continuous);
+		break;
+	case PROP_DUAL_PAGE:
+		g_value_set_boolean (value, view->dual_page);
+		break;
+	case PROP_FULL_SCREEN:
+		g_value_set_boolean (value, view->full_screen);
+		break;
+	case PROP_PRESENTATION:
+		g_value_set_boolean (value, view->presentation);
+		break;
+	case PROP_SIZING_MODE:
+		g_value_set_enum (value, view->sizing_mode);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 	}
 }
 
@@ -1296,6 +1626,45 @@ ev_view_class_init (EvViewClass *class)
 							      NULL,
 							      G_PARAM_READABLE));
 
+	g_object_class_install_property (object_class,
+					 PROP_CONTINUOUS,
+					 g_param_spec_boolean ("continuous",
+							       "Continuous",
+							       "Continuous scrolling mode",
+							       TRUE,
+							       G_PARAM_READWRITE));
+
+	g_object_class_install_property (object_class,
+					 PROP_DUAL_PAGE,
+					 g_param_spec_boolean ("dual-page",
+							       "Dual Page",
+							       "Two pages visible at once",
+							       FALSE,
+							       G_PARAM_READWRITE));
+	g_object_class_install_property (object_class,
+					 PROP_FULL_SCREEN,
+					 g_param_spec_boolean ("full-screen",
+							       "Full Screen",
+							       "Draw page in a full-screen fashion",
+							       FALSE,
+							       G_PARAM_READWRITE));
+	g_object_class_install_property (object_class,
+					 PROP_PRESENTATION,
+					 g_param_spec_boolean ("presentation",
+							       "Presentation",
+							       "Draw page in presentation mode",
+							       TRUE,
+							       G_PARAM_READWRITE));
+
+	g_object_class_install_property (object_class,
+					 PROP_SIZING_MODE,
+					 g_param_spec_enum ("sizing-mode",
+							    "Sizing Mode",
+							    "Sizing Mode",
+							    EV_TYPE_SIZING_MODE,
+							    EV_SIZING_FIT_WIDTH,
+							    G_PARAM_READWRITE));
+
 	binding_set = gtk_binding_set_by_class (class);
 
 	add_scroll_binding_keypad (binding_set, GDK_Left,  GTK_SCROLL_STEP_BACKWARD, TRUE);
@@ -1334,6 +1703,12 @@ ev_view_init (EvView *view)
 	view->pressed_button = -1;
 	view->cursor = EV_VIEW_CURSOR_NORMAL;
 	view->show_border = TRUE;
+
+	view->continuous = TRUE;
+	view->dual_page = FALSE;
+	view->presentation = FALSE;
+	view->full_screen = FALSE;
+	view->sizing_mode = EV_SIZING_FIT_WIDTH;
 }
 
 static void
@@ -1480,7 +1855,15 @@ find_changed_cb (EvDocument *document, i
 GtkWidget*
 ev_view_new (void)
 {
-	return g_object_new (EV_TYPE_VIEW, NULL);
+	GtkWidget *view;
+	GtkWidget *prop;
+
+	view = g_object_new (EV_TYPE_VIEW, NULL);
+
+	prop = create_prop_editor (G_OBJECT (view), EV_TYPE_VIEW);
+	gtk_widget_show (prop);
+
+	return view;
 }
 
 static void
@@ -1511,8 +1894,6 @@ page_changed_cb (EvPageCache *page_cache
 	view->current_page = new_page;
 	view->has_selection = FALSE;
 
-	compute_zoom_factor (view);
-
 	ev_page_cache_get_size (page_cache,
 				new_page,
 				view->scale,
@@ -1538,6 +1919,8 @@ page_changed_cb (EvPageCache *page_cache
 		view->find_result = 0;
 		update_find_status_message (view);
 	}
+
+	view_update_range_and_current_page (view);
 }
 
 void
@@ -1578,6 +1961,7 @@ ev_view_set_document (EvView     *view,
 	}
 }
 
+#define EPSILON 0.0000001
 static void
 ev_view_zoom (EvView   *view,
 	      double    factor,
@@ -1592,37 +1976,324 @@ ev_view_zoom (EvView   *view,
 
 	scale = CLAMP (scale, MIN_SCALE, MAX_SCALE);
 
+	if (ABS (view->scale - scale) < EPSILON)
+		return;
 	view->scale = scale;
-	view->width = view->height = -1;
 	gtk_widget_queue_resize (GTK_WIDGET (view));
 }
 
+
+void
+ev_view_set_continuous (EvView   *view,
+			gboolean  continuous)
+{
+	g_return_if_fail (EV_IS_VIEW (view));
+
+	continuous = continuous != FALSE;
+
+	if (view->continuous != continuous) {
+		view->continuous = continuous;
+		gtk_widget_queue_resize (GTK_WIDGET (view));
+	}
+
+	g_object_notify (G_OBJECT (view), "continuous");
+}
+
+void
+ev_view_set_dual_page (EvView   *view,
+		       gboolean  dual_page)
+{
+	g_return_if_fail (EV_IS_VIEW (view));
+
+	dual_page = dual_page != FALSE;
+
+	if (view->dual_page == dual_page)
+		return;
+
+	view->dual_page = dual_page;
+	/* FIXME: if we're keeping the pixbuf cache around, we should extend the
+	 * preload_cache_size to be 2 if dual_page is set.
+	 */
+	gtk_widget_queue_resize (GTK_WIDGET (view));
+
+	g_object_notify (G_OBJECT (view), "dual-page");
+}
+
+void
+ev_view_set_full_screen (EvView   *view,
+			 gboolean  full_screen)
+{
+	g_return_if_fail (EV_IS_VIEW (view));
+
+	full_screen = full_screen != FALSE;
+
+	if (view->full_screen != full_screen) {
+		view->full_screen = full_screen;
+		gtk_widget_queue_resize (GTK_WIDGET (view));
+	}
+
+	g_object_notify (G_OBJECT (view), "full-screen");
+}
+
+void
+ev_view_set_presentation (EvView   *view,
+			  gboolean  presentation)
+{
+	g_return_if_fail (EV_IS_VIEW (view));
+
+	presentation = presentation != FALSE;
+
+	if (view->presentation != presentation) {
+		view->presentation = presentation;
+		gtk_widget_queue_resize (GTK_WIDGET (view));
+	}
+
+	g_object_notify (G_OBJECT (view), "presentation");
+}
+
+void
+ev_view_set_sizing_mode (EvView       *view,
+			 EvSizingMode  sizing_mode)
+{
+	g_return_if_fail (EV_IS_VIEW (view));
+
+	if (view->sizing_mode != sizing_mode) {
+		view->sizing_mode = sizing_mode;
+		gtk_widget_queue_resize (GTK_WIDGET (view));
+	}
+
+	g_object_notify (G_OBJECT (view), "sizing-mode");
+}
+
+
 void
 ev_view_zoom_in (EvView *view)
 {
+	g_return_if_fail (view->sizing_mode == EV_SIZING_FREE);
+
 	ev_view_zoom (view, ZOOM_IN_FACTOR, TRUE);
 }
 
 void
 ev_view_zoom_out (EvView *view)
 {
+	g_return_if_fail (view->sizing_mode == EV_SIZING_FREE);
+
 	ev_view_zoom (view, ZOOM_OUT_FACTOR, TRUE);
 }
 
-void
-ev_view_set_size (EvView     *view,
-		  int         width,
-		  int         height)
+
+
+static double
+zoom_for_size_fit_width (int doc_width,
+			 int doc_height,
+			 int target_width,
+			 int target_height,
+			 int vsb_width)
 {
-	if (!view->document) {
-		return;
-	}
+	double scale;
 
-	if (width != view->width || height != view->height) {
-		view->width = width;
-		view->height = height;
-		gtk_widget_queue_resize (GTK_WIDGET (view));
+	scale = (double)target_width / doc_width;
+
+	if (doc_height * scale > target_height)
+		scale = (double) (target_width - vsb_width) / doc_width;
+
+	return scale;
+}
+
+static double
+zoom_for_size_best_fit (int doc_width,
+			int doc_height,
+			int target_width,
+			int target_height,
+			int vsb_width,
+			int hsb_width)
+{
+	double w_scale;
+	double h_scale;
+
+	w_scale = (double)target_width / doc_width;
+	h_scale = (double)target_height / doc_height;
+
+	if (doc_height * w_scale > target_height)
+		w_scale = (double) (target_width - vsb_width) / doc_width;
+	if (doc_width * h_scale > target_width)
+		h_scale = (double) (target_height - hsb_width) / doc_height;
+
+	return MIN (w_scale, h_scale);
+}
+
+static void
+ev_view_zoom_for_size_continuous_and_dual_page (EvView *view,
+			   int     width,
+			   int     height,
+			   int     vsb_width,
+			   int     hsb_height)
+{
+	int doc_width, doc_height;
+	GtkBorder border;
+	gdouble scale;
+
+	ev_page_cache_get_max_width_size (view->page_cache,
+					  1.0,
+					  &doc_width, NULL);
+	ev_page_cache_get_max_height_size (view->page_cache,
+					   1.0,
+					   NULL, &doc_height);
+	compute_border (view, doc_width, doc_height, &border);
+
+	doc_width = doc_width * 2;
+	width -= ((border.left + border.right)* 2 + 3 * view->spacing);
+	height -= (border.top + border.bottom + 2 * view->spacing);
+
+	/* FIXME: We really need to calculat the overall height here, not the
+	 * page height.  We assume there's always a vertical scrollbar for
+	 * now.  We need to fix this. */
+	if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
+		scale = zoom_for_size_fit_width (doc_width, doc_height, width - vsb_width, height, 0);
+	else if (view->sizing_mode == EV_SIZING_BEST_FIT)
+		scale = zoom_for_size_best_fit (doc_width, doc_height, width - vsb_width, height, 0, hsb_height);
+	else
+		g_assert_not_reached ();
+
+	ev_view_zoom (view, scale, FALSE);
+}
+
+static void
+ev_view_zoom_for_size_continuous (EvView *view,
+				  int     width,
+				  int     height,
+				  int     vsb_width,
+				  int     hsb_height)
+{
+	int doc_width, doc_height;
+	GtkBorder border;
+	gdouble scale;
+
+	ev_page_cache_get_max_width_size (view->page_cache,
+					  1.0,
+					  &doc_width, NULL);
+	ev_page_cache_get_max_height_size (view->page_cache,
+					   1.0,
+					   NULL, &doc_height);
+	compute_border (view, doc_width, doc_height, &border);
+
+	width -= (border.left + border.right + 2 * view->spacing);
+	height -= (border.top + border.bottom + 2 * view->spacing);
+
+	if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
+		scale = zoom_for_size_fit_width (doc_width, doc_height, width, height, vsb_width);
+	else if (view->sizing_mode == EV_SIZING_BEST_FIT)
+		scale = zoom_for_size_best_fit (doc_width, doc_height, width, height, vsb_width, hsb_height);
+	else
+		g_assert_not_reached ();
+
+	ev_view_zoom (view, scale, FALSE);
+}
+
+static void
+ev_view_zoom_for_size_dual_page (EvView *view,
+				 int     width,
+				 int     height,
+				 int     vsb_width,
+				 int     hsb_height)
+{
+	GtkBorder border;
+	gint doc_width, doc_height;
+	gdouble scale;
+	gint other_page;
+
+	other_page = view->current_page ^ 1;
+
+	/* Find the largest of the two. */
+	ev_page_cache_get_size (view->page_cache,
+				view->current_page,
+				1.0,
+				&doc_width, &doc_height);
+
+	if (other_page < ev_page_cache_get_n_pages (view->page_cache)) {
+		gint width_2, height_2;
+		ev_page_cache_get_size (view->page_cache,
+					other_page,
+					1.0,
+					&width_2, &height_2);
+		if (width_2 > doc_width)
+			doc_width = width_2;
+		if (height_2 > doc_height)
+			doc_height = height_2;
 	}
+	compute_border (view, doc_width, doc_height, &border);
+
+	doc_width = doc_width * 2;
+	width -= ((border.left + border.right)* 2 + 3 * view->spacing);
+	height -= (border.top + border.bottom + 2 * view->spacing);
+
+	if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
+		scale = zoom_for_size_fit_width (doc_width, doc_height, width, height, vsb_width);
+	else if (view->sizing_mode == EV_SIZING_BEST_FIT)
+		scale = zoom_for_size_best_fit (doc_width, doc_height, width, height, vsb_width, hsb_height);
+	else
+		g_assert_not_reached ();
+
+	ev_view_zoom (view, scale, FALSE);
+}
+
+static void
+ev_view_zoom_for_size_single_page (EvView *view,
+				   int     width,
+				   int     height,
+				   int     vsb_width,
+				   int     hsb_height)
+{
+	int doc_width, doc_height;
+	GtkBorder border;
+	gdouble scale;
+
+	ev_page_cache_get_size (view->page_cache,
+				view->current_page,
+				1.0,
+				&doc_width,
+				&doc_height);
+	/* Get an approximate border */
+	compute_border (view, width, height, &border);
+
+	width -= (border.left + border.right + 2 * view->spacing);
+	height -= (border.top + border.bottom + 2 * view->spacing);
+
+	if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
+		scale = zoom_for_size_fit_width (doc_width, doc_height, width, height, vsb_width);
+	else if (view->sizing_mode == EV_SIZING_BEST_FIT)
+		scale = zoom_for_size_best_fit (doc_width, doc_height, width, height, vsb_width, hsb_height);
+	else
+		g_assert_not_reached ();
+
+	ev_view_zoom (view, scale, FALSE);
+}
+
+
+void
+ev_view_set_zoom_for_size (EvView *view,
+			   int     width,
+			   int     height,
+			   int     vsb_width,
+			   int     hsb_height)
+{
+	g_return_if_fail (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
+			  view->sizing_mode == EV_SIZING_BEST_FIT);
+	g_return_if_fail (width >= 0);
+	g_return_if_fail (height >= 0);
+
+	if (view->document == NULL)
+		return;
+
+	if (view->continuous && view->dual_page)
+		ev_view_zoom_for_size_continuous_and_dual_page (view, width, height, vsb_width, hsb_height);
+	else if (view->continuous)
+		ev_view_zoom_for_size_continuous (view, width, height, vsb_width, hsb_height);
+	else if (view->dual_page)
+		ev_view_zoom_for_size_dual_page (view, width, height, vsb_width, hsb_height);
+	else
+		ev_view_zoom_for_size_single_page (view, width, height, vsb_width, hsb_height);
 }
 
 const char *
@@ -1729,4 +2400,21 @@ void
 ev_view_show_cursor (EvView *view)
 {
        ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
+}
+
+
+GType
+ev_sizing_mode_get_type (void)
+{
+  static GType etype = 0;
+  if (etype == 0) {
+    static const GEnumValue values[] = {
+      { EV_SIZING_FIT_WIDTH, "EV_SIZING_FIT_WIDTH", "fit-width" },
+      { EV_SIZING_BEST_FIT, "EV_SIZING_BEST_FIT", "best-fit" },
+      { EV_SIZING_FREE, "EV_SIZING_FREE", "free" },
+      { 0, NULL, NULL }
+    };
+    etype = g_enum_register_static ("EvSizingMode", values);
+  }
+  return etype;
 }
Index: shell/ev-view.h
===================================================================
RCS file: /cvs/gnome/evince/shell/ev-view.h,v
retrieving revision 1.23
diff -u -p -r1.23 ev-view.h
--- shell/ev-view.h	16 Apr 2005 22:54:22 -0000	1.23
+++ shell/ev-view.h	21 Apr 2005 04:07:02 -0000
@@ -28,13 +28,22 @@
 G_BEGIN_DECLS
 
 #define EV_TYPE_VIEW            (ev_view_get_type ())
+#define EV_TYPE_SIZING_MODE     (ev_sizing_mode_get_type())
 #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 struct _EvView       EvView;
 typedef struct _EvViewClass  EvViewClass;
 
+
+typedef enum {
+	EV_SIZING_BEST_FIT,
+	EV_SIZING_FIT_WIDTH,
+	EV_SIZING_FREE,
+} EvSizingMode;
+
 GType		ev_view_get_type	(void) G_GNUC_CONST;
+GType           ev_sizing_mode_get_type (void) G_GNUC_CONST;
 GtkWidget*	ev_view_new		(void);
 void		ev_view_set_document	(EvView     *view,
 			   		 EvDocument *document);
@@ -43,12 +52,29 @@ void		ev_view_set_document	(EvView     *
 void		ev_view_copy		(EvView     *view);
 void		ev_view_select_all	(EvView     *view);
 
-/* Page size */
+
+/* sizing and behavior */
+/* These are all orthoganal to each other, with the exception of 'presentation'
+ */
+void ev_view_set_continuous   (EvView       *view,
+			       gboolean      continuous);
+void ev_view_set_dual_page    (EvView       *view,
+			       gboolean      dual_page);
+void ev_view_set_full_screen  (EvView       *view,
+			       gboolean      full_screen);
+void ev_view_set_presentation (EvView       *view,
+			       gboolean      presentation);
+void ev_view_set_sizing_mode  (EvView       *view,
+			       EvSizingMode  mode);
+
+
 void		ev_view_zoom_in		(EvView     *view);
 void		ev_view_zoom_out	(EvView     *view);
-void		ev_view_set_size        (EvView     *view,
-					 int         width,
-					 int         height);
+void		ev_view_set_zoom_for_size (EvView     *view,
+					   int         width,
+					   int         height,
+					   int         vsb_width,
+					   int         hsb_height);
 void		ev_view_set_spacing	(EvView     *view,
 					 int         spacing);
 void		ev_view_set_show_border (EvView     *view,
Index: shell/ev-window.c
===================================================================
RCS file: /cvs/gnome/evince/shell/ev-window.c,v
retrieving revision 1.110
diff -u -p -r1.110 ev-window.c
--- shell/ev-window.c	19 Apr 2005 17:14:20 -0000	1.110
+++ shell/ev-window.c	21 Apr 2005 04:07:02 -0000
@@ -65,12 +65,6 @@
 #include "ev-stock-icons.h"
 
 typedef enum {
-	EV_SIZING_BEST_FIT,
-	EV_SIZING_FIT_WIDTH,
-	EV_SIZING_FREE,
-} EvSizingMode;
-
-typedef enum {
 	PAGE_MODE_SINGLE_PAGE,
 	PAGE_MODE_CONTINUOUS_PAGE,
 	PAGE_MODE_PASSWORD,
@@ -117,7 +111,6 @@ struct _EvWindowPrivate {
 
 	EvChrome chrome;
 	gboolean fullscreen_mode;
-	EvSizingMode sizing_mode;
 	GSource *fullscreen_timeout_source;
 
 	/* recent file stuff */
@@ -153,7 +146,8 @@ static gboolean start_loading_document  
 						   EvDocument       *document,
 						   const char       *uri);
 static void     ev_window_set_sizing_mode         (EvWindow         *ev_window,
-						   EvSizingMode      sizing_mode);
+						   EvSizingMode      sizing_mode,
+						   gboolean          first_time);
 
 static void 	ev_window_add_recent (EvWindow *window, const char *filename);
 static void	ev_window_fullscreen (EvWindow *window);
@@ -302,9 +296,9 @@ static void
 ev_window_cmd_view_best_fit (GtkAction *action, EvWindow *ev_window)
 {
 	if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
-		ev_window_set_sizing_mode (ev_window, EV_SIZING_BEST_FIT);
+		ev_window_set_sizing_mode (ev_window, EV_SIZING_BEST_FIT, FALSE);
 	} else {
-		ev_window_set_sizing_mode (ev_window, EV_SIZING_FREE);
+		ev_window_set_sizing_mode (ev_window, EV_SIZING_FREE, FALSE);
 	}
 }
 
@@ -312,9 +306,9 @@ static void
 ev_window_cmd_view_page_width (GtkAction *action, EvWindow *ev_window)
 {
 	if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
-		ev_window_set_sizing_mode (ev_window, EV_SIZING_FIT_WIDTH);
+		ev_window_set_sizing_mode (ev_window, EV_SIZING_FIT_WIDTH, FALSE);
 	} else {
-		ev_window_set_sizing_mode (ev_window, EV_SIZING_FREE);
+		ev_window_set_sizing_mode (ev_window, EV_SIZING_FREE, FALSE);
 	}
 }
 
@@ -324,8 +318,16 @@ update_sizing_buttons (EvWindow *window)
 	GtkActionGroup *action_group = window->priv->action_group;
 	GtkAction *action;
 	gboolean best_fit, page_width;
+	EvSizingMode sizing_mode;
+
+	if (window->priv->view == NULL)
+		return;
+
+	g_object_get (window->priv->view,
+		      "sizing_mode", &sizing_mode,
+		      NULL);
 
-	switch (window->priv->sizing_mode) {
+	switch (sizing_mode) {
 	case EV_SIZING_BEST_FIT:
 		best_fit = TRUE;
 		page_width = FALSE;
@@ -1479,7 +1481,7 @@ ev_window_cmd_view_zoom_in (GtkAction *a
 {
         g_return_if_fail (EV_IS_WINDOW (ev_window));
 
-	ev_window_set_sizing_mode (ev_window, EV_SIZING_FREE);
+	ev_window_set_sizing_mode (ev_window, EV_SIZING_FREE, FALSE);
 
 	ev_view_zoom_in (EV_VIEW (ev_window->priv->view));
 }
@@ -1489,7 +1491,7 @@ ev_window_cmd_view_zoom_out (GtkAction *
 {
         g_return_if_fail (EV_IS_WINDOW (ev_window));
 
-	ev_window_set_sizing_mode (ev_window, EV_SIZING_FREE);
+	ev_window_set_sizing_mode (ev_window, EV_SIZING_FREE, FALSE);
 
 	ev_view_zoom_out (EV_VIEW (ev_window->priv->view));
 }
@@ -1499,7 +1501,8 @@ ev_window_cmd_view_normal_size (GtkActio
 {
         g_return_if_fail (EV_IS_WINDOW (ev_window));
 
-	ev_view_set_size (EV_VIEW (ev_window->priv->view), -1, -1);
+	// FIXME: write.
+	//ev_view_set_size (EV_VIEW (ev_window->priv->view), -1, -1);
 }
 
 static void
@@ -1593,30 +1596,31 @@ update_view_size (EvWindow *window)
 {
 	int width, height;
 	GtkRequisition vsb_requisition;
+	GtkRequisition hsb_requisition;
 	int scrollbar_spacing;
 
+	/* Calculate the width available for the */
 	width = window->priv->scrolled_window->allocation.width;
 	height = window->priv->scrolled_window->allocation.height;
 
-	if (gtk_scrolled_window_get_shadow_type
-		(GTK_SCROLLED_WINDOW (window->priv->scrolled_window)) == GTK_SHADOW_IN)
-	{
+	if (gtk_scrolled_window_get_shadow_type (GTK_SCROLLED_WINDOW (window->priv->scrolled_window)) == GTK_SHADOW_IN) {
 		width -= 2 * window->priv->view->style->xthickness;
 		height -= 2 * window->priv->view->style->ythickness;
 	}
 
-	if (window->priv->sizing_mode == EV_SIZING_BEST_FIT) {
-		ev_view_set_size (EV_VIEW (window->priv->view),
-				  MAX (1, width), MAX (1, height));
-	} else if (window->priv->sizing_mode == EV_SIZING_FIT_WIDTH) {
-		gtk_widget_size_request (GTK_SCROLLED_WINDOW (window->priv->scrolled_window)->vscrollbar,
-					 &vsb_requisition);
-		gtk_widget_style_get (window->priv->scrolled_window,
-				      "scrollbar_spacing", &scrollbar_spacing,
-				      NULL);
-		ev_view_set_size (EV_VIEW (window->priv->view),
-				  width - vsb_requisition.width - scrollbar_spacing, -1);
-	}
+	gtk_widget_size_request (GTK_SCROLLED_WINDOW (window->priv->scrolled_window)->vscrollbar,
+				 &vsb_requisition);
+	gtk_widget_size_request (GTK_SCROLLED_WINDOW (window->priv->scrolled_window)->hscrollbar,
+				 &hsb_requisition);
+	gtk_widget_style_get (window->priv->scrolled_window,
+			      "scrollbar_spacing", &scrollbar_spacing,
+			      NULL);
+
+	ev_view_set_zoom_for_size (EV_VIEW (window->priv->view),
+				   MAX (1, width),
+				   MAX (1, height),
+				   vsb_requisition.width + scrollbar_spacing,
+				   hsb_requisition.height + scrollbar_spacing);
 }
 
 static void
@@ -1629,16 +1633,26 @@ size_allocate_cb (GtkWidget     *scrolle
 
 static void
 ev_window_set_sizing_mode (EvWindow     *ev_window,
-			   EvSizingMode  sizing_mode)
+			   EvSizingMode  sizing_mode,
+			   gboolean      first_time)
 {
 	GtkWidget *scrolled_window;
 
-	if (ev_window->priv->sizing_mode == sizing_mode)
-		return;
+	/* Short circuit the call if it's not the first time we call this */
+	if (!first_time) {
+		EvSizingMode old_sizing_mode;
 
-	scrolled_window = ev_window->priv->scrolled_window;
-	ev_window->priv->sizing_mode = sizing_mode;
+		g_object_get (ev_window->priv->view,
+			      "sizing-mode", &old_sizing_mode,
+			      NULL);
+		if (old_sizing_mode == sizing_mode)
+			return;
+	}
 
+	scrolled_window = ev_window->priv->scrolled_window;
+	g_object_set (ev_window->priv->view,
+		      "sizing-mode", sizing_mode,
+		      NULL);
 	g_signal_handlers_disconnect_by_func (scrolled_window, size_allocate_cb, ev_window);
 
 	update_view_size (ev_window);
@@ -2508,7 +2522,6 @@ ev_window_init (EvWindow *ev_window)
 			  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_FIT_WIDTH);
+	ev_window_set_sizing_mode (ev_window,  EV_SIZING_FIT_WIDTH, TRUE);
 	update_action_sensitivity (ev_window);
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]