]> www.fi.muni.cz Git - evince.git/blobdiff - shell/ev-view.c
Updated Ukrainian translation.
[evince.git] / shell / ev-view.c
index 131966b9c16af5d93ae8b86fdf775bfaf2e48add..7fe99552eb4e3ea83c3c9cf6454bad465bcb0537 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "ev-marshal.h"
 #include "ev-view.h"
+#include "ev-utils.h"
 #include "ev-selection.h"
 #include "ev-document-find.h"
 #include "ev-document-misc.h"
@@ -41,6 +42,7 @@
 #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))
 
+
 enum {
        PROP_0,
        PROP_STATUS,
@@ -85,6 +87,11 @@ typedef enum {
        EV_VIEW_CURSOR_DRAG
 } EvViewCursor;
 
+typedef enum {
+       EV_VIEW_FIND_NEXT,
+       EV_VIEW_FIND_PREV
+} EvViewFindDirection;
+
 #define ZOOM_IN_FACTOR  1.2
 #define ZOOM_OUT_FACTOR (1.0/ZOOM_IN_FACTOR)
 
@@ -120,6 +127,10 @@ struct _EvView {
        char *status;
        char *find_status;
 
+       /* Scrolling */
+       GtkAdjustment *hadjustment;
+       GtkAdjustment *vadjustment;
+
        gint scroll_x;
        gint scroll_y;
 
@@ -127,15 +138,16 @@ struct _EvView {
        DragInfo drag_info;
 
        /* Selection */
+       gint motion_x;
+       gint motion_y;
+       guint selection_update_id;
+
        EvViewSelectionMode selection_mode;
        SelectionInfo selection_info;
 
-       gboolean pressed_button;
+       int pressed_button;
        EvViewCursor cursor;
 
-       GtkAdjustment *hadjustment;
-       GtkAdjustment *vadjustment;
-
        EvPageCache *page_cache;
        EvPixbufCache *pixbuf_cache;
 
@@ -149,6 +161,7 @@ struct _EvView {
        int find_result;
        int spacing;
 
+       int rotation;
        double scale;
 
        gboolean continuous;
@@ -258,6 +271,10 @@ static gboolean   ev_view_motion_notify_event                (GtkWidget
                                                              GdkEventMotion     *event);
 static gboolean   ev_view_button_release_event               (GtkWidget          *widget,
                                                              GdkEventButton     *event);
+static gboolean   ev_view_leave_notify_event                 (GtkWidget          *widget,
+                                                             GdkEventCrossing   *event);
+static void       ev_view_style_set                          (GtkWidget          *widget,
+                                                             GtkStyle           *old_style);
 
 /*** Drawing ***/
 static guint32    ev_gdk_color_to_rgb                        (const GdkColor     *color);
@@ -347,13 +364,15 @@ static void       ev_view_set_find_status                    (EvView
                                                              const char         *message);
 /*** Find ***/
 static void       jump_to_find_result                        (EvView             *view);
-static void       jump_to_find_page                          (EvView             *view);
+static void       jump_to_find_page                          (EvView             *view, 
+                                                             EvViewFindDirection direction);
 
 /*** Selection ***/
 static void       compute_selections                         (EvView             *view,
                                                              GdkPoint           *start,
                                                              GdkPoint           *stop);
 static void       clear_selection                            (EvView             *view);
+static void       selection_free                             (EvViewSelection    *selection);
 static char*      get_selected_text                          (EvView             *ev_view);
 static void       ev_view_primary_get_cb                     (GtkClipboard       *clipboard,
                                                              GtkSelectionData   *selection_data,
@@ -371,7 +390,11 @@ scroll_to_current_page (EvView *view, GtkOrientation orientation)
 {
        GdkRectangle page_area;
        GtkBorder border;
-       
+
+       if (view->document == NULL) {
+               return;
+       }
+
        get_page_extents (view, view->current_page, &page_area, &border);
 
        if (orientation == GTK_ORIENTATION_VERTICAL) {
@@ -465,6 +488,9 @@ view_set_adjustment_values (EvView         *view,
 static void
 view_update_range_and_current_page (EvView *view)
 {
+       if (view->pending_scroll != SCROLL_TO_KEEP_POSITION)
+               return;
+
        /* Presentation trumps all other modes */
        if (view->presentation) {
                view->start_page = view->current_page;
@@ -525,6 +551,7 @@ view_update_range_and_current_page (EvView *view)
        ev_pixbuf_cache_set_page_range (view->pixbuf_cache,
                                        view->start_page,
                                        view->end_page,
+                                       view->rotation,
                                        view->scale,
                                        view->selection_info.selections);
 }
@@ -699,6 +726,8 @@ ensure_rectangle_is_visible (EvView *view, GdkRectangle *rect)
        GtkAdjustment *adjustment;
        int value;
 
+       view->pending_scroll = SCROLL_TO_KEEP_POSITION;
+
        adjustment = view->vadjustment;
 
        if (rect->y < adjustment->value) {
@@ -739,25 +768,25 @@ compute_border (EvView *view, int width, int height, GtkBorder *border)
        }
 }
 
-static void       get_page_y_offset                          (EvView *view,
-                                                             int page,
-                                                             double zoom,
-                                                             int *y_offset)
+static void
+get_page_y_offset (EvView *view, int page, double zoom, int *y_offset)
 {
        int max_width, offset;
        GtkBorder border;
 
        g_return_if_fail (y_offset != NULL);
 
-       ev_page_cache_get_max_width (view->page_cache, zoom, &max_width);
+       ev_page_cache_get_max_width (view->page_cache, view->rotation, zoom, &max_width);
 
        compute_border (view, max_width, max_width, &border);
 
        if (view->dual_page) {
-               ev_page_cache_get_height_to_page (view->page_cache, page, zoom, NULL, &offset);
+               ev_page_cache_get_height_to_page (view->page_cache, page,
+                                                 view->rotation, zoom, NULL, &offset);
                offset += (page / 2 + 1) * view->spacing + (page / 2) * (border.top + border.bottom);
        } else {
-               ev_page_cache_get_height_to_page (view->page_cache, page, zoom, &offset, NULL);
+               ev_page_cache_get_height_to_page (view->page_cache, page,
+                                                 view->rotation, zoom, &offset, NULL);
                offset += (page + 1) * view->spacing + page * (border.top + border.bottom);
        }
 
@@ -778,6 +807,7 @@ get_page_extents (EvView       *view,
 
        /* Get the size of the page */
        ev_page_cache_get_size (view->page_cache, page,
+                               view->rotation,
                                view->scale,
                                &width, &height);
        compute_border (view, width, height, border);
@@ -791,7 +821,8 @@ get_page_extents (EvView       *view,
                gint max_width;
                gint x, y;
 
-               ev_page_cache_get_max_width (view->page_cache, view->scale, &max_width);
+               ev_page_cache_get_max_width (view->page_cache, view->rotation,
+                                            view->scale, &max_width);
                max_width = max_width + border->left + border->right;
                /* Get the location of the bounding box */
                if (view->dual_page) {
@@ -823,6 +854,7 @@ get_page_extents (EvView       *view,
                        if (other_page < ev_page_cache_get_n_pages (view->page_cache)) {
                                ev_page_cache_get_size (view->page_cache,
                                                        other_page,
+                                                       view->rotation,
                                                        view->scale,
                                                        &width_2, &height_2);
                                if (width_2 > width)
@@ -895,16 +927,44 @@ doc_rect_to_view_rect (EvView       *view,
 {
        GdkRectangle page_area;
        GtkBorder border;
+       double x, y, w, h;
        int width, height;
 
+       ev_page_cache_get_size (view->page_cache, page,
+                               view->rotation,
+                               1.0,
+                               &width, &height);
+
+       if (view->rotation == 0) {
+               x = doc_rect->x1;
+               y = doc_rect->y1;
+               w = doc_rect->x2 - doc_rect->x1;
+               h = doc_rect->y2 - doc_rect->y1;
+       } else if (view->rotation == 90) {
+               x = width - doc_rect->y2;
+               y = doc_rect->x1;
+               w = doc_rect->y2 - doc_rect->y1;
+               h = doc_rect->x2 - doc_rect->x1;
+       } else if (view->rotation == 180) {
+               x = width - doc_rect->x2;
+               y = height - doc_rect->y2;
+               w = doc_rect->x2 - doc_rect->x1;
+               h = doc_rect->y2 - doc_rect->y1;
+       } else if (view->rotation == 270) {
+               x = doc_rect->y1;
+               y = height - doc_rect->x2;
+               w = doc_rect->y2 - doc_rect->y1;
+               h = doc_rect->x2 - doc_rect->x1;
+       } else {
+               g_assert_not_reached ();
+       }
+
        get_page_extents (view, page, &page_area, &border);
 
-       width = doc_rect->x2 - doc_rect->x1;
-       height = doc_rect->y2 - doc_rect->y1;
-       view_rect->x = floor (doc_rect->x1 * view->scale) + page_area.x;
-       view_rect->y = floor (doc_rect->y1 * view->scale) + page_area.y;
-       view_rect->width = ceil (width * view->scale);
-       view_rect->height = ceil (height * view->scale);
+       view_rect->x = x * view->scale + page_area.x;
+       view_rect->y = y * view->scale + page_area.y;
+       view_rect->width = w * view->scale;
+       view_rect->height = h * view->scale;
 }
 
 static void
@@ -1054,7 +1114,8 @@ ev_view_size_request_continuous_dual_page (EvView         *view,
        gint n_pages;
        GtkBorder border;
 
-       ev_page_cache_get_max_width (view->page_cache, view->scale, &max_width);
+       ev_page_cache_get_max_width (view->page_cache, view->rotation,
+                                    view->scale, &max_width);
        compute_border (view, max_width, max_width, &border);
 
        n_pages = ev_page_cache_get_n_pages (view->page_cache) + 1;
@@ -1081,7 +1142,8 @@ ev_view_size_request_continuous (EvView         *view,
        GtkBorder border;
 
 
-       ev_page_cache_get_max_width (view->page_cache, view->scale, &max_width);
+       ev_page_cache_get_max_width (view->page_cache, view->rotation,
+                                    view->scale, &max_width);
        n_pages = ev_page_cache_get_n_pages (view->page_cache);
        compute_border (view, max_width, max_width, &border);
 
@@ -1108,12 +1170,14 @@ ev_view_size_request_dual_page (EvView         *view,
        /* Find the largest of the two. */
        ev_page_cache_get_size (view->page_cache,
                                view->current_page,
+                               view->rotation,
                                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->rotation,
                                        view->scale,
                                        &width_2, &height_2);
                if (width_2 > width) {
@@ -1145,6 +1209,7 @@ ev_view_size_request_single_page (EvView         *view,
 
        ev_page_cache_get_size (view->page_cache,
                                view->current_page,
+                               view->rotation,
                                view->scale,
                                &width, &height);
        compute_border (view, width, height, &border);
@@ -1378,6 +1443,19 @@ ev_view_button_press_event (GtkWidget      *widget,
        return FALSE;
 }
 
+
+static gboolean
+selection_update_idle_cb (EvView *view)
+{
+       GdkPoint point;
+       point.x = view->motion_x;
+       point.y = view->motion_y;
+       compute_selections (view, &view->selection_info.start, &point);
+
+       view->selection_update_id = 0;
+       return FALSE;
+}
+
 static gboolean
 ev_view_motion_notify_event (GtkWidget      *widget,
                             GdkEventMotion *event)
@@ -1388,12 +1466,16 @@ ev_view_motion_notify_event (GtkWidget      *widget,
                return FALSE;
 
        if (view->pressed_button == 1) {
-               GdkPoint point;
-
                view->selection_info.in_selection = TRUE;
-               point.x = event->x + view->scroll_x;
-               point.y = event->y + view->scroll_y;
-               compute_selections (view, &view->selection_info.start, &point);
+               view->motion_x = event->x + view->scroll_x;
+               view->motion_y = event->y + view->scroll_y;
+
+               /* Queue an idle to handle the motion.  We do this because
+                * handling any selection events in the motion is probably going
+                * to be slower than new motion events reach us.  This means that */
+
+               if (! view->selection_update_id)
+                       view->selection_update_id = g_idle_add ((GSourceFunc)selection_update_idle_cb, view);
 
                return TRUE;
        } else if (view->pressed_button == 2) {
@@ -1484,6 +1566,53 @@ ev_view_button_release_event (GtkWidget      *widget,
        return FALSE;
 }
 
+static gint
+ev_view_focus_in (GtkWidget     *widget,
+                 GdkEventFocus *event)
+{
+       if (EV_VIEW (widget)->pixbuf_cache)
+               ev_pixbuf_cache_style_changed (EV_VIEW (widget)->pixbuf_cache);
+       gtk_widget_queue_draw (widget);
+
+       return FALSE;
+}
+
+static gint
+ev_view_focus_out (GtkWidget     *widget,
+                    GdkEventFocus *event)
+{
+       if (EV_VIEW (widget)->pixbuf_cache)
+               ev_pixbuf_cache_style_changed (EV_VIEW (widget)->pixbuf_cache);
+       gtk_widget_queue_draw (widget);
+
+       return FALSE;
+}
+
+static gboolean
+ev_view_leave_notify_event (GtkWidget *widget, GdkEventCrossing   *event)
+{
+       EvView *view = EV_VIEW (widget);
+    
+       ev_view_set_status (view, NULL);
+
+       if (view->cursor == EV_VIEW_CURSOR_LINK ||
+           view->cursor == EV_VIEW_CURSOR_IBEAM)
+               ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
+
+       return FALSE;
+}
+
+static void
+ev_view_style_set (GtkWidget *widget,
+                  GtkStyle  *old_style)
+{
+       if (EV_VIEW (widget)->pixbuf_cache)
+               ev_pixbuf_cache_style_changed (EV_VIEW (widget)->pixbuf_cache);
+
+       GTK_WIDGET_CLASS (ev_view_parent_class)->style_set (widget, old_style);
+}
+
+
 /*** Drawing ***/
 
 static guint32
@@ -1583,7 +1712,8 @@ draw_one_page (EvView          *view,
 
        selection = find_selection_for_page (view, page);
        ev_page_cache_get_size (view->page_cache,
-                               page, view->scale,
+                               page, view->rotation,
+                               view->scale,
                                &width, &height);
        /* Render the document itself */
        real_page_area = *page_area;
@@ -1608,7 +1738,8 @@ draw_one_page (EvView          *view,
                if (current_pixbuf && view->selection_mode == EV_VIEW_SELECTION_TEXT && selection)
                        selection_pixbuf = ev_pixbuf_cache_get_selection_pixbuf (view->pixbuf_cache,
                                                                                 page,
-                                                                                view->scale);
+                                                                                view->scale,
+                                                                                NULL);
 
                if (current_pixbuf == NULL)
                        scaled_image = NULL;
@@ -1785,11 +1916,15 @@ ev_view_class_init (EvViewClass *class)
        widget_class->button_press_event = ev_view_button_press_event;
        widget_class->motion_notify_event = ev_view_motion_notify_event;
        widget_class->button_release_event = ev_view_button_release_event;
+       widget_class->focus_in_event = ev_view_focus_in;
+       widget_class->focus_out_event = ev_view_focus_out;
        widget_class->size_request = ev_view_size_request;
        widget_class->size_allocate = ev_view_size_allocate;
        widget_class->realize = ev_view_realize;
        widget_class->unrealize = ev_view_unrealize;
        widget_class->scroll_event = ev_view_scroll_event;
+       widget_class->leave_notify_event = ev_view_leave_notify_event;
+       widget_class->style_set = ev_view_style_set;
        gtk_object_class->destroy = ev_view_destroy;
 
        class->set_scroll_adjustments = ev_view_set_scroll_adjustments;
@@ -1924,7 +2059,7 @@ ev_view_init (EvView *view)
 static void
 find_changed_cb (EvDocument *document, int page, EvView *view)
 {
-       jump_to_find_page (view);
+       jump_to_find_page (view, EV_VIEW_FIND_NEXT);
        jump_to_find_result (view);
        update_find_status_message (view);
 
@@ -2006,7 +2141,7 @@ setup_caches (EvView *view)
 {
        view->page_cache = ev_page_cache_get (view->document);
        g_signal_connect (view->page_cache, "page-changed", G_CALLBACK (page_changed_cb), view);
-       view->pixbuf_cache = ev_pixbuf_cache_new (view->document);
+       view->pixbuf_cache = ev_pixbuf_cache_new (GTK_WIDGET (view), view->document);
        g_signal_connect (view->pixbuf_cache, "job-finished", G_CALLBACK (job_finished_cb), view);
 }
 
@@ -2018,8 +2153,9 @@ clear_caches (EvView *view)
                view->pixbuf_cache = NULL;
        }
 
-       if (view->document) {
-               ev_page_cache_clear (view->document);
+       if (view->page_cache) {
+               g_object_unref (view->page_cache);
+               view->page_cache = NULL;
        }
 }
 
@@ -2095,6 +2231,14 @@ ev_view_get_zoom (EvView *view)
        return view->scale;
 }
 
+gboolean
+ev_view_get_continuous (EvView *view)
+{
+       g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
+
+       return view->continuous;
+}
+
 void
 ev_view_set_continuous (EvView   *view,
                        gboolean  continuous)
@@ -2112,6 +2256,14 @@ ev_view_set_continuous (EvView   *view,
        g_object_notify (G_OBJECT (view), "continuous");
 }
 
+gboolean
+ev_view_get_dual_page (EvView *view)
+{
+       g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
+
+       return view->dual_page;
+}
+
 void
 ev_view_set_dual_page (EvView   *view,
                       gboolean  dual_page)
@@ -2247,52 +2399,45 @@ ev_view_zoom_out (EvView *view)
        ev_view_set_zoom (view, ZOOM_OUT_FACTOR, TRUE);
 }
 
-static void
-ev_view_set_orientation (EvView         *view,
-                        EvOrientation   orientation)
+void
+ev_view_rotate_right (EvView *view)
 {
-       ev_document_set_orientation (view->document, orientation);
+       int rotation = view->rotation + 90;
 
-       clear_caches (view);
-       setup_caches (view);
+       if (rotation >= 360) {
+               rotation -= 360;
+       }
 
-       gtk_widget_queue_resize (GTK_WIDGET (view));
+       ev_view_set_rotation (view, rotation);
 }
 
 void
-ev_view_rotate_right (EvView *view)
+ev_view_rotate_left (EvView *view)
 {
-       EvOrientation orientation, new_orientation;
+       int rotation = view->rotation - 90;
 
-       orientation = ev_document_get_orientation (view->document);
-       if (orientation == EV_ORIENTATION_PORTRAIT) {
-               new_orientation = EV_ORIENTATION_LANDSCAPE;
-       } else if (orientation == EV_ORIENTATION_LANDSCAPE) {
-               new_orientation = EV_ORIENTATION_UPSIDEDOWN;
-       } else if (orientation == EV_ORIENTATION_UPSIDEDOWN) {
-               new_orientation = EV_ORIENTATION_SEASCAPE;
-       } else {
-               new_orientation = EV_ORIENTATION_PORTRAIT;
+       if (rotation < 0) {
+               rotation += 360;
        }
-       ev_view_set_orientation (view, new_orientation);
+
+       ev_view_set_rotation (view, rotation);
 }
 
 void
-ev_view_rotate_left (EvView *view)
+ev_view_set_rotation (EvView *view, int rotation)
 {
-       EvOrientation orientation, new_orientation;
+       view->rotation = rotation;
 
-       orientation = ev_document_get_orientation (view->document);
-       if (orientation == EV_ORIENTATION_PORTRAIT) {
-               new_orientation = EV_ORIENTATION_SEASCAPE;
-       } else if (orientation == EV_ORIENTATION_SEASCAPE) {
-               new_orientation = EV_ORIENTATION_UPSIDEDOWN;
-       } else if (orientation == EV_ORIENTATION_UPSIDEDOWN) {
-               new_orientation = EV_ORIENTATION_LANDSCAPE;
-       } else {
-               new_orientation = EV_ORIENTATION_PORTRAIT;
+       if (view->pixbuf_cache) {
+               ev_pixbuf_cache_clear (view->pixbuf_cache);
+               gtk_widget_queue_resize (GTK_WIDGET (view));
        }
-       ev_view_set_orientation (view, new_orientation);
+}
+
+int
+ev_view_get_rotation (EvView *view)
+{
+       return view->rotation;
 }
 
 static double
@@ -2345,6 +2490,7 @@ ev_view_zoom_for_size_presentation (EvView *view,
 
        ev_page_cache_get_size (view->page_cache,
                                view->current_page,
+                               view->rotation,
                                1.0,
                                &doc_width,
                                &doc_height);
@@ -2364,9 +2510,11 @@ ev_view_zoom_for_size_continuous_and_dual_page (EvView *view,
        gdouble scale;
 
        ev_page_cache_get_max_width (view->page_cache,
+                                    view->rotation,
                                     1.0,
                                     &doc_width);
        ev_page_cache_get_max_height (view->page_cache,
+                                     view->rotation,
                                      1.0,
                                      &doc_height);
        compute_border (view, doc_width, doc_height, &border);
@@ -2400,9 +2548,11 @@ ev_view_zoom_for_size_continuous (EvView *view,
        gdouble scale;
 
        ev_page_cache_get_max_width (view->page_cache,
+                                    view->rotation,
                                     1.0,
                                     &doc_width);
        ev_page_cache_get_max_height (view->page_cache,
+                                     view->rotation,
                                      1.0,
                                      &doc_height);
        compute_border (view, doc_width, doc_height, &border);
@@ -2440,6 +2590,7 @@ ev_view_zoom_for_size_dual_page (EvView *view,
        /* Find the largest of the two. */
        ev_page_cache_get_size (view->page_cache,
                                view->current_page,
+                               view->rotation,
                                1.0,
                                &doc_width, &doc_height);
 
@@ -2447,6 +2598,7 @@ ev_view_zoom_for_size_dual_page (EvView *view,
                gint width_2, height_2;
                ev_page_cache_get_size (view->page_cache,
                                        other_page,
+                                       view->rotation,
                                        1.0,
                                        &width_2, &height_2);
                if (width_2 > doc_width)
@@ -2483,6 +2635,7 @@ ev_view_zoom_for_size_single_page (EvView *view,
 
        ev_page_cache_get_size (view->page_cache,
                                view->current_page,
+                               view->rotation,
                                1.0,
                                &doc_width,
                                &doc_height);
@@ -2617,7 +2770,7 @@ jump_to_find_result (EvView *view)
 
        n_results = ev_document_find_get_n_results (find, page);
 
-       if (n_results > view->find_result) {
+       if (n_results > 0  && view->find_result < n_results) {
                ev_document_find_get_result
                        (find, page, view->find_result, &rect);
 
@@ -2627,7 +2780,7 @@ jump_to_find_result (EvView *view)
 }
 
 static void
-jump_to_find_page (EvView *view)
+jump_to_find_page (EvView *view, EvViewFindDirection direction)
 {
        int n_pages, i;
 
@@ -2636,12 +2789,19 @@ jump_to_find_page (EvView *view)
        for (i = 0; i < n_pages; i++) {
                int has_results;
                int page;
+               
+               if (direction == EV_VIEW_FIND_NEXT)
+                       page = view->find_page + i;
+               else
+                       page = view->find_page - i;
+
 
-               page = i + view->find_page;
                if (page >= n_pages) {
                        page = page - n_pages;
                }
-
+               if (page < 0) 
+                       page = page + n_pages;
+               
                has_results = ev_document_find_page_has_results
                                (EV_DOCUMENT_FIND (view->document), page);
                if (has_results == -1) {
@@ -2649,7 +2809,6 @@ jump_to_find_page (EvView *view)
                        break;
                } else if (has_results == 1) {
                        ev_page_cache_set_current_page (view->page_cache, page);
-                       jump_to_find_result (view);
                        break;
                }
        }
@@ -2672,26 +2831,25 @@ ev_view_can_find_next (EvView *view)
 void
 ev_view_find_next (EvView *view)
 {
-       EvPageCache *page_cache;
        int n_results, n_pages;
        EvDocumentFind *find = EV_DOCUMENT_FIND (view->document);
 
-       page_cache = ev_page_cache_get (view->document);
        n_results = ev_document_find_get_n_results (find, view->current_page);
 
-       n_pages = ev_page_cache_get_n_pages (page_cache);
+       n_pages = ev_page_cache_get_n_pages (view->page_cache);
 
        view->find_result++;
 
        if (view->find_result >= n_results) {
+
                view->find_result = 0;
                view->find_page++;
-
                if (view->find_page >= n_pages) {
                        view->find_page = 0;
                }
 
-               jump_to_find_page (view);
+               jump_to_find_page (view, EV_VIEW_FIND_NEXT);
+               jump_to_find_result (view);
        } else {
                jump_to_find_result (view);
                gtk_widget_queue_draw (GTK_WIDGET (view));
@@ -2714,14 +2872,15 @@ ev_view_find_previous (EvView *view)
        view->find_result--;
 
        if (view->find_result < 0) {
-               view->find_result = 0;
-               view->find_page--;
 
+               view->find_page--;
                if (view->find_page < 0) {
                        view->find_page = n_pages - 1;
                }
 
-               jump_to_find_page (view);
+               jump_to_find_page (view, EV_VIEW_FIND_PREV);
+               view->find_result = ev_document_find_get_n_results (find, view->current_page) - 1;
+               jump_to_find_result (view);
        } else {
                jump_to_find_result (view);
                gtk_widget_queue_draw (GTK_WIDGET (view));
@@ -2827,6 +2986,7 @@ compute_new_selection_text (EvView   *view,
                GdkPoint *point;
 
                ev_page_cache_get_size (view->page_cache, i,
+                                       view->rotation,
                                        1.0, &width, &height);
 
                selection = g_new0 (EvViewSelection, 1);
@@ -2869,15 +3029,114 @@ compute_new_selection_text (EvView   *view,
  */
 static void
 merge_selection_region (EvView *view,
-                       GList  *list)
+                       GList  *new_list)
 {
+       GList *old_list;
+       GList *new_list_ptr, *old_list_ptr;
 
-       /* FIXME: actually write... */
-       clear_selection (view);
-       gtk_widget_queue_draw (GTK_WIDGET (view));
+       /* Update the selection */
+       old_list = ev_pixbuf_cache_get_selection_list (view->pixbuf_cache);
+       g_list_foreach (view->selection_info.selections, (GFunc)selection_free, NULL);
+       view->selection_info.selections = new_list;
+       ev_pixbuf_cache_set_selection_list (view->pixbuf_cache, new_list);
+
+       new_list_ptr = new_list;
+       old_list_ptr = old_list;
+
+       while (new_list_ptr || old_list_ptr) {
+               EvViewSelection *old_sel, *new_sel;
+               int cur_page;
+               GdkRegion *region = NULL;
+
+               new_sel = (new_list_ptr) ? (new_list_ptr->data) : NULL;
+               old_sel = (old_list_ptr) ? (old_list_ptr->data) : NULL;
+
+               /* Assume that the lists are in order, and we run through them
+                * comparing them, one page at a time.  We come out with the
+                * first page we see. */
+               if (new_sel && old_sel) {
+                       if (new_sel->page < old_sel->page) {
+                               new_list_ptr = new_list_ptr->next;
+                               old_sel = NULL;
+                       } else if (new_sel->page > old_sel->page) {
+                               old_list_ptr = old_list_ptr->next;
+                               new_sel = NULL;
+                       } else {
+                               new_list_ptr = new_list_ptr->next;
+                               old_list_ptr = old_list_ptr->next;
+                       }
+               } else if (new_sel) {
+                       new_list_ptr = new_list_ptr->next;
+               } else if (old_sel) {
+                       old_list_ptr = old_list_ptr->next;
+               }
 
-       view->selection_info.selections = list;
-       ev_pixbuf_cache_set_selection_list (view->pixbuf_cache, list);
+               g_assert (new_sel || old_sel);
+
+               /* is the page we're looking at on the screen?*/
+               cur_page = new_sel ? new_sel->page : old_sel->page;
+               if (cur_page < view->start_page || cur_page > view->end_page)
+                       continue;
+
+               /* seed the cache with a new page.  We are going to need the new
+                * region too. */
+               if (new_sel) {
+                       GdkRegion *tmp_region = NULL;
+                       ev_pixbuf_cache_get_selection_pixbuf (view->pixbuf_cache,
+                                                             cur_page,
+                                                             view->scale,
+                                                             &tmp_region);
+                       if (tmp_region) {
+                               new_sel->covered_region = gdk_region_copy (tmp_region);
+                       }
+               }
+
+               /* Now we figure out what needs redrawing */
+               if (old_sel && new_sel) {
+                       if (old_sel->covered_region &&
+                           new_sel->covered_region) {
+                               /* We only want to redraw the areas that have
+                                * changed, so we xor the old and new regions
+                                * and redraw if it's different */
+                               region = gdk_region_copy (old_sel->covered_region);
+                               gdk_region_xor (region, new_sel->covered_region);
+                               if (gdk_region_empty (region)) {
+                                       gdk_region_destroy (region);
+                                       region = NULL;
+                               }
+                       } else if (old_sel->covered_region) {
+                               region = gdk_region_copy (old_sel->covered_region);
+                       } else if (new_sel->covered_region) {
+                               region = gdk_region_copy (new_sel->covered_region);
+                       }
+               } else if (old_sel && !new_sel) {
+                       if (old_sel->covered_region && !gdk_region_empty (old_sel->covered_region)) {
+                               region = gdk_region_copy (old_sel->covered_region);
+                       }
+               } else if (!old_sel && new_sel) {
+                       if (new_sel->covered_region && !gdk_region_empty (new_sel->covered_region)) {
+                               region = gdk_region_copy (new_sel->covered_region);
+                       }
+               } else {
+                       g_assert_not_reached ();
+               }
+
+               /* Redraw the damaged region! */
+               if (region) {
+                       GdkRectangle page_area;
+                       GtkBorder border;
+
+                       get_page_extents (view, cur_page, &page_area, &border);
+                       gdk_region_offset (region,
+                                          page_area.x + border.left - view->scroll_x,
+                                          page_area.y + border.top - view->scroll_y);
+                       gdk_window_invalidate_region (GTK_WIDGET (view)->window, region, TRUE);
+                       gdk_region_destroy (region);
+               }
+       }
+
+       /* Free the old list, now that we're done with it. */
+       g_list_foreach (old_list, (GFunc) selection_free, NULL);
 }
 
 static void
@@ -2899,6 +3158,8 @@ compute_selections (EvView   *view,
 static void
 selection_free (EvViewSelection *selection)
 {
+       if (selection->covered_region)
+               gdk_region_destroy (selection->covered_region);
        g_free (selection);
 }
 
@@ -2924,7 +3185,9 @@ ev_view_select_all (EvView *view)
                EvViewSelection *selection;
 
                ev_page_cache_get_size (view->page_cache,
-                                       i, 1.0, &width, &height);
+                                       i,
+                                       view->rotation,
+                                       1.0, &width, &height);
 
                selection = g_new0 (EvViewSelection, 1);
                selection->page = i;