diff -uprN evince/data/evince-ui.xml evince.new/data/evince-ui.xml
--- evince/data/evince-ui.xml	2005-06-18 10:50:29.000000000 +0400
+++ evince.new/data/evince-ui.xml	2005-06-22 16:05:02.000000000 +0400
@@ -77,9 +77,14 @@
   <accelerator name="ShiftSpaceAccel" action="ShiftSpace"/>
   <accelerator name="ShiftBackSpaceAccel" action="ShiftBackSpace"/>
   <accelerator name="FocusPageSelectorAccel" action="FocusPageSelector"/>
+
   <accelerator name="PlusAccel" action="Plus"/>
   <accelerator name="MinusAccel" action="Minus"/>
+  <accelerator name="Equal" action="Equal"/>
   <accelerator name="CtrlEqualAccel" action="CtrlEqual"/>
+  <accelerator name="KpPlusAccel" action="KpPlus"/>
+  <accelerator name="KpMinusAccel" action="KpMinus"/>
+  
   <accelerator name="GoBackwardFastAccel" action="GoBackwardFast"/>
   <accelerator name="GoForwardFastAccel" action="GoForwardFast"/>
 </ui>
diff -uprN evince/shell/ev-view.c evince.new/shell/ev-view.c
--- evince/shell/ev-view.c	2005-06-22 12:03:38.000000000 +0400
+++ evince.new/shell/ev-view.c	2005-06-22 16:05:02.000000000 +0400
@@ -35,6 +35,7 @@
 #include "ev-job-queue.h"
 #include "ev-page-cache.h"
 #include "ev-pixbuf-cache.h"
+#include "gtkgesture.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))
@@ -53,7 +54,7 @@ enum {
 };
 
 enum {
-	SIGNAL_SCROLL_VIEW,
+	SIGNAL_BINDING_ACTIVATED,
 	SIGNAL_ZOOM_INVALID,
 	N_SIGNALS,
 };
@@ -150,6 +151,8 @@ struct _EvView {
 	
 	PendingScroll pending_scroll;
 	gboolean pending_resize;
+	
+	GtkGestureHandler *gesture_handler;
 };
 
 struct _EvViewClass {
@@ -158,7 +161,7 @@ struct _EvViewClass {
 	void	(*set_scroll_adjustments) (EvView         *view,
 					   GtkAdjustment  *hadjustment,
 					   GtkAdjustment  *vadjustment);
-	void    (*scroll_view)		  (EvView         *view,
+	void    (*binding_activated)	  (EvView         *view,
 					   GtkScrollType   scroll,
 					   gboolean        horizontal);
 	void    (*zoom_invalid)		  (EvView         *view);
@@ -181,7 +184,7 @@ static void       add_scroll_binding_key
 							      guint               keyval,
 							      GtkScrollType       scroll,
 							      gboolean            horizontal);
-static void       ev_view_scroll_view                        (EvView             *view,
+static void       ev_view_binding_activated                  (EvView             *view,
 							      GtkScrollType       scroll,
 							      gboolean            horizontal);
 static void       ensure_rectangle_is_visible                (EvView             *view,
@@ -276,6 +279,33 @@ static void       page_changed_cb       
 static void       on_adjustment_value_changed                (GtkAdjustment      *adjustment,
 							      EvView             *view);
 
+/*** Gestures ***/
+static void	  gesture_page_next_event_cb 		     (GtkGestureHandler *gh,
+							      EvView *ev_view, 
+							      gpointer p);
+static void	  gesture_page_prev_event_cb 		     (GtkGestureHandler *gh,
+							      EvView *ev_view, 
+							      gpointer p);
+static void	  gesture_page_first_event_cb 		     (GtkGestureHandler *gh,
+							      EvView *ev_view, 
+							      gpointer p);
+static void	  gesture_page_last_event_cb 		     (GtkGestureHandler *gh,
+							      EvView *ev_view, 
+							      gpointer p);
+static void	  gesture_zoom_in_event_cb	 	     (GtkGestureHandler *gh,
+							      EvView *ev_view, 
+							      gpointer p);
+static void	  gesture_zoom_out_event_cb		     (GtkGestureHandler *gh,
+							      EvView *ev_view, 
+							      gpointer p);
+static void	  gesture_zoom_fit_width_event_cb 	     (GtkGestureHandler *gh,
+							      EvView *ev_view, 
+							      gpointer p);
+static void	  gesture_zoom_fit_page_event_cb	     (GtkGestureHandler *gh,
+							      EvView *ev_view, 
+							      gpointer p);
+static void      ev_view_setup_gesture_handler 	     (EvView *view);
+
 /*** GObject ***/
 static void       ev_view_finalize                           (GObject            *object);
 static void       ev_view_destroy                            (GtkObject          *object);
@@ -569,11 +599,11 @@ add_scroll_binding_keypad (GtkBindingSet
   guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
 
   gtk_binding_entry_add_signal (binding_set, keyval, 0,
-                                "scroll_view", 2,
+                                "binding_activated", 2,
                                 GTK_TYPE_SCROLL_TYPE, scroll,
 				G_TYPE_BOOLEAN, horizontal);
   gtk_binding_entry_add_signal (binding_set, keypad_keyval, 0,
-                                "scroll_view", 2,
+                                "binding_activated", 2,
                                 GTK_TYPE_SCROLL_TYPE, scroll,
 				G_TYPE_BOOLEAN, horizontal);
 }
@@ -633,12 +663,26 @@ ev_view_scroll (EvView        *view,
 }
 
 static void
-ev_view_scroll_view (EvView *view,
-		     GtkScrollType scroll,
-		     gboolean horizontal)
+ev_view_binding_activated (EvView *view,
+		    	   GtkScrollType scroll,
+		    	   gboolean horizontal)
 {
 	GtkAdjustment *adjustment;
 	double value;
+	
+	if (view->presentation) {
+		switch (scroll) {
+			case GTK_SCROLL_STEP_BACKWARD:
+				ev_page_cache_prev_page (view->page_cache);
+				break;
+			case GTK_SCROLL_STEP_FORWARD:
+				ev_page_cache_next_page (view->page_cache);
+				break;
+			default:
+				break;
+		}
+		return;
+	}
 
 	if (horizontal) {
 		adjustment = view->hadjustment;
@@ -1566,6 +1610,110 @@ draw_one_page (EvView       *view,
 	}
 }
 
+/*** Gestures ***/
+
+static void
+gesture_page_next_event_cb (GtkGestureHandler *gh,
+			    EvView *ev_view, gpointer p)
+{
+	ev_page_cache_next_page (ev_view->page_cache);
+}
+
+static void
+gesture_page_prev_event_cb (GtkGestureHandler *gh,
+			    EvView *ev_view, gpointer p)
+{
+	ev_page_cache_prev_page (ev_view->page_cache);
+}
+
+static void
+gesture_page_first_event_cb (GtkGestureHandler *gh,
+			     EvView *ev_view, gpointer p)
+{
+	ev_page_cache_set_current_page (ev_view->page_cache, 0);
+}
+
+static void
+gesture_page_last_event_cb (GtkGestureHandler *gh,
+			    EvView *ev_view, gpointer p)
+{
+	ev_page_cache_set_current_page (ev_view->page_cache,
+					ev_page_cache_get_n_pages (ev_view->page_cache) - 1);
+}
+
+static void
+gesture_zoom_in_event_cb (GtkGestureHandler *gh,
+			  EvView *ev_view, gpointer p)
+{
+	ev_view_set_sizing_mode (ev_view, EV_SIZING_FREE);
+	ev_view_zoom_in (ev_view);
+}
+
+static void
+gesture_zoom_out_event_cb (GtkGestureHandler *gh,
+			   EvView *ev_view, gpointer p)
+{
+	ev_view_set_sizing_mode (ev_view, EV_SIZING_FREE);
+	ev_view_zoom_out (ev_view);
+}
+
+static void
+gesture_zoom_fit_page_event_cb (GtkGestureHandler *gh,
+			  EvView *ev_view, gpointer p)
+{
+	ev_view_set_sizing_mode (ev_view, EV_SIZING_BEST_FIT);
+}
+
+static void
+gesture_zoom_fit_width_event_cb (GtkGestureHandler *gh,
+			   EvView *ev_view, gpointer p)
+{
+	ev_view_set_sizing_mode (ev_view, EV_SIZING_FIT_WIDTH);
+}
+
+static void
+ev_view_setup_gesture_handler (EvView *ev_view)
+{
+	GtkGestureHandler *gh;
+
+	gh = gtk_gesture_handler_new (GTK_WIDGET (ev_view));
+	ev_view->gesture_handler = gh;
+
+	gtk_gesture_add_callback (
+		gh, "012",
+		GTK_GESTURE_FUNC (gesture_page_next_event_cb),
+		ev_view, NULL);
+	gtk_gesture_add_callback (
+		gh, "210",
+		GTK_GESTURE_FUNC (gesture_page_prev_event_cb),
+		ev_view, NULL);
+	gtk_gesture_add_callback (
+		gh, "630",
+		GTK_GESTURE_FUNC (gesture_page_first_event_cb),
+		ev_view, NULL);
+	gtk_gesture_add_callback (
+		gh, "036",
+		GTK_GESTURE_FUNC (gesture_page_last_event_cb),
+		ev_view, NULL);
+
+	gtk_gesture_add_callback (
+		gh, "048",
+		GTK_GESTURE_FUNC (gesture_zoom_in_event_cb),
+		ev_view, NULL);
+	gtk_gesture_add_callback (
+		gh, "840",
+		GTK_GESTURE_FUNC (gesture_zoom_out_event_cb),
+		ev_view, NULL);
+	gtk_gesture_add_callback (
+		gh, "246",
+		GTK_GESTURE_FUNC (gesture_zoom_fit_width_event_cb),
+		ev_view, NULL);
+	gtk_gesture_add_callback (
+		gh, "642",
+		GTK_GESTURE_FUNC (gesture_zoom_fit_page_event_cb),
+		ev_view, NULL);
+}
+
 /*** GObject functions ***/
 
 static void
@@ -1596,6 +1744,12 @@ ev_view_destroy (GtkObject *object)
 		g_object_unref (view->pixbuf_cache);
 		view->pixbuf_cache = NULL;
 	}
+
+	if (view->gesture_handler) {
+		gtk_gesture_handler_destroy (view->gesture_handler);
+		view->gesture_handler = NULL;
+	}
+
 	ev_view_set_scroll_adjustments (view, NULL, NULL);
 
 	GTK_OBJECT_CLASS (ev_view_parent_class)->destroy (object);
@@ -1697,7 +1851,7 @@ ev_view_class_init (EvViewClass *class)
 	gtk_object_class->destroy = ev_view_destroy;
 
 	class->set_scroll_adjustments = ev_view_set_scroll_adjustments;
-	class->scroll_view = ev_view_scroll_view;
+	class->binding_activated = ev_view_binding_activated;
 
 	widget_class->set_scroll_adjustments_signal =  
 	    g_signal_new ("set-scroll-adjustments",
@@ -1710,10 +1864,10 @@ ev_view_class_init (EvViewClass *class)
 			  GTK_TYPE_ADJUSTMENT,
 			  GTK_TYPE_ADJUSTMENT);
 
-	signals[SIGNAL_SCROLL_VIEW] = g_signal_new ("scroll-view",
+	signals[SIGNAL_BINDING_ACTIVATED] = g_signal_new ("binding_activated",
 	  	         G_TYPE_FROM_CLASS (object_class),
 		         G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-		         G_STRUCT_OFFSET (EvViewClass, scroll_view),
+		         G_STRUCT_OFFSET (EvViewClass, binding_activated),
 		         NULL, NULL,
 		         ev_marshal_VOID__ENUM_BOOLEAN,
 		         G_TYPE_NONE, 2,
@@ -1890,7 +2044,8 @@ static void on_adjustment_value_changed 
 
 
 	if (view->document)
-		view_update_range_and_current_page (view);}
+		view_update_range_and_current_page (view);
+}
 
 GtkWidget*
 ev_view_new (void)
@@ -1956,6 +2111,7 @@ ev_view_set_document (EvView     *view,
 			}
 
 			setup_caches (view);
+			ev_view_setup_gesture_handler (view);
                 }
 
 		gtk_widget_queue_resize (GTK_WIDGET (view));
diff -uprN evince/shell/ev-window.c evince.new/shell/ev-window.c
--- evince/shell/ev-window.c	2005-06-19 21:36:41.000000000 +0400
+++ evince.new/shell/ev-window.c	2005-06-22 16:05:02.000000000 +0400
@@ -2206,17 +2206,18 @@ ev_window_sidebar_visibility_changed_cb 
 					 EvWindow   *ev_window)
 {
 	GtkAction *action;
-	gboolean visible, fullscreen;
+	gboolean visible, fullscreen_mode;
+
+
+	fullscreen_mode = ev_view_get_presentation (EV_VIEW (ev_window->priv->view)) ||
+			       ev_view_get_fullscreen (EV_VIEW (ev_window->priv->view));
 
-	g_object_get (ev_window->priv->view,
-		      "fullscreen", &fullscreen,
-		      NULL);
 	visible = GTK_WIDGET_VISIBLE (ev_sidebar);
 
 	/* In fullscreen mode the sidebar is not visible,
 	 * but we don't want to update the chrome
 	 */
-	if (fullscreen)
+	if (fullscreen_mode)
 		return;
 	
 	action = gtk_action_group_get_action (ev_window->priv->action_group, "ViewSidebar");
@@ -2619,6 +2620,7 @@ static const GtkActionEntry entries[] = 
         { "ShiftBackSpace", NULL, "", "<shift>BackSpace",
           N_("Scroll one page forward"),
           G_CALLBACK (ev_window_cmd_scroll_forward) },
+
         { "Plus", GTK_STOCK_ZOOM_IN, NULL, "plus",
           N_("Enlarge the document"),
           G_CALLBACK (ev_window_cmd_view_zoom_in) },
@@ -2628,9 +2630,20 @@ static const GtkActionEntry entries[] = 
         { "Minus", GTK_STOCK_ZOOM_OUT, NULL, "minus",
           N_("Shrink the document"),
           G_CALLBACK (ev_window_cmd_view_zoom_out) },
+        { "Equal", GTK_STOCK_ZOOM_IN, NULL, "equal",
+          N_("Enlarge the document"),
+          G_CALLBACK (ev_window_cmd_view_zoom_in) },
+        { "KpPlus", GTK_STOCK_ZOOM_IN, NULL, "KP_Add",
+          N_("Enlarge the document"),
+          G_CALLBACK (ev_window_cmd_view_zoom_in) },
+        { "KpMinus", GTK_STOCK_ZOOM_OUT, NULL, "KP_Subtract",
+          N_("Shrink the document"),
+          G_CALLBACK (ev_window_cmd_view_zoom_out) },
+
         { "FocusPageSelector", NULL, "", "<control>l",
           N_("Focus the page selector"),
           G_CALLBACK (ev_window_cmd_focus_page_selector) },
+
         { "GoBackwardFast", NULL, "", "<shift>Page_Up",
           N_("Go ten pages backward"),
           G_CALLBACK (ev_window_cmd_go_backward) },
@@ -2878,7 +2891,7 @@ sidebar_widget_model_set (EvSidebarLinks
 
 
 static void
-set_view_actions_sensitivity (EvWindow *window, gboolean sensitive)
+ev_window_set_accels_sensitivity (EvWindow *window, gboolean sensitive)
 {
 	if (window->priv->action_group) {
 		set_action_sensitive (window, "PageDown", sensitive);
@@ -2890,6 +2903,9 @@ set_view_actions_sensitivity (EvWindow *
 		set_action_sensitive (window, "Slash", sensitive);
 		set_action_sensitive (window, "Plus", sensitive);
 		set_action_sensitive (window, "Minus", sensitive);
+		set_action_sensitive (window, "KpPlus", sensitive);
+		set_action_sensitive (window, "KpMinus", sensitive);
+		set_action_sensitive (window, "Equal", sensitive);
 	}
 }
 
@@ -2899,13 +2915,13 @@ view_actions_focus_in_cb (GtkWidget *wid
 	update_chrome_flag (window, EV_CHROME_RAISE_TOOLBAR, NULL, FALSE);
 	set_action_sensitive (window, "ViewToolbar", TRUE);
 
-	set_view_actions_sensitivity (window, TRUE);
+	ev_window_set_accels_sensitivity (window, TRUE);
 }
 
 static void
 view_actions_focus_out_cb (GtkWidget *widget, GdkEventFocus *event, EvWindow *window)
 {
-	set_view_actions_sensitivity (window, FALSE);
+	ev_window_set_accels_sensitivity (window, FALSE);
 }
 
 static void
@@ -2967,7 +2983,7 @@ ev_window_init (EvWindow *ev_window)
 		gtk_ui_manager_get_accel_group (ev_window->priv->ui_manager);
 	gtk_window_add_accel_group (GTK_WINDOW (ev_window), accel_group);
 
-	set_view_actions_sensitivity (ev_window, FALSE);
+	ev_window_set_accels_sensitivity (ev_window, FALSE);
 
 	g_signal_connect (ev_window->priv->ui_manager, "connect_proxy",
 			  G_CALLBACK (connect_proxy_cb), ev_window);
diff -uprN evince/shell/gtkgesture.c evince.new/shell/gtkgesture.c
--- evince/shell/gtkgesture.c	1970-01-01 03:00:00.000000000 +0300
+++ evince.new/shell/gtkgesture.c	2005-06-22 16:01:52.000000000 +0400
@@ -0,0 +1,379 @@
+/*
+ * Primitive gesture recognition
+ *
+ * Author:
+ *      Michael Meeks <mmeeks@gnu.org>
+ */
+
+#include <glib.h>
+#include <math.h>
+#include <stdio.h>
+#include <gtk/gtk.h>
+#include <gtkgesture.h>
+
+typedef struct {
+	char           *gesture;
+	GtkGestureFunc  cb_func;
+	gpointer        user_data_a;
+	gpointer        user_data_b;
+} Callback;
+
+typedef struct {
+	GtkGestureHandler  h;
+	GList             *callbacks;
+	GList             *points;
+	gboolean           stroking;
+	guint              button;
+	gdouble            tlx, tly, brx, bry;
+} GestureHandlerPriv;
+
+typedef struct {
+	gdouble x;
+	gdouble y;
+} GesturePoint;
+
+static GestureHandlerPriv *
+gesture_data_new (GtkWidget *widget, guint button)
+{
+	GestureHandlerPriv *ghp = g_new (GestureHandlerPriv, 1);
+
+	ghp->h.widget  = widget;
+	ghp->callbacks = NULL;
+	ghp->points    = NULL;
+	ghp->stroking  = FALSE;
+	ghp->button    = button;
+
+	ghp->tlx = 0.0;
+	ghp->tly = 0.0;
+	ghp->brx = 0.0;
+	ghp->bry = 0.0;
+
+	return ghp;
+}
+
+static void
+gesture_data_free_points (GestureHandlerPriv *ghp)
+{
+	GList *l;
+	g_return_if_fail (ghp != NULL);
+	
+	for (l = ghp->points; l; l = g_list_next (l))
+		g_free (l->data);
+
+	g_list_free (ghp->points);
+
+	ghp->points = NULL;
+}
+
+static void
+gesture_data_append_point (GestureHandlerPriv *ghp,
+			  const gdouble * const x,
+			  const gdouble * const y)
+{
+	GesturePoint *ghpoint;
+
+	g_return_if_fail (ghp != NULL);
+	ghpoint = g_new (GesturePoint, 1);
+
+	ghpoint->x = *x;
+	ghpoint->y = *y;
+
+	/* Attempt at rendering */
+	if (GTK_WIDGET_FLAGS (GTK_WIDGET (ghp->h.widget)) & GTK_NO_WINDOW)
+		g_warning ("No window for the gesturing widget");
+	else if (ghp->points) {
+		GdkGC       *gc;
+		GesturePoint *lghpoint = ghp->points->data;
+
+		g_return_if_fail (lghpoint != NULL);
+
+		gc = gdk_gc_new (ghp->h.widget->window);
+		gdk_gc_copy (gc, ghp->h.widget->style->bg_gc[GTK_STATE_SELECTED]);
+		gdk_gc_set_line_attributes (gc, 3, GDK_LINE_SOLID, GDK_CAP_BUTT,
+					    GDK_JOIN_MITER);
+		gdk_draw_line (ghp->h.widget->window, gc,
+			       ghpoint->x, ghpoint->y,
+			       lghpoint->x, lghpoint->y);
+		g_object_unref (G_OBJECT (gc));
+	}
+
+	ghp->points = g_list_prepend (ghp->points, ghpoint);
+}
+
+/*
+ * Normalize the gestures dimensions,
+ * tlx, tly are purely for interest / debug.
+ * The result is in the range 0-2, 0-2 x vs. y
+ * There are good reasons for several passes.
+ */
+static void
+gesture_normalize_dimensions (GestureHandlerPriv *ghp)
+{
+	GList   *l;
+	gdouble  dx, dy;
+
+	ghp->points = g_list_reverse (ghp->points);
+
+	/* Find the top left corner */
+	for (l = ghp->points; l; l = g_list_next (l)) {
+		const GesturePoint * const ghpoint = l->data;
+
+		if (!g_list_previous (l)) {
+			ghp->tlx = ghpoint->x;
+			ghp->tly = ghpoint->y;
+			ghp->brx = ghpoint->x;
+			ghp->bry = ghpoint->y;
+		} else {
+			if (ghpoint->x < ghp->tlx)
+				ghp->tlx = ghpoint->x;
+			if (ghpoint->y < ghp->tly)
+				ghp->tly = ghpoint->y;
+			if (ghpoint->x > ghp->brx)
+				ghp->brx = ghpoint->x;
+			if (ghpoint->y > ghp->bry)
+				ghp->bry = ghpoint->y;
+		}
+	}
+
+ 	/*  Relativize [ John 3:18 ] to tlc */
+	for (l = ghp->points; l; l = g_list_next (l)) {
+		GesturePoint * const ghpoint = l->data;
+
+		ghpoint->x -= ghp->tlx;
+		ghpoint->y -= ghp->tly;
+	}
+
+	/* We want to detect gestures such as 012 */
+	dx = ghp->brx - ghp->tlx;
+	dy = ghp->bry - ghp->tly;
+	if (dx > 2.0 * dy)
+		dy = dx;
+	else if (dy > 2.0 * dx)
+		dx = dy;
+
+	/* Normalize to side calculation. */
+	for (l = ghp->points; l; l = g_list_next (l)) {
+		GesturePoint * const ghpoint = l->data;
+
+		ghpoint->x = (ghpoint->x * 3.0) / dx;
+		ghpoint->y = (ghpoint->y * 3.0) / dy;
+	}
+}
+
+/*
+ * The resolution of this bitmap may need tweaking.
+ */
+#define GESTURE_BITMAP_MAX 4.0
+int gesture_lookup[12][12] = {
+	{ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1 },
+	{ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1 },
+	{ 1, 1, 1, 0,  0, 1, 1, 0,  0, 0, 1, 1 },
+	{ 1, 1, 0, 0,  0, 0, 0, 0,  0, 0, 1, 1 },
+	{ 1, 1, 0, 0,  0, 1, 1, 0,  0, 0, 1, 1 },
+	{ 1, 1, 1, 0,  1, 1, 1, 1,  0, 1, 1, 1 },
+	{ 1, 1, 1, 0,  1, 1, 1, 1,  0, 1, 1, 1 },
+	{ 1, 1, 0, 0,  0, 1, 1, 0,  0, 0, 1, 1 },
+	{ 1, 1, 0, 0,  0, 0, 0, 0,  0, 0, 1, 1 },
+	{ 1, 1, 1, 0,  0, 1, 1, 0,  0, 1, 1, 1 },
+	{ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1 },
+	{ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1 }
+};
+
+static GArray *
+gesture_analyze (GestureHandlerPriv *ghp)
+{
+	GArray  *ans = g_array_new (FALSE, FALSE, sizeof (int));
+
+	gesture_normalize_dimensions (ghp);
+	gtk_widget_queue_draw_area (ghp->h.widget,
+				    ghp->tlx, ghp->tly,
+				    ghp->brx - ghp->tlx,
+				    ghp->bry - ghp->tly);
+	{ /* Gesture the data */
+		guint  lastpos;
+		GList *l;
+		
+		lastpos = -1;
+		for (l = ghp->points; l; l = g_list_next (l)) {
+			guint x, y, sx, sy;
+			GesturePoint * const ghpoint = l->data;
+			x  = floor (ghpoint->x * GESTURE_BITMAP_MAX);
+			y  = floor (ghpoint->y * GESTURE_BITMAP_MAX);
+			sx = floor (ghpoint->x);
+			sy = floor (ghpoint->y);
+			if (sx >= 3)
+				sx = 2;
+			if (sy >= 3)
+				sy = 2;
+			if (gesture_lookup[x][y] &&
+			    (sx + sy * 3) != lastpos) {
+				lastpos = sx + sy * 3;
+				g_array_append_val (ans, lastpos);
+			}
+		}
+	}
+
+	return ans;
+}
+
+/*
+ * Expand to allow "63048|6308" style syntax.
+ */
+static gboolean
+gesture_path_compare (GArray *path, const char * compare)
+{
+	gint       i, j;
+	gchar    **gestures;
+	gboolean   ans;
+
+	if (!path || path->len == 0 || !compare || !compare[0])
+		return FALSE;
+
+	gestures = g_strsplit (compare, "|", -1);
+	
+	ans = FALSE;
+	for (j = 0; gestures[j] && !ans; j++) {
+		for (i = 0, ans = TRUE; gestures[j][i] && i < path->len && ans; i++) {
+			if (gestures[j][i] - '0' != g_array_index (path, int, i))
+				ans = FALSE;
+		}
+
+		if (ans && i < path->len)
+			ans = FALSE;
+
+		g_free (gestures[j]);
+	}
+
+	while (gestures[j])
+		g_free (gestures[j++]);
+	g_free (gestures);
+
+	return ans;
+}
+
+static gint
+gesture_event (GtkWidget *widget, GdkEvent *event,
+	       GestureHandlerPriv *ghp)
+{
+	gint handled = FALSE;
+
+	g_return_val_if_fail (ghp != NULL, FALSE);
+	g_return_val_if_fail (widget != NULL, FALSE);
+	g_return_val_if_fail (event != NULL, FALSE);
+
+	switch (event->type) {
+	case GDK_BUTTON_PRESS:
+		if (event->button.button == ghp->button) {
+			ghp->stroking = TRUE;
+			gesture_data_free_points (ghp);
+			handled = TRUE;
+		}
+		break;
+	case GDK_LEAVE_NOTIFY:
+		if (!ghp->stroking)
+			break;
+		/* else drop down */
+	case GDK_BUTTON_RELEASE:
+		if (event->button.button == ghp->button) {
+			GArray *path;
+			GList  *l;
+
+			ghp->stroking = FALSE;
+
+			path = gesture_analyze (ghp);
+
+			for (l = ghp->callbacks; l; l = g_list_next (l)) {
+				Callback *cb = (Callback *)l->data;
+				if (gesture_path_compare (path, cb->gesture))
+					cb->cb_func ((GtkGestureHandler *)ghp,
+						     cb->user_data_a,
+						     cb->user_data_b);
+			}
+
+			g_array_free (path, TRUE);
+			
+			gtk_widget_queue_draw (widget);
+			
+			handled = TRUE;
+		}
+		break;
+	case GDK_MOTION_NOTIFY:
+		if (ghp->stroking) {
+			gesture_data_append_point (ghp, &event->motion.x,
+						  &event->motion.y);
+			handled = TRUE;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return handled;
+}
+
+void
+gtk_gesture_handler_attach (GtkGestureHandler *gh,
+			    GtkWidget *widget)
+{
+	g_signal_connect (G_OBJECT (widget), "event",
+			  G_CALLBACK (gesture_event), gh);
+}
+
+GtkGestureHandler *
+gtk_gesture_handler_new (GtkWidget *widget)
+{
+	GtkGestureHandler *gh;
+      
+	g_return_val_if_fail (widget != NULL, NULL);
+
+	gh = (GtkGestureHandler *)gesture_data_new (widget, 3);
+
+	gtk_gesture_handler_attach (gh, widget);
+
+	return gh;
+}
+
+void
+gtk_gesture_add_callback (GtkGestureHandler *gh,
+			  const char        *gesture,
+			  GtkGestureFunc     cb_func,
+			  gpointer           user_data_a,
+			  gpointer           user_data_b)
+{
+	Callback *cb;
+	GestureHandlerPriv *ghp = (GestureHandlerPriv *)gh;
+
+	g_return_if_fail (gh != NULL);
+	g_return_if_fail (cb_func != NULL);
+	g_return_if_fail (gesture != NULL);
+
+	cb              = g_new (Callback, 1);
+	cb->gesture     = g_strdup (gesture);
+	cb->cb_func     = cb_func;
+	cb->user_data_a = user_data_a;
+	cb->user_data_b = user_data_b;
+
+	ghp->callbacks  = g_list_prepend (ghp->callbacks, cb);
+}
+
+void
+gtk_gesture_handler_destroy (GtkGestureHandler *gh)
+{
+	GestureHandlerPriv *ghp = (GestureHandlerPriv *)gh;
+
+	while (ghp->callbacks) {
+		Callback *cb = ghp->callbacks->data;
+
+		if (cb->gesture)
+			g_free (cb->gesture);
+		cb->gesture = NULL;
+		g_free (cb);
+
+		ghp->callbacks = g_list_remove (ghp->callbacks, cb);
+	}
+
+	if (ghp->points)
+		gesture_data_free_points (ghp);
+
+	g_free (ghp);
+}
diff -uprN evince/shell/gtkgesture.h evince.new/shell/gtkgesture.h
--- evince/shell/gtkgesture.h	1970-01-01 03:00:00.000000000 +0300
+++ evince.new/shell/gtkgesture.h	2002-10-12 15:46:34.000000000 +0400
@@ -0,0 +1,44 @@
+/*
+ * Primitive gesture recognition
+ *
+ * Author:
+ *      Michael Meeks <mmeeks@gnu.org>
+ */
+
+/*
+ *   A gesture is described by the path traced in 9 regions which are
+ * numbered thus:
+ *
+ *   0  1  2       So to describe a standard 'zoom in' gesture we would
+ *   3  4  5       have "048", for a standard 'help' stroke we might have
+ *   6  7  8       "3157|3012587|3012547" for example tracing a '?' shape.
+ */
+
+#ifndef GTK_GESTURE_HANDLER_H
+#define GTK_GESTURE_HANDLER_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct {
+	GtkWidget *widget;
+} GtkGestureHandler;
+
+typedef void (*GtkGestureFunc) (GtkGestureHandler *gh, gpointer user_data_a,
+				gpointer user_data_b);
+#define GTK_GESTURE_FUNC(g)    ((GtkGestureFunc)(g))
+
+GtkGestureHandler *gtk_gesture_handler_new     (GtkWidget *widget);
+void               gtk_gesture_handler_attach  (GtkGestureHandler *gh,
+						GtkWidget *widget);
+void               gtk_gesture_add_callback    (GtkGestureHandler *gh,
+						const char *gesture,
+						GtkGestureFunc cb_func,
+						gpointer user_data_a,
+						gpointer user_data_b);
+void               gtk_gesture_handler_destroy (GtkGestureHandler *gh);
+
+G_END_DECLS
+
+#endif /* GTK_GESTURE_HANDLER_H */
diff -uprN evince/shell/Makefile.am evince.new/shell/Makefile.am
--- evince/shell/Makefile.am	2005-06-08 03:28:54.000000000 +0400
+++ evince.new/shell/Makefile.am	2005-06-22 16:05:02.000000000 +0400
@@ -98,6 +98,8 @@ evince_SOURCES=				\
 	ev-statusbar.h			\
 	ev-stock-icons.c		\
 	ev-stock-icons.h		\
+	gtkgesture.c			\
+	gtkgesture.h			\
 	main.c				\
 	$(NULL)
 
