]> www.fi.muni.cz Git - evince.git/blob - shell/ev-view.c
c5cc5038a7e1018e2126536241960ebfa21a0cf7
[evince.git] / shell / ev-view.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /* this file is part of evince, a gnome document viewer
3  *
4  *  Copyright (C) 2004 Red Hat, Inc
5  *
6  * Evince is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Evince is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 #include <math.h>
22 #include <gtk/gtkalignment.h>
23 #include <glib/gi18n.h>
24 #include <gtk/gtkbindings.h>
25 #include <gtk/gtkselection.h>
26 #include <gtk/gtkclipboard.h>
27 #include <gdk/gdkkeysyms.h>
28 #include <libgnomevfs/gnome-vfs-utils.h>
29
30 #include "ev-marshal.h"
31 #include "ev-view.h"
32 #include "ev-utils.h"
33 #include "ev-selection.h"
34 #include "ev-document-find.h"
35 #include "ev-document-misc.h"
36 #include "ev-debug.h"
37 #include "ev-job-queue.h"
38 #include "ev-page-cache.h"
39 #include "ev-pixbuf-cache.h"
40 #include "ev-tooltip.h"
41
42 #define EV_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_VIEW, EvViewClass))
43 #define EV_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_VIEW))
44 #define EV_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_VIEW, EvViewClass))
45
46
47 enum {
48         PROP_0,
49         PROP_STATUS,
50         PROP_FIND_STATUS,
51         PROP_CONTINUOUS,
52         PROP_DUAL_PAGE,
53         PROP_FULLSCREEN,
54         PROP_PRESENTATION,
55         PROP_SIZING_MODE,
56         PROP_ZOOM,
57         PROP_ROTATION,
58 };
59
60 enum {
61         SIGNAL_BINDING_ACTIVATED,
62         SIGNAL_ZOOM_INVALID,
63         N_SIGNALS,
64 };
65
66 enum {
67         TARGET_STRING,
68         TARGET_TEXT,
69         TARGET_COMPOUND_TEXT,
70         TARGET_UTF8_STRING,
71         TARGET_TEXT_BUFFER_CONTENTS
72 };
73
74 static const GtkTargetEntry targets[] = {
75         { "STRING", 0, TARGET_STRING },
76         { "TEXT",   0, TARGET_TEXT },
77         { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
78         { "UTF8_STRING", 0, TARGET_UTF8_STRING },
79 };
80
81 static guint signals[N_SIGNALS];
82
83 typedef enum {
84         EV_VIEW_CURSOR_NORMAL,
85         EV_VIEW_CURSOR_IBEAM,
86         EV_VIEW_CURSOR_LINK,
87         EV_VIEW_CURSOR_WAIT,
88         EV_VIEW_CURSOR_HIDDEN,
89         EV_VIEW_CURSOR_DRAG
90 } EvViewCursor;
91
92 typedef enum {
93         EV_VIEW_FIND_NEXT,
94         EV_VIEW_FIND_PREV
95 } EvViewFindDirection;
96
97 #define ZOOM_IN_FACTOR  1.2
98 #define ZOOM_OUT_FACTOR (1.0/ZOOM_IN_FACTOR)
99
100 #define MIN_SCALE 0.05409
101 #define MAX_SCALE 4.0
102
103 /* Information for middle clicking and moving around the doc */
104 typedef struct {
105         gboolean in_drag;
106         GdkPoint start;
107         gdouble hadj;
108         gdouble vadj;
109 } DragInfo;
110
111 /* Information for handling selection */
112 typedef struct {
113         gboolean in_selection;
114         GdkPoint start;
115         GList *selections;
116 } SelectionInfo;
117
118 typedef enum {
119         SCROLL_TO_KEEP_POSITION,
120         SCROLL_TO_CURRENT_PAGE,
121         SCROLL_TO_CENTER
122 } PendingScroll;
123
124 struct _EvView {
125         GtkWidget parent_instance;
126
127         EvDocument *document;
128
129         char *status;
130         char *find_status;
131
132         /* Scrolling */
133         GtkAdjustment *hadjustment;
134         GtkAdjustment *vadjustment;
135
136         gint scroll_x;
137         gint scroll_y;
138
139         /* Information for middle clicking and dragging around. */
140         DragInfo drag_info;
141
142         /* Selection */
143         gint motion_x;
144         gint motion_y;
145         guint selection_update_id;
146
147         EvViewSelectionMode selection_mode;
148         SelectionInfo selection_info;
149
150         int pressed_button;
151         EvViewCursor cursor;
152         GtkWidget *link_tooltip;
153         EvLink *hovered_link;
154
155         EvPageCache *page_cache;
156         EvPixbufCache *pixbuf_cache;
157
158         gint start_page;
159         gint end_page;
160         gint current_page;
161
162         EvJobRender *current_job;
163
164         int find_page;
165         int find_result;
166         int spacing;
167
168         int rotation;
169         double scale;
170
171         gboolean continuous;
172         gboolean dual_page;
173         gboolean fullscreen;
174         gboolean presentation;
175         EvSizingMode sizing_mode;
176
177         PendingScroll pending_scroll;
178         gboolean pending_resize;
179 };
180
181 struct _EvViewClass {
182         GtkWidgetClass parent_class;
183
184         void    (*set_scroll_adjustments) (EvView         *view,
185                                            GtkAdjustment  *hadjustment,
186                                            GtkAdjustment  *vadjustment);
187         void    (*binding_activated)      (EvView         *view,
188                                            GtkScrollType   scroll,
189                                            gboolean        horizontal);
190         void    (*zoom_invalid)           (EvView         *view);
191 };
192
193 /*** Scrolling ***/
194 static void       scroll_to_current_page                     (EvView *view,
195                                                               GtkOrientation orientation);
196 static void       ev_view_set_scroll_adjustments             (EvView             *view,
197                                                               GtkAdjustment      *hadjustment,
198                                                               GtkAdjustment      *vadjustment);
199 static void       view_update_range_and_current_page         (EvView             *view);
200 static void       set_scroll_adjustment                      (EvView             *view,
201                                                               GtkOrientation      orientation,
202                                                               GtkAdjustment      *adjustment);
203 static void       ev_view_set_scroll_adjustments             (EvView             *view,
204                                                               GtkAdjustment      *hadjustment,
205                                                               GtkAdjustment      *vadjustment);
206 static void       add_scroll_binding_keypad                  (GtkBindingSet      *binding_set,
207                                                               guint               keyval,
208                                                               GtkScrollType       scroll,
209                                                               gboolean            horizontal);
210 static void       ev_view_binding_activated                  (EvView             *view,
211                                                               GtkScrollType       scroll,
212                                                               gboolean            horizontal);
213 static void       ensure_rectangle_is_visible                (EvView             *view,
214                                                               GdkRectangle       *rect);
215
216 /*** Geometry computations ***/
217 static void       compute_border                             (EvView             *view,
218                                                               int                 width,
219                                                               int                 height,
220                                                               GtkBorder          *border);
221 static void       get_page_y_offset                          (EvView *view,
222                                                               int page,
223                                                               double zoom,
224                                                               int *y_offset);
225 static gboolean   get_page_extents                           (EvView             *view,
226                                                               gint                page,
227                                                               GdkRectangle       *page_area,
228                                                               GtkBorder          *border);
229 static void       view_rect_to_doc_rect                      (EvView             *view,
230                                                               GdkRectangle       *view_rect,
231                                                               GdkRectangle       *page_area,
232                                                               EvRectangle        *doc_rect);
233 static void       doc_rect_to_view_rect                      (EvView             *view,
234                                                               int                 page,
235                                                               EvRectangle        *doc_rect,
236                                                               GdkRectangle       *view_rect);
237 static void       find_page_at_location                      (EvView             *view,
238                                                               gdouble             x,
239                                                               gdouble             y,
240                                                               gint               *page,
241                                                               gint               *x_offset,
242                                                               gint               *y_offset);
243
244 /*** Hyperrefs ***/
245 static EvLink*    get_link_at_location                       (EvView             *view,
246                                                               gdouble             x,
247                                                               gdouble             y);
248 static char*      tip_from_link                              (EvView             *view,
249                                                               EvLink             *link);
250 static void       handle_link_over_xy                        (EvView *view, 
251                                                               gint x, 
252                                                               gint y);
253 /*** GtkWidget implementation ***/
254 static void       ev_view_size_request_continuous_dual_page  (EvView             *view,
255                                                               GtkRequisition     *requisition);
256 static void       ev_view_size_request_continuous            (EvView             *view,
257                                                               GtkRequisition     *requisition);
258 static void       ev_view_size_request_dual_page             (EvView             *view,
259                                                               GtkRequisition     *requisition);
260 static void       ev_view_size_request_single_page           (EvView             *view,
261                                                               GtkRequisition     *requisition);
262 static void       ev_view_size_request                       (GtkWidget          *widget,
263                                                               GtkRequisition     *requisition);
264 static void       ev_view_size_allocate                      (GtkWidget          *widget,
265                                                               GtkAllocation      *allocation);
266 static void       ev_view_realize                            (GtkWidget          *widget);
267 static gboolean   ev_view_scroll_event                       (GtkWidget          *widget,
268                                                               GdkEventScroll     *event);
269 static gboolean   ev_view_expose_event                       (GtkWidget          *widget,
270                                                               GdkEventExpose     *event);
271 static gboolean   ev_view_button_press_event                 (GtkWidget          *widget,
272                                                               GdkEventButton     *event);
273 static gboolean   ev_view_motion_notify_event                (GtkWidget          *widget,
274                                                               GdkEventMotion     *event);
275 static gboolean   ev_view_button_release_event               (GtkWidget          *widget,
276                                                               GdkEventButton     *event);
277 static gboolean   ev_view_enter_notify_event                 (GtkWidget          *widget,
278                                                               GdkEventCrossing   *event);
279 static gboolean   ev_view_leave_notify_event                 (GtkWidget          *widget,
280                                                               GdkEventCrossing   *event);
281 static void       ev_view_style_set                          (GtkWidget          *widget,
282                                                               GtkStyle           *old_style);
283
284 /*** Drawing ***/
285 static guint32    ev_gdk_color_to_rgb                        (const GdkColor     *color);
286 static void       draw_rubberband                            (GtkWidget          *widget,
287                                                               GdkWindow          *window,
288                                                               const GdkRectangle *rect,
289                                                               guchar              alpha);
290 static void       highlight_find_results                     (EvView             *view,
291                                                               int                 page);
292 static void       draw_one_page                              (EvView             *view,
293                                                               gint                page,
294                                                               GdkRectangle       *page_area,
295                                                               GtkBorder          *border,
296                                                               GdkRectangle       *expose_area);
297
298 /*** Callbacks ***/
299 static void       find_changed_cb                            (EvDocument         *document,
300                                                               int                 page,
301                                                               EvView             *view);
302 static void       job_finished_cb                            (EvPixbufCache      *pixbuf_cache,
303                                                               EvView             *view);
304 static void       page_changed_cb                            (EvPageCache        *page_cache,
305                                                               int                 new_page,
306                                                               EvView             *view);
307 static void       on_adjustment_value_changed                (GtkAdjustment      *adjustment,
308                                                               EvView             *view);
309
310 /*** GObject ***/
311 static void       ev_view_finalize                           (GObject            *object);
312 static void       ev_view_destroy                            (GtkObject          *object);
313 static void       ev_view_set_property                       (GObject            *object,
314                                                               guint               prop_id,
315                                                               const GValue       *value,
316                                                               GParamSpec         *pspec);
317 static void       ev_view_get_property                       (GObject            *object,
318                                                               guint               prop_id,
319                                                               GValue             *value,
320                                                               GParamSpec         *pspec);
321 static void       ev_view_class_init                         (EvViewClass        *class);
322 static void       ev_view_init                               (EvView             *view);
323
324 /*** Zoom and sizing ***/
325 static double   zoom_for_size_fit_width                      (int doc_width,
326                                                               int doc_height,
327                                                               int target_width,
328                                                               int target_height,
329                                                               int vsb_width);
330 static double   zoom_for_size_fit_height                     (int doc_width,
331                                                               int doc_height,
332                                                               int target_width,
333                                                               int target_height,
334                                                               int vsb_height);
335 static double   zoom_for_size_best_fit                       (int doc_width,
336                                                               int doc_height,
337                                                               int target_width,
338                                                               int target_height,
339                                                               int vsb_width,
340                                                               int hsb_width);
341 static void     ev_view_zoom_for_size_presentation           (EvView *view,
342                                                               int     width,
343                                                               int     height);
344 static void     ev_view_zoom_for_size_continuous_and_dual_page (EvView *view,
345                                                                 int     width,
346                                                                 int     height,
347                                                                 int     vsb_width,
348                                                                 int     hsb_height);
349 static void     ev_view_zoom_for_size_continuous               (EvView *view,
350                                                                 int     width,
351                                                                 int     height,
352                                                                 int     vsb_width,
353                                                                 int     hsb_height);
354 static void     ev_view_zoom_for_size_dual_page                (EvView *view,
355                                                                 int     width,
356                                                                 int     height,
357                                                                 int     vsb_width,
358                                                                 int     hsb_height);
359 static void     ev_view_zoom_for_size_single_page              (EvView *view,
360                                                                 int     width,
361                                                                 int     height,
362                                                                 int     vsb_width,
363                                                                 int     hsb_height);
364 /*** Cursors ***/
365 static GdkCursor* ev_view_create_invisible_cursor            (void);
366 static void       ev_view_set_cursor                         (EvView             *view,
367                                                               EvViewCursor        new_cursor);
368
369 /*** Status messages ***/
370 static void       ev_view_set_status                         (EvView             *view,
371                                                               const char         *message);
372 static void       update_find_status_message                 (EvView             *view);
373 static void       ev_view_set_find_status                    (EvView             *view,
374                                                               const char         *message);
375 /*** Find ***/
376 static void       jump_to_find_result                        (EvView             *view);
377 static void       jump_to_find_page                          (EvView             *view, 
378                                                               EvViewFindDirection direction);
379
380 /*** Selection ***/
381 static void       compute_selections                         (EvView             *view,
382                                                               GdkPoint           *start,
383                                                               GdkPoint           *stop);
384 static void       clear_selection                            (EvView             *view);
385 static void       selection_free                             (EvViewSelection    *selection);
386 static char*      get_selected_text                          (EvView             *ev_view);
387 static void       ev_view_primary_get_cb                     (GtkClipboard       *clipboard,
388                                                               GtkSelectionData   *selection_data,
389                                                               guint               info,
390                                                               gpointer            data);
391 static void       ev_view_primary_clear_cb                   (GtkClipboard       *clipboard,
392                                                               gpointer            data);
393 static void       ev_view_update_primary_selection           (EvView             *ev_view);
394
395
396 G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_WIDGET)
397
398 static void
399 scroll_to_current_page (EvView *view, GtkOrientation orientation)
400 {
401         GdkRectangle page_area;
402         GtkBorder border;
403
404         if (view->document == NULL) {
405                 return;
406         }
407
408         get_page_extents (view, view->current_page, &page_area, &border);
409
410         if (orientation == GTK_ORIENTATION_VERTICAL) {
411                 if (view->continuous) {
412                         gtk_adjustment_clamp_page (view->vadjustment,
413                                                    page_area.y - view->spacing,
414                                                    page_area.y + view->vadjustment->page_size);
415                 } else {
416                         gtk_adjustment_set_value (view->vadjustment,
417                                                   view->vadjustment->lower);
418                 }
419         } else {
420                 if (view->dual_page) {
421                         gtk_adjustment_clamp_page (view->hadjustment,
422                                                    page_area.x,
423                                                    page_area.x + view->hadjustment->page_size);
424                 } else {
425                         gtk_adjustment_set_value (view->hadjustment,
426                                                   CLAMP (view->hadjustment->value,
427                                                   view->hadjustment->lower,
428                                                   view->hadjustment->upper -
429                                                   view->hadjustment->page_size));
430                 }
431         }
432 }
433
434 static void
435 view_set_adjustment_values (EvView         *view,
436                             GtkOrientation  orientation)
437 {
438         GtkWidget *widget = GTK_WIDGET (view);
439         GtkAdjustment *adjustment;
440         int requisition;
441         int allocation;
442
443         double factor;
444         gint new_value;
445
446         if (orientation == GTK_ORIENTATION_HORIZONTAL)  {
447                 requisition = widget->requisition.width;
448                 allocation = widget->allocation.width;
449                 adjustment = view->hadjustment;
450         } else {
451                 requisition = widget->requisition.height;
452                 allocation = widget->allocation.height;
453                 adjustment = view->vadjustment;
454         }
455
456         if (!adjustment)
457                 return;
458
459         factor = 1.0;
460         switch (view->pending_scroll) {
461                 case SCROLL_TO_KEEP_POSITION:
462                         factor = (adjustment->value) / adjustment->upper;
463                         break;
464                 case SCROLL_TO_CURRENT_PAGE:
465                         break;
466                 case SCROLL_TO_CENTER:
467                         factor = (adjustment->value + adjustment->page_size * 0.5) / adjustment->upper;
468                         break;
469         }
470
471         adjustment->page_size = allocation;
472         adjustment->step_increment = allocation * 0.1;
473         adjustment->page_increment = allocation * 0.9;
474         adjustment->lower = 0;
475         adjustment->upper = MAX (allocation, requisition);
476
477         /*
478          * We add 0.5 to the values before to average out our rounding errors.
479          */
480         switch (view->pending_scroll) {
481                 case SCROLL_TO_KEEP_POSITION:
482                         new_value = CLAMP (adjustment->upper * factor + 0.5, 0, adjustment->upper - adjustment->page_size);
483                         gtk_adjustment_set_value (adjustment, (int)new_value);
484                         break;
485                 case SCROLL_TO_CURRENT_PAGE:
486                         scroll_to_current_page (view, orientation);
487                         break;
488                 case SCROLL_TO_CENTER:
489                         new_value = CLAMP (adjustment->upper * factor - adjustment->page_size * 0.5 + 0.5,
490                                            0, adjustment->upper - adjustment->page_size);
491                         gtk_adjustment_set_value (adjustment, (int)new_value);
492                         break;
493         }
494
495         gtk_adjustment_changed (adjustment);
496 }
497
498 static void
499 view_update_range_and_current_page (EvView *view)
500 {
501         if (view->pending_scroll != SCROLL_TO_KEEP_POSITION)
502                 return;
503
504         /* Presentation trumps all other modes */
505         if (view->presentation) {
506                 view->start_page = view->current_page;
507                 view->end_page = view->current_page;
508         } else if (view->continuous) {
509                 GdkRectangle current_area, unused, page_area;
510                 GtkBorder border;
511                 gint current_page;
512                 gboolean found = FALSE;
513                 int i;
514
515                 if (!(view->vadjustment && view->hadjustment))
516                         return;
517
518                 current_area.x = view->hadjustment->value;
519                 current_area.width = view->hadjustment->upper;
520                 current_area.y = view->vadjustment->value;
521                 current_area.height = view->vadjustment->page_size;
522
523                 for (i = 0; i < ev_page_cache_get_n_pages (view->page_cache); i++) {
524
525                         get_page_extents (view, i, &page_area, &border);
526
527                         if (gdk_rectangle_intersect (&current_area, &page_area, &unused)) {
528                                 if (! found) {
529                                         view->start_page = i;
530                                         found = TRUE;
531
532                                 }
533                                 view->end_page = i;
534                         } else if (found) {
535                                 break;
536                         }
537                 }
538
539                 current_page = ev_page_cache_get_current_page (view->page_cache);
540
541                 if (current_page < view->start_page || current_page > view->end_page) {
542                         view->current_page = view->start_page;
543                         ev_page_cache_set_current_page (view->page_cache, view->start_page);
544                 }
545         } else {
546                 if (view->dual_page) {
547                         if (view->current_page % 2 == 0) {
548                                 view->start_page = view->current_page;
549                                 if (view->current_page + 1 < ev_page_cache_get_n_pages (view->page_cache))
550                                         view->end_page = view->start_page + 1;
551                                 else 
552                                         view->end_page = view->start_page;
553                         } else {
554                                 view->start_page = view->current_page - 1;
555                                 view->end_page = view->current_page;
556                         }
557                 } else {
558                         view->start_page = view->current_page;
559                         view->end_page = view->current_page;
560                 }
561         }
562
563         ev_pixbuf_cache_set_page_range (view->pixbuf_cache,
564                                         view->start_page,
565                                         view->end_page,
566                                         view->rotation,
567                                         view->scale,
568                                         view->selection_info.selections);
569 }
570
571 static void
572 set_scroll_adjustment (EvView *view,
573                        GtkOrientation  orientation,
574                        GtkAdjustment  *adjustment)
575 {
576         GtkAdjustment **to_set;
577
578         if (orientation == GTK_ORIENTATION_HORIZONTAL)
579                 to_set = &view->hadjustment;
580         else
581                 to_set = &view->vadjustment;
582
583         if (*to_set != adjustment) {
584                 if (*to_set) {
585                         g_signal_handlers_disconnect_by_func (*to_set,
586                                                               (gpointer) on_adjustment_value_changed,
587                                                               view);
588                         g_object_unref (*to_set);
589                 }
590
591                 *to_set = adjustment;
592                 view_set_adjustment_values (view, orientation);
593
594                 if (*to_set) {
595                         g_object_ref (*to_set);
596                         g_signal_connect (*to_set, "value_changed",
597                                           G_CALLBACK (on_adjustment_value_changed), view);
598                 }
599         }
600 }
601
602 static void
603 ev_view_set_scroll_adjustments (EvView *view,
604                                 GtkAdjustment  *hadjustment,
605                                 GtkAdjustment  *vadjustment)
606 {
607         set_scroll_adjustment (view, GTK_ORIENTATION_HORIZONTAL, hadjustment);
608         set_scroll_adjustment (view, GTK_ORIENTATION_VERTICAL, vadjustment);
609
610         on_adjustment_value_changed (NULL, view);
611 }
612
613 static void
614 add_scroll_binding_keypad (GtkBindingSet  *binding_set,
615                            guint           keyval,
616                            GtkScrollType   scroll,
617                            gboolean        horizontal)
618 {
619   guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
620
621   gtk_binding_entry_add_signal (binding_set, keyval, 0,
622                                 "binding_activated", 2,
623                                 GTK_TYPE_SCROLL_TYPE, scroll,
624                                 G_TYPE_BOOLEAN, horizontal);
625   gtk_binding_entry_add_signal (binding_set, keypad_keyval, 0,
626                                 "binding_activated", 2,
627                                 GTK_TYPE_SCROLL_TYPE, scroll,
628                                 G_TYPE_BOOLEAN, horizontal);
629 }
630
631 void
632 ev_view_scroll (EvView        *view,
633                 EvScrollType   scroll)
634 {
635         GtkAdjustment *adjustment;
636         double value, increment;
637         gboolean first_page = FALSE;
638         gboolean last_page = FALSE;
639
640         /* Assign values for increment and vertical adjustment */
641         adjustment = view->vadjustment;
642         increment = adjustment->page_size * 0.75;
643         value = adjustment->value;
644
645         /* Assign boolean for first and last page */
646         if (view->current_page == 0)
647                 first_page = TRUE;
648         if (view->current_page == ev_page_cache_get_n_pages (view->page_cache) - 1)
649                 last_page = TRUE;
650
651         switch (scroll) {
652                 case EV_SCROLL_PAGE_BACKWARD:
653                         /* Do not jump backwards if at the first page */
654                         if (value == (adjustment->lower) && first_page) {
655                                 /* Do nothing */
656                                 /* At the top of a page, assign the upper bound limit of previous page */
657                         } else if (value == (adjustment->lower)) {
658                                 value = adjustment->upper - adjustment->page_size;
659                                 ev_page_cache_set_current_page (view->page_cache, view->current_page - 1);
660                                 /* Jump to the top */
661                         } else {
662                                 value = MAX (value - increment, adjustment->lower);
663                         }
664                         break;
665                 case EV_SCROLL_PAGE_FORWARD:
666                         /* Do not jump forward if at the last page */
667                         if (value == (adjustment->upper - adjustment->page_size) && last_page) {
668                                 /* Do nothing */
669                         /* At the bottom of a page, assign the lower bound limit of next page */
670                         } else if (value == (adjustment->upper - adjustment->page_size)) {
671                                 value = 0;
672                                 ev_page_cache_set_current_page (view->page_cache, view->current_page + 1);
673                         /* Jump to the bottom */
674                         } else {
675                                 value = MIN (value + increment, adjustment->upper - adjustment->page_size);
676                         }
677                         break;
678                 default:
679                         break;
680         }
681
682         gtk_adjustment_set_value (adjustment, value);
683 }
684
685 static void
686 ev_view_binding_activated (EvView *view,
687                            GtkScrollType scroll,
688                            gboolean horizontal)
689 {
690         GtkAdjustment *adjustment;
691         double value;
692
693         if (view->presentation) {
694                 switch (scroll) {
695                         case GTK_SCROLL_STEP_BACKWARD:
696                                 ev_view_previous_page (view);
697                                 break;
698                         case GTK_SCROLL_STEP_FORWARD:
699                                 ev_view_next_page (view);
700                                 break;
701                         default:
702                                 break;
703                 }
704                 return;
705         }
706
707         if (horizontal) {
708                 adjustment = view->hadjustment;
709         } else {
710                 adjustment = view->vadjustment;
711         }
712
713         value = adjustment->value;
714
715         switch (scroll) {
716                 case GTK_SCROLL_STEP_BACKWARD:
717                         value -= adjustment->step_increment;
718                         break;
719                 case GTK_SCROLL_STEP_FORWARD:
720                         value += adjustment->step_increment;
721                         break;
722                 default:
723                         break;
724         }
725
726         value = CLAMP (value, adjustment->lower,
727                        adjustment->upper - adjustment->page_size);
728
729         gtk_adjustment_set_value (adjustment, value);
730 }
731
732 #define MARGIN 5
733
734 static void
735 ensure_rectangle_is_visible (EvView *view, GdkRectangle *rect)
736 {
737         GtkWidget *widget = GTK_WIDGET (view);
738         GtkAdjustment *adjustment;
739         int value;
740
741         view->pending_scroll = SCROLL_TO_KEEP_POSITION;
742
743         adjustment = view->vadjustment;
744
745         if (rect->y < adjustment->value) {
746                 value = MAX (adjustment->lower, rect->y - MARGIN);
747                 gtk_adjustment_set_value (view->vadjustment, value);
748         } else if (rect->y + rect->height >
749                    adjustment->value + widget->allocation.height) {
750                 value = MIN (adjustment->upper, rect->y + rect->height -
751                              widget->allocation.height + MARGIN);
752                 gtk_adjustment_set_value (view->vadjustment, value);
753         }
754
755         adjustment = view->hadjustment;
756
757         if (rect->x < adjustment->value) {
758                 value = MAX (adjustment->lower, rect->x - MARGIN);
759                 gtk_adjustment_set_value (view->hadjustment, value);
760         } else if (rect->x + rect->height >
761                    adjustment->value + widget->allocation.width) {
762                 value = MIN (adjustment->upper, rect->x + rect->width -
763                              widget->allocation.width + MARGIN);
764                 gtk_adjustment_set_value (view->hadjustment, value);
765         }
766 }
767
768 /*** Geometry computations ***/
769
770 static void
771 compute_border (EvView *view, int width, int height, GtkBorder *border)
772 {
773         if (view->presentation) {
774                 border->left = 0;
775                 border->right = 0;
776                 border->top = 0;
777                 border->bottom = 0;
778         } else {
779                 ev_document_misc_get_page_border_size (width, height, border);
780         }
781 }
782
783 static void
784 get_page_y_offset (EvView *view, int page, double zoom, int *y_offset)
785 {
786         int max_width, offset;
787         GtkBorder border;
788
789         g_return_if_fail (y_offset != NULL);
790
791         ev_page_cache_get_max_width (view->page_cache, view->rotation, zoom, &max_width);
792
793         compute_border (view, max_width, max_width, &border);
794
795         if (view->dual_page) {
796                 ev_page_cache_get_height_to_page (view->page_cache, page,
797                                                   view->rotation, zoom, NULL, &offset);
798                 offset += (page / 2 + 1) * view->spacing + (page / 2) * (border.top + border.bottom);
799         } else {
800                 ev_page_cache_get_height_to_page (view->page_cache, page,
801                                                   view->rotation, zoom, &offset, NULL);
802                 offset += (page + 1) * view->spacing + page * (border.top + border.bottom);
803         }
804
805         *y_offset = offset;
806         return;
807 }
808
809 static gboolean
810 get_page_extents (EvView       *view,
811                   gint          page,
812                   GdkRectangle *page_area,
813                   GtkBorder    *border)
814 {
815         GtkWidget *widget;
816         int width, height;
817
818         widget = GTK_WIDGET (view);
819
820         /* Get the size of the page */
821         ev_page_cache_get_size (view->page_cache, page,
822                                 view->rotation,
823                                 view->scale,
824                                 &width, &height);
825         compute_border (view, width, height, border);
826         page_area->width = width + border->left + border->right;
827         page_area->height = height + border->top + border->bottom;
828
829         if (view->presentation) {
830                 page_area->x = (MAX (0, widget->allocation.width - width))/2;
831                 page_area->y = (MAX (0, widget->allocation.height - height))/2;
832         } else if (view->continuous) {
833                 gint max_width;
834                 gint x, y;
835
836                 ev_page_cache_get_max_width (view->page_cache, view->rotation,
837                                              view->scale, &max_width);
838                 max_width = max_width + border->left + border->right;
839                 /* Get the location of the bounding box */
840                 if (view->dual_page) {
841                         x = view->spacing + (page % 2) * (max_width + view->spacing);
842                         x = x + MAX (0, widget->allocation.width - (max_width * 2 + view->spacing * 3)) / 2;
843                         if (page % 2 == 0)
844                                 x = x + (max_width - width - border->left - border->right);
845                 } else {
846                         x = view->spacing;
847                         x = x + MAX (0, widget->allocation.width - (width + view->spacing * 2)) / 2;
848                 }
849
850                 get_page_y_offset (view, page, view->scale, &y);
851
852                 page_area->x = x;
853                 page_area->y = y;
854         } else {
855                 gint x, y;
856                 if (view->dual_page) {
857                         gint width_2, height_2;
858                         gint max_width = width;
859                         gint max_height = height;
860                         GtkBorder overall_border;
861                         gint other_page;
862
863                         other_page = page ^ 1;
864
865                         /* First, we get the bounding box of the two pages */
866                         if (other_page < ev_page_cache_get_n_pages (view->page_cache)) {
867                                 ev_page_cache_get_size (view->page_cache,
868                                                         other_page,
869                                                         view->rotation,
870                                                         view->scale,
871                                                         &width_2, &height_2);
872                                 if (width_2 > width)
873                                         max_width = width_2;
874                                 if (height_2 > height)
875                                         max_height = height_2;
876                         }
877                         compute_border (view, max_width, max_height, &overall_border);
878
879                         /* Find the offsets */
880                         x = view->spacing;
881                         y = view->spacing;
882
883                         /* Adjust for being the left or right page */
884                         if (page % 2 == 0)
885                                 x = x + max_width - width;
886                         else
887                                 x = x + (max_width + overall_border.left + overall_border.right) + view->spacing;
888
889                         y = y + (max_height - height)/2;
890
891                         /* Adjust for extra allocation */
892                         x = x + MAX (0, widget->allocation.width -
893                                      ((max_width + overall_border.left + overall_border.right) * 2 + view->spacing * 3))/2;
894                         y = y + MAX (0, widget->allocation.height - (height + view->spacing * 2))/2;
895                 } else {
896                         x = view->spacing;
897                         y = view->spacing;
898
899                         /* Adjust for extra allocation */
900                         x = x + MAX (0, widget->allocation.width - (width + border->left + border->right + view->spacing * 2))/2;
901                         y = y + MAX (0, widget->allocation.height - (height + border->top + border->bottom +  view->spacing * 2))/2;
902                 }
903
904                 page_area->x = x;
905                 page_area->y = y;
906         }
907
908         return TRUE;
909 }
910
911 static void
912 view_point_to_doc_point (EvView *view,
913                          GdkPoint *view_point,
914                          GdkRectangle *page_area,
915                          double  *doc_point_x,
916                          double  *doc_point_y)
917 {
918         *doc_point_x = (double) (view_point->x - page_area->x) / view->scale;
919         *doc_point_y = (double) (view_point->y - page_area->y) / view->scale;
920 }
921
922 static void
923 view_rect_to_doc_rect (EvView *view,
924                        GdkRectangle *view_rect,
925                        GdkRectangle *page_area,
926                        EvRectangle  *doc_rect)
927 {
928         doc_rect->x1 = (double) (view_rect->x - page_area->x) / view->scale;
929         doc_rect->y1 = (double) (view_rect->y - page_area->y) / view->scale;
930         doc_rect->x2 = doc_rect->x1 + (double) view_rect->width / view->scale;
931         doc_rect->y2 = doc_rect->y1 + (double) view_rect->height / view->scale;
932 }
933
934 static void
935 doc_point_to_view_point (EvView       *view,
936                          int           page,
937                          EvPoint      *doc_point,
938                          GdkPoint     *view_point)
939 {
940         GdkRectangle page_area;
941         GtkBorder border;
942         double x, y;
943         int width, height;
944
945         ev_page_cache_get_size (view->page_cache, page,
946                                 view->rotation,
947                                 1.0,
948                                 &width, &height);
949
950         if (view->rotation == 0) {
951                 x = doc_point->x;
952                 y = doc_point->y;
953         } else if (view->rotation == 90) {
954                 x = width - doc_point->y;
955                 y = doc_point->x;
956         } else if (view->rotation == 180) {
957                 x = width - doc_point->x;
958                 y = height - doc_point->y;
959         } else if (view->rotation == 270) {
960                 x = doc_point->y;
961                 y = height - doc_point->x;
962         } else {
963                 g_assert_not_reached ();
964         }
965
966         get_page_extents (view, page, &page_area, &border);
967
968         view_point->x = x * view->scale + page_area.x;
969         view_point->y = y * view->scale + page_area.y;
970 }
971
972 static void
973 doc_rect_to_view_rect (EvView       *view,
974                        int           page,
975                        EvRectangle  *doc_rect,
976                        GdkRectangle *view_rect)
977 {
978         GdkRectangle page_area;
979         GtkBorder border;
980         double x, y, w, h;
981         int width, height;
982
983         ev_page_cache_get_size (view->page_cache, page,
984                                 view->rotation,
985                                 1.0,
986                                 &width, &height);
987
988         if (view->rotation == 0) {
989                 x = doc_rect->x1;
990                 y = doc_rect->y1;
991                 w = doc_rect->x2 - doc_rect->x1;
992                 h = doc_rect->y2 - doc_rect->y1;
993         } else if (view->rotation == 90) {
994                 x = width - doc_rect->y2;
995                 y = doc_rect->x1;
996                 w = doc_rect->y2 - doc_rect->y1;
997                 h = doc_rect->x2 - doc_rect->x1;
998         } else if (view->rotation == 180) {
999                 x = width - doc_rect->x2;
1000                 y = height - doc_rect->y2;
1001                 w = doc_rect->x2 - doc_rect->x1;
1002                 h = doc_rect->y2 - doc_rect->y1;
1003         } else if (view->rotation == 270) {
1004                 x = doc_rect->y1;
1005                 y = height - doc_rect->x2;
1006                 w = doc_rect->y2 - doc_rect->y1;
1007                 h = doc_rect->x2 - doc_rect->x1;
1008         } else {
1009                 g_assert_not_reached ();
1010         }
1011
1012         get_page_extents (view, page, &page_area, &border);
1013
1014         view_rect->x = x * view->scale + page_area.x;
1015         view_rect->y = y * view->scale + page_area.y;
1016         view_rect->width = w * view->scale;
1017         view_rect->height = h * view->scale;
1018 }
1019
1020 static void
1021 find_page_at_location (EvView  *view,
1022                        gdouble  x,
1023                        gdouble  y,
1024                        gint    *page,
1025                        gint    *x_offset,
1026                        gint    *y_offset)
1027 {
1028         int i;
1029
1030         if (view->document == NULL)
1031                 return;
1032
1033         g_assert (page);
1034         g_assert (x_offset);
1035         g_assert (y_offset);
1036
1037         for (i = view->start_page; i <= view->end_page; i++) {
1038                 GdkRectangle page_area;
1039                 GtkBorder border;
1040
1041                 if (! get_page_extents (view, i, &page_area, &border))
1042                         continue;
1043
1044                 if ((x >= page_area.x + border.left) &&
1045                     (x < page_area.x + page_area.width - border.right) &&
1046                     (y >= page_area.y + border.top) &&
1047                     (y < page_area.y + page_area.height - border.bottom)) {
1048                         *page = i;
1049                         *x_offset = x - (page_area.x + border.left);
1050                         *y_offset = y - (page_area.y + border.top);
1051                         return;
1052                 }
1053         }
1054
1055         *page = -1;
1056 }
1057
1058 static gboolean
1059 location_in_text (EvView  *view,
1060                   gdouble  x,
1061                   gdouble  y)
1062 {
1063         GdkRegion *region;
1064         gint page = -1;
1065         gint x_offset = 0, y_offset = 0;
1066
1067         find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
1068
1069         if (page == -1)
1070                 return FALSE;
1071         
1072         region = ev_pixbuf_cache_get_text_mapping (view->pixbuf_cache, page);
1073
1074         if (region)
1075                 return gdk_region_point_in (region, x_offset / view->scale, y_offset / view->scale);
1076         else
1077                 return FALSE;
1078 }
1079
1080 static int
1081 ev_view_get_width (EvView *view)
1082 {
1083         return GTK_WIDGET (view)->allocation.width;
1084 }
1085
1086 static int
1087 ev_view_get_height (EvView *view)
1088 {
1089         return GTK_WIDGET (view)->allocation.height;
1090 }
1091
1092 /*** Hyperref ***/
1093 static EvLink *
1094 get_link_at_location (EvView  *view,
1095                       gdouble  x,
1096                       gdouble  y)
1097 {
1098         gint page = -1;
1099         gint x_offset = 0, y_offset = 0;
1100         GList *link_mapping;
1101
1102         find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
1103
1104         if (page == -1)
1105                 return NULL;
1106
1107         link_mapping = ev_pixbuf_cache_get_link_mapping (view->pixbuf_cache, page);
1108
1109         if (link_mapping)
1110                 return ev_link_mapping_find (link_mapping, x_offset / view->scale, y_offset / view->scale);
1111         else
1112                 return NULL;
1113 }
1114
1115 static void
1116 goto_fitr_link (EvView *view, EvLink *link)
1117 {
1118         GdkPoint view_point;
1119         EvPoint doc_point;
1120         int doc_width, doc_height, page;
1121         double zoom;
1122
1123         page = ev_link_get_page (link);
1124         ev_page_cache_get_size (view->page_cache, page, 0, 1.0, &doc_width, &doc_height);
1125
1126         doc_point.x = ev_link_get_left (link);
1127         doc_point.y = ev_link_get_top (link);
1128         doc_point_to_view_point (view, page, &doc_point, &view_point);
1129
1130         zoom = zoom_for_size_best_fit (ev_link_get_right (link) - ev_link_get_left (link),
1131                                        ev_link_get_top (link) - ev_link_get_bottom (link),
1132                                        ev_view_get_width (view),
1133                                        ev_view_get_height (view), 0, 0);
1134
1135         ev_view_set_sizing_mode (view, EV_SIZING_FREE);
1136         ev_view_set_zoom (view, zoom, FALSE);
1137         ev_page_cache_set_current_page (view->page_cache, page);
1138         gtk_adjustment_set_value (view->hadjustment, view_point.x);
1139 }
1140
1141 static void
1142 goto_fitv_link (EvView *view, EvLink *link)
1143 {
1144         GdkPoint view_point;
1145         EvPoint doc_point;
1146         int doc_width, doc_height, page;
1147         double zoom;
1148
1149         page = ev_link_get_page (link);
1150         ev_page_cache_get_size (view->page_cache, page, 0, 1.0, &doc_width, &doc_height);
1151
1152         doc_point.x = ev_link_get_left (link);
1153         doc_point.y = 0;
1154         doc_point_to_view_point (view, page, &doc_point, &view_point);
1155
1156         zoom = zoom_for_size_fit_height (doc_width - doc_point.x , doc_height,
1157                                          ev_view_get_width (view),
1158                                          ev_view_get_height (view), 0);
1159
1160         ev_view_set_sizing_mode (view, EV_SIZING_FREE);
1161         ev_view_set_zoom (view, zoom, FALSE);
1162         ev_page_cache_set_current_page (view->page_cache, page);
1163         gtk_adjustment_set_value (view->hadjustment, view_point.x);
1164 }
1165
1166 static void
1167 goto_fith_link (EvView *view, EvLink *link)
1168 {
1169         GdkPoint view_point;
1170         EvPoint doc_point;
1171         int doc_width, doc_height, page;
1172         double zoom;
1173
1174         page = ev_link_get_page (link);
1175         ev_page_cache_get_size (view->page_cache, page, 0, 1.0, &doc_width, &doc_height);
1176
1177         doc_point.x = 0;
1178         doc_point.y = doc_height - ev_link_get_top (link);
1179         doc_point_to_view_point (view, page, &doc_point, &view_point);
1180
1181         zoom = zoom_for_size_fit_width (doc_width, ev_link_get_top (link),
1182                                         ev_view_get_width (view),
1183                                         ev_view_get_height (view), 0);
1184
1185         ev_view_set_sizing_mode (view, EV_SIZING_FREE);
1186         ev_view_set_zoom (view, zoom, FALSE);
1187         gtk_adjustment_set_value (view->vadjustment, view_point.y);
1188 }
1189
1190 static void
1191 goto_fit_link (EvView *view, EvLink *link)
1192 {
1193         double zoom;
1194         int doc_width, doc_height;
1195         int page;
1196
1197         page = ev_link_get_page (link);
1198         ev_page_cache_get_size (view->page_cache, page, 0, 1.0, &doc_width, &doc_height);
1199
1200         zoom = zoom_for_size_best_fit (doc_width, doc_height, ev_view_get_width (view),
1201                                        ev_view_get_height (view), 0, 0);
1202
1203         ev_view_set_sizing_mode (view, EV_SIZING_FREE);
1204         ev_view_set_zoom (view, zoom, FALSE);
1205         ev_page_cache_set_current_page (view->page_cache, page);
1206 }
1207
1208 static void
1209 goto_xyz_link (EvView *view, EvLink *link)
1210 {
1211         GdkPoint view_point;
1212         EvPoint doc_point;
1213         int height, page;
1214         double zoom;
1215
1216         zoom = ev_link_get_zoom (link);
1217         page = ev_link_get_page (link);
1218         ev_page_cache_get_size (view->page_cache, page, 0, 1.0, NULL, &height);
1219
1220         ev_view_set_sizing_mode (view, EV_SIZING_FREE);
1221         if (zoom != 0) {
1222                 ev_view_set_zoom (view, zoom, FALSE);
1223         }
1224
1225         doc_point.x = ev_link_get_left (link);
1226         doc_point.y = height - ev_link_get_top (link);
1227         doc_point_to_view_point (view, page, &doc_point, &view_point);
1228
1229         gtk_adjustment_set_value (view->hadjustment, view_point.x);
1230         gtk_adjustment_set_value (view->vadjustment, view_point.y);
1231 }
1232
1233 void
1234 ev_view_goto_link (EvView *view, EvLink *link)
1235 {
1236         EvLinkType type;
1237         const char *uri;
1238         int page;
1239
1240         type = ev_link_get_link_type (link);
1241
1242         switch (type) {
1243                 case EV_LINK_TYPE_TITLE:
1244                         break;
1245                 case EV_LINK_TYPE_PAGE:
1246                         page = ev_link_get_page (link);
1247                         ev_page_cache_set_current_page (view->page_cache, page);
1248                         break;
1249                 case EV_LINK_TYPE_PAGE_FIT:
1250                         goto_fit_link (view, link);
1251                         break;
1252                 case EV_LINK_TYPE_PAGE_FITH:
1253                         goto_fith_link (view, link);
1254                         break;
1255                 case EV_LINK_TYPE_PAGE_FITV:
1256                         goto_fitv_link (view, link);
1257                         break;
1258                 case EV_LINK_TYPE_PAGE_FITR:
1259                         goto_fitr_link (view, link);
1260                         break;
1261                 case EV_LINK_TYPE_PAGE_XYZ:
1262                         goto_xyz_link (view, link);
1263                         break;
1264                 case EV_LINK_TYPE_EXTERNAL_URI:
1265                         uri = ev_link_get_uri (link);
1266                         gnome_vfs_url_show (uri);
1267                         break;
1268         }
1269 }
1270
1271 static char *
1272 tip_from_link (EvView *view, EvLink *link)
1273 {
1274         EvLinkType type;
1275         char *msg = NULL;
1276         char *page_label;
1277
1278         type = ev_link_get_link_type (link);
1279
1280         switch (type) {
1281                 case EV_LINK_TYPE_TITLE:
1282                         if (ev_link_get_title (link))
1283                                 msg = g_strdup (ev_link_get_title (link));
1284                         break;
1285                 case EV_LINK_TYPE_PAGE:
1286                 case EV_LINK_TYPE_PAGE_XYZ:
1287                         page_label = ev_page_cache_get_page_label (view->page_cache, ev_link_get_page (link));
1288                         msg = g_strdup_printf (_("Go to page %s"), page_label);
1289                         g_free (page_label);
1290                         break;
1291                 case EV_LINK_TYPE_EXTERNAL_URI:
1292                         msg = g_strdup (ev_link_get_uri (link));
1293                         break;
1294                 default:
1295                         break;
1296         }
1297
1298         return msg;
1299 }
1300
1301 static void
1302 handle_link_over_xy (EvView *view, gint x, gint y)
1303 {
1304         EvLink *link;
1305
1306         link = get_link_at_location (view, x + view->scroll_x, y + view->scroll_y);
1307
1308         if (view->link_tooltip == NULL) {
1309                 view->link_tooltip = ev_tooltip_new (GTK_WIDGET (view));
1310         }
1311
1312         if (view->hovered_link != link) {
1313                 view->hovered_link = link;
1314                 ev_tooltip_deactivate (EV_TOOLTIP (view->link_tooltip));
1315         }
1316
1317         if (link) {
1318                 char *msg = tip_from_link (view, link);
1319
1320                 ev_tooltip_set_position (EV_TOOLTIP (view->link_tooltip), x, y);
1321                 ev_tooltip_set_text (EV_TOOLTIP (view->link_tooltip), msg);
1322                 ev_tooltip_activate (EV_TOOLTIP (view->link_tooltip));
1323                 g_free (msg);
1324
1325                 ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK);
1326         } else if (location_in_text (view, x + view->scroll_x, y + view->scroll_y)) {
1327                 ev_view_set_cursor (view, EV_VIEW_CURSOR_IBEAM);
1328         } else {
1329                 ev_view_set_status (view, NULL);
1330                 if (view->cursor == EV_VIEW_CURSOR_LINK ||
1331                     view->cursor == EV_VIEW_CURSOR_IBEAM)
1332                         ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
1333         }
1334         return;
1335 }
1336
1337 /*** GtkWidget implementation ***/
1338
1339 static void
1340 ev_view_size_request_continuous_dual_page (EvView         *view,
1341                                            GtkRequisition *requisition)
1342 {
1343         int max_width;
1344         gint n_pages;
1345         GtkBorder border;
1346
1347         ev_page_cache_get_max_width (view->page_cache, view->rotation,
1348                                      view->scale, &max_width);
1349         compute_border (view, max_width, max_width, &border);
1350
1351         n_pages = ev_page_cache_get_n_pages (view->page_cache) + 1;
1352
1353         requisition->width = (max_width + border.left + border.right) * 2 + (view->spacing * 3);
1354         get_page_y_offset (view, n_pages, view->scale, &requisition->height);
1355
1356         if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
1357                 requisition->width = 1;
1358         } else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
1359                 requisition->width = 1;
1360                 /* FIXME: This could actually be set on one page docs or docs
1361                  * with a strange aspect ratio. */
1362                 /* requisition->height = 1;*/
1363         }
1364 }
1365
1366 static void
1367 ev_view_size_request_continuous (EvView         *view,
1368                                  GtkRequisition *requisition)
1369 {
1370         int max_width;
1371         int n_pages;
1372         GtkBorder border;
1373
1374
1375         ev_page_cache_get_max_width (view->page_cache, view->rotation,
1376                                      view->scale, &max_width);
1377         n_pages = ev_page_cache_get_n_pages (view->page_cache);
1378         compute_border (view, max_width, max_width, &border);
1379
1380         requisition->width = max_width + (view->spacing * 2) + border.left + border.right;
1381         get_page_y_offset (view, n_pages, view->scale, &requisition->height);
1382
1383         if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
1384                 requisition->width = 1;
1385         } else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
1386                 requisition->width = 1;
1387                 /* FIXME: This could actually be set on one page docs or docs
1388                  * with a strange aspect ratio. */
1389                 /* requisition->height = 1;*/
1390         }
1391 }
1392
1393 static void
1394 ev_view_size_request_dual_page (EvView         *view,
1395                                 GtkRequisition *requisition)
1396 {
1397         GtkBorder border;
1398         gint width, height;
1399
1400         /* Find the largest of the two. */
1401         ev_page_cache_get_size (view->page_cache,
1402                                 view->current_page,
1403                                 view->rotation,
1404                                 view->scale,
1405                                 &width, &height);
1406         if (view->current_page + 1 < ev_page_cache_get_n_pages (view->page_cache)) {
1407                 gint width_2, height_2;
1408                 ev_page_cache_get_size (view->page_cache,
1409                                         view->current_page + 1,
1410                                         view->rotation,
1411                                         view->scale,
1412                                         &width_2, &height_2);
1413                 if (width_2 > width) {
1414                         width = width_2;
1415                         height = height_2;
1416                 }
1417         }
1418         compute_border (view, width, height, &border);
1419
1420         requisition->width = ((width + border.left + border.right) * 2) +
1421                 (view->spacing * 3);
1422         requisition->height = (height + border.top + border.bottom) +
1423                 (view->spacing * 2);
1424
1425         if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
1426                 requisition->width = 1;
1427         } else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
1428                 requisition->width = 1;
1429                 requisition->height = 1;
1430         }
1431 }
1432
1433 static void
1434 ev_view_size_request_single_page (EvView         *view,
1435                                   GtkRequisition *requisition)
1436 {
1437         GtkBorder border;
1438         gint width, height;
1439
1440         ev_page_cache_get_size (view->page_cache,
1441                                 view->current_page,
1442                                 view->rotation,
1443                                 view->scale,
1444                                 &width, &height);
1445         compute_border (view, width, height, &border);
1446
1447         requisition->width = width + border.left + border.right + (2 * view->spacing);
1448         requisition->height = height + border.top + border.bottom + (2 * view->spacing);
1449
1450         if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
1451                 requisition->width = 1;
1452                 requisition->height = height + border.top + border.bottom + (2 * view->spacing);
1453         } else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
1454                 requisition->width = 1;
1455                 requisition->height = 1;
1456         }
1457 }
1458
1459 static void
1460 ev_view_size_request (GtkWidget      *widget,
1461                       GtkRequisition *requisition)
1462 {
1463         EvView *view = EV_VIEW (widget);
1464
1465         if (view->document == NULL) {
1466                 requisition->width = 1;
1467                 requisition->height = 1;
1468                 return;
1469         }
1470
1471         if (view->presentation) {
1472                 requisition->width = 1;
1473                 requisition->height = 1;
1474                 return;
1475         }
1476
1477         if (view->continuous && view->dual_page)
1478                 ev_view_size_request_continuous_dual_page (view, requisition);
1479         else if (view->continuous)
1480                 ev_view_size_request_continuous (view, requisition);
1481         else if (view->dual_page)
1482                 ev_view_size_request_dual_page (view, requisition);
1483         else
1484                 ev_view_size_request_single_page (view, requisition);
1485 }
1486
1487 static void
1488 ev_view_size_allocate (GtkWidget      *widget,
1489                        GtkAllocation  *allocation)
1490 {
1491         EvView *view = EV_VIEW (widget);
1492
1493         if (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
1494             view->sizing_mode == EV_SIZING_BEST_FIT) {
1495
1496                 g_signal_emit (view, signals[SIGNAL_ZOOM_INVALID], 0);
1497
1498                 ev_view_size_request (widget, &widget->requisition);
1499         }
1500
1501         view_set_adjustment_values (view, GTK_ORIENTATION_HORIZONTAL);
1502         view_set_adjustment_values (view, GTK_ORIENTATION_VERTICAL);
1503
1504         view->pending_scroll = SCROLL_TO_KEEP_POSITION;
1505         view->pending_resize = FALSE;
1506
1507         if (view->document)
1508                 view_update_range_and_current_page (view);
1509
1510         GTK_WIDGET_CLASS (ev_view_parent_class)->size_allocate (widget, allocation);
1511 }
1512
1513 static void
1514 ev_view_realize (GtkWidget *widget)
1515 {
1516         EvView *view = EV_VIEW (widget);
1517         GdkWindowAttr attributes;
1518
1519         GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1520
1521
1522         attributes.window_type = GDK_WINDOW_CHILD;
1523         attributes.wclass = GDK_INPUT_OUTPUT;
1524         attributes.visual = gtk_widget_get_visual (widget);
1525         attributes.colormap = gtk_widget_get_colormap (widget);
1526
1527         attributes.x = widget->allocation.x;
1528         attributes.y = widget->allocation.y;
1529         attributes.width = widget->allocation.width;
1530         attributes.height = widget->allocation.height;
1531         attributes.event_mask = GDK_EXPOSURE_MASK |
1532                                 GDK_BUTTON_PRESS_MASK |
1533                                 GDK_BUTTON_RELEASE_MASK |
1534                                 GDK_SCROLL_MASK |
1535                                 GDK_KEY_PRESS_MASK |
1536                                 GDK_POINTER_MOTION_MASK |
1537                                 GDK_ENTER_NOTIFY_MASK |
1538                                 GDK_LEAVE_NOTIFY_MASK;
1539
1540         widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1541                                          &attributes,
1542                                          GDK_WA_X | GDK_WA_Y |
1543                                          GDK_WA_COLORMAP |
1544                                          GDK_WA_VISUAL);
1545         gdk_window_set_user_data (widget->window, widget);
1546         widget->style = gtk_style_attach (widget->style, widget->window);
1547
1548         if (view->presentation)
1549                 gdk_window_set_background (widget->window, &widget->style->black);
1550         else
1551                 gdk_window_set_background (widget->window, &widget->style->mid [GTK_STATE_NORMAL]);
1552 }
1553
1554 static gboolean
1555 ev_view_scroll_event (GtkWidget *widget, GdkEventScroll *event)
1556 {
1557         EvView *view = EV_VIEW (widget);
1558         guint state;
1559
1560         state = event->state & gtk_accelerator_get_default_mod_mask ();
1561
1562         if (state == GDK_CONTROL_MASK && view->presentation == FALSE) {
1563                 ev_view_set_sizing_mode (view, EV_SIZING_FREE);
1564
1565                 if (event->direction == GDK_SCROLL_UP ||
1566                     event->direction == GDK_SCROLL_LEFT) {
1567                         if (ev_view_can_zoom_in (view)) {
1568                                 ev_view_zoom_in (view);
1569                         }
1570                 } else {
1571                         if (ev_view_can_zoom_out (view)) {
1572                                 ev_view_zoom_out (view);
1573                         }
1574                 }
1575
1576                 return TRUE;
1577         }
1578
1579         /* Shift+Wheel scrolls the in the perpendicular direction */
1580         if (state & GDK_SHIFT_MASK) {
1581                 if (event->direction == GDK_SCROLL_UP)
1582                         event->direction = GDK_SCROLL_LEFT;
1583                 if (event->direction == GDK_SCROLL_LEFT)
1584                         event->direction = GDK_SCROLL_UP;
1585                 if (event->direction == GDK_SCROLL_DOWN)
1586                         event->direction = GDK_SCROLL_RIGHT;
1587                 if (event->direction == GDK_SCROLL_RIGHT)
1588                         event->direction = GDK_SCROLL_DOWN;
1589
1590                 event->state &= ~GDK_SHIFT_MASK;
1591                 state &= ~GDK_SHIFT_MASK;
1592         }
1593
1594         if (state == 0 && view->presentation) {
1595                 switch (event->direction) {
1596                 case GDK_SCROLL_DOWN:
1597                 case GDK_SCROLL_RIGHT:
1598                         ev_view_next_page (view);       
1599                         break;
1600                 case GDK_SCROLL_UP:
1601                 case GDK_SCROLL_LEFT:
1602                         ev_view_previous_page (view);
1603                         break;
1604                 }
1605
1606                 return TRUE;
1607         }
1608
1609         return FALSE;
1610 }
1611
1612 static EvViewSelection *
1613 find_selection_for_page (EvView *view,
1614                          gint    page)
1615 {
1616         GList *list;
1617
1618         for (list = view->selection_info.selections; list != NULL; list = list->next) {
1619                 EvViewSelection *selection;
1620
1621                 selection = (EvViewSelection *) list->data;
1622
1623                 if (selection->page == page)
1624                         return selection;
1625         }
1626
1627         return NULL;
1628 }
1629
1630 static gboolean
1631 ev_view_expose_event (GtkWidget      *widget,
1632                       GdkEventExpose *event)
1633 {
1634         EvView *view = EV_VIEW (widget);
1635         int i;
1636
1637         if (view->document == NULL)
1638                 return FALSE;
1639
1640         for (i = view->start_page; i <= view->end_page; i++) {
1641                 GdkRectangle page_area;
1642                 GtkBorder border;
1643
1644                 if (!get_page_extents (view, i, &page_area, &border))
1645                         continue;
1646
1647                 page_area.x -= view->scroll_x;
1648                 page_area.y -= view->scroll_y;
1649
1650                 draw_one_page (view, i, &page_area, &border, &(event->area));
1651
1652                 if (EV_IS_DOCUMENT_FIND (view->document))
1653                         highlight_find_results (view, i);
1654         }
1655
1656         return FALSE;
1657 }
1658
1659 static gboolean
1660 ev_view_button_press_event (GtkWidget      *widget,
1661                             GdkEventButton *event)
1662 {
1663         EvView *view = EV_VIEW (widget);
1664
1665         if (!GTK_WIDGET_HAS_FOCUS (widget)) {
1666                 gtk_widget_grab_focus (widget);
1667         }
1668
1669         view->pressed_button = event->button;
1670
1671         switch (event->button) {
1672                 case 1:
1673                         if (view->selection_info.selections) {
1674                                 clear_selection (view);
1675                                 gtk_widget_queue_draw (widget);
1676                         }
1677
1678                         view->selection_info.start.x = event->x + view->scroll_x;
1679                         view->selection_info.start.y = event->y + view->scroll_y;
1680                         return TRUE;
1681                 case 2:
1682                         /* use root coordinates as reference point because
1683                          * scrolling changes window relative coordinates */
1684                         view->drag_info.start.x = event->x_root;
1685                         view->drag_info.start.y = event->y_root;
1686                         view->drag_info.hadj = gtk_adjustment_get_value (view->hadjustment);
1687                         view->drag_info.vadj = gtk_adjustment_get_value (view->vadjustment);
1688
1689                         ev_view_set_cursor (view, EV_VIEW_CURSOR_DRAG);
1690
1691                         return TRUE;
1692         }
1693
1694         return FALSE;
1695 }
1696
1697
1698 static gboolean
1699 selection_update_idle_cb (EvView *view)
1700 {
1701         GdkPoint point;
1702         point.x = view->motion_x;
1703         point.y = view->motion_y;
1704         compute_selections (view, &view->selection_info.start, &point);
1705
1706         view->selection_update_id = 0;
1707         return FALSE;
1708 }
1709
1710 static gboolean
1711 ev_view_motion_notify_event (GtkWidget      *widget,
1712                              GdkEventMotion *event)
1713 {
1714         EvView *view = EV_VIEW (widget);
1715
1716         if (!view->document)
1717                 return FALSE;
1718
1719         /* For the Evince 0.4.x release, we limit selection to un-rotated
1720          * documents only.
1721          */
1722         if (view->pressed_button == 1 &&
1723             view->rotation == 0) {
1724                 view->selection_info.in_selection = TRUE;
1725                 view->motion_x = event->x + view->scroll_x;
1726                 view->motion_y = event->y + view->scroll_y;
1727
1728                 /* Queue an idle to handle the motion.  We do this because
1729                  * handling any selection events in the motion could be slower
1730                  * than new motion events reach us.  We always put it in the
1731                  * idle to make sure we catch up and don't visibly lag the
1732                  * mouse. */
1733                 if (! view->selection_update_id)
1734                         view->selection_update_id = g_idle_add ((GSourceFunc)selection_update_idle_cb, view);
1735
1736                 return TRUE;
1737         } else if (view->pressed_button == 2) {
1738                 if (!view->drag_info.in_drag) {
1739                         gboolean start;
1740
1741                         start = gtk_drag_check_threshold (widget,
1742                                                           view->drag_info.start.x,
1743                                                           view->drag_info.start.y,
1744                                                           event->x_root,
1745                                                           event->y_root);
1746                         view->drag_info.in_drag = start;
1747                 }
1748
1749                 if (view->drag_info.in_drag) {
1750                         int dx, dy;
1751                         gdouble dhadj_value, dvadj_value;
1752
1753                         dx = event->x_root - view->drag_info.start.x;
1754                         dy = event->y_root - view->drag_info.start.y;
1755
1756                         dhadj_value = view->hadjustment->page_size *
1757                                       (gdouble)dx / widget->allocation.width;
1758                         dvadj_value = view->vadjustment->page_size *
1759                                       (gdouble)dy / widget->allocation.height;
1760
1761                         /* clamp scrolling to visible area */
1762                         gtk_adjustment_set_value (view->hadjustment,
1763                                                   MIN(view->drag_info.hadj - dhadj_value,
1764                                                       view->hadjustment->upper -
1765                                                       view->hadjustment->page_size));
1766                         gtk_adjustment_set_value (view->vadjustment,
1767                                                   MIN(view->drag_info.vadj - dvadj_value,
1768                                                       view->vadjustment->upper -
1769                                                       view->vadjustment->page_size));
1770
1771                         return TRUE;
1772                 }
1773         /* For the Evince 0.4.x release, we limit links to un-rotated documents
1774          * only.
1775          */
1776         } else if (view->pressed_button <= 0 &&
1777                    view->rotation == 0) {
1778                 handle_link_over_xy (view, event->x, event->y);
1779                 return TRUE;
1780         }
1781
1782         return FALSE;
1783 }
1784
1785 static gboolean
1786 ev_view_button_release_event (GtkWidget      *widget,
1787                               GdkEventButton *event)
1788 {
1789         EvView *view = EV_VIEW (widget);
1790         EvLink *link;
1791
1792         if (view->pressed_button == 2) {
1793                 ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
1794         }
1795
1796         if (view->document) {
1797                 link = get_link_at_location (view, event->x + view->scroll_x,
1798                                              event->y + view->scroll_y);
1799         } else {
1800                 link = NULL;
1801         }
1802
1803         view->pressed_button = -1;
1804         view->drag_info.in_drag = FALSE;
1805
1806         if (view->selection_info.selections) {
1807                 ev_view_update_primary_selection (view);
1808         } else if (link) {
1809                 ev_view_goto_link (view, link);
1810         } else if (view->presentation) {
1811                 switch (event->button) {
1812                 case 1:
1813                         ev_view_next_page (view);       
1814                         return TRUE;
1815                 case 3:
1816                         ev_view_previous_page (view);   
1817                         return TRUE;
1818                 }
1819         }
1820  
1821         return FALSE;
1822 }
1823
1824 static gint
1825 ev_view_focus_in (GtkWidget     *widget,
1826                   GdkEventFocus *event)
1827 {
1828         if (EV_VIEW (widget)->pixbuf_cache)
1829                 ev_pixbuf_cache_style_changed (EV_VIEW (widget)->pixbuf_cache);
1830         gtk_widget_queue_draw (widget);
1831
1832         return FALSE;
1833 }
1834
1835 static gint
1836 ev_view_focus_out (GtkWidget     *widget,
1837                      GdkEventFocus *event)
1838 {
1839         if (EV_VIEW (widget)->pixbuf_cache)
1840                 ev_pixbuf_cache_style_changed (EV_VIEW (widget)->pixbuf_cache);
1841         gtk_widget_queue_draw (widget);
1842
1843         return FALSE;
1844 }
1845
1846 static gboolean
1847 ev_view_leave_notify_event (GtkWidget *widget, GdkEventCrossing   *event)
1848 {
1849         EvView *view = EV_VIEW (widget);
1850     
1851         ev_view_set_status (view, NULL);
1852
1853         if (view->cursor == EV_VIEW_CURSOR_LINK ||
1854             view->cursor == EV_VIEW_CURSOR_IBEAM)
1855                 ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
1856
1857         if (view->link_tooltip) {
1858                 view->hovered_link = NULL;
1859                 ev_tooltip_deactivate (EV_TOOLTIP (view->link_tooltip));
1860         }
1861
1862         return FALSE;
1863 }
1864
1865 static gboolean
1866 ev_view_enter_notify_event (GtkWidget *widget, GdkEventCrossing   *event)
1867 {
1868         EvView *view = EV_VIEW (widget);
1869
1870         handle_link_over_xy (view, event->x, event->y);
1871     
1872         return FALSE;
1873 }
1874
1875 static void
1876 ev_view_style_set (GtkWidget *widget,
1877                    GtkStyle  *old_style)
1878 {
1879         if (EV_VIEW (widget)->pixbuf_cache)
1880                 ev_pixbuf_cache_style_changed (EV_VIEW (widget)->pixbuf_cache);
1881
1882         GTK_WIDGET_CLASS (ev_view_parent_class)->style_set (widget, old_style);
1883 }
1884
1885
1886 /*** Drawing ***/
1887
1888 static guint32
1889 ev_gdk_color_to_rgb (const GdkColor *color)
1890 {
1891   guint32 result;
1892   result = (0xff0000 | (color->red & 0xff00));
1893   result <<= 8;
1894   result |= ((color->green & 0xff00) | (color->blue >> 8));
1895   return result;
1896 }
1897
1898 static void
1899 draw_rubberband (GtkWidget *widget, GdkWindow *window,
1900                  const GdkRectangle *rect, guchar alpha)
1901 {
1902         GdkGC *gc;
1903         GdkPixbuf *pixbuf;
1904         GdkColor *fill_color_gdk;
1905         guint fill_color;
1906
1907         fill_color_gdk = gdk_color_copy (&GTK_WIDGET (widget)->style->base[GTK_STATE_SELECTED]);
1908         fill_color = ev_gdk_color_to_rgb (fill_color_gdk) << 8 | alpha;
1909
1910         pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
1911                                  rect->width, rect->height);
1912         gdk_pixbuf_fill (pixbuf, fill_color);
1913
1914         gdk_draw_pixbuf (window, NULL, pixbuf,
1915                          0, 0,
1916                          rect->x - EV_VIEW (widget)->scroll_x, rect->y - EV_VIEW (widget)->scroll_y,
1917                          rect->width, rect->height,
1918                          GDK_RGB_DITHER_NONE,
1919                          0, 0);
1920
1921         g_object_unref (pixbuf);
1922
1923         gc = gdk_gc_new (window);
1924         gdk_gc_set_rgb_fg_color (gc, fill_color_gdk);
1925         gdk_draw_rectangle (window, gc, FALSE,
1926                             rect->x - EV_VIEW (widget)->scroll_x, rect->y - EV_VIEW (widget)->scroll_y,
1927                             rect->width - 1,
1928                             rect->height - 1);
1929         g_object_unref (gc);
1930
1931         gdk_color_free (fill_color_gdk);
1932 }
1933
1934
1935 static void
1936 highlight_find_results (EvView *view, int page)
1937 {
1938         EvDocumentFind *find;
1939         int i, results = 0;
1940
1941         g_return_if_fail (EV_IS_DOCUMENT_FIND (view->document));
1942
1943         find = EV_DOCUMENT_FIND (view->document);
1944
1945         results = ev_document_find_get_n_results (find, page);
1946
1947         for (i = 0; i < results; i++) {
1948                 EvRectangle rectangle;
1949                 GdkRectangle view_rectangle;
1950                 guchar alpha;
1951
1952                 if (i == view->find_result && page == view->find_page) {
1953                         alpha = 0x90;
1954                 } else {
1955                         alpha = 0x20;
1956                 }
1957
1958                 ev_document_find_get_result (find, page, i, &rectangle);
1959                 doc_rect_to_view_rect (view, page, &rectangle, &view_rectangle);
1960                 draw_rubberband (GTK_WIDGET (view), GTK_WIDGET(view)->window,
1961                                  &view_rectangle, alpha);
1962         }
1963 }
1964
1965 static void
1966 draw_loading_text (EvView       *view,
1967                    GdkRectangle *page_area,
1968                    GdkRectangle *expose_area)
1969 {
1970         PangoLayout *layout;
1971         PangoFontDescription *font_desc;
1972         PangoRectangle logical_rect;
1973         double real_scale;
1974         int target_width;
1975
1976         const char *loading_text = _("Loading...");     
1977
1978         layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), loading_text);
1979
1980         font_desc = pango_font_description_new ();
1981
1982
1983         /* We set the font to be 10 points, get the size, and scale appropriately */
1984         pango_font_description_set_size (font_desc, 10 * PANGO_SCALE);
1985         pango_layout_set_font_description (layout, font_desc);
1986         pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1987
1988         /* Make sure we fit the middle of the page */
1989         target_width = MAX (page_area->width / 2, 1);
1990         real_scale = ((double)target_width / (double) logical_rect.width) * (PANGO_SCALE * 10);
1991         pango_font_description_set_size (font_desc, (int)real_scale);
1992         pango_layout_set_font_description (layout, font_desc);
1993         pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
1994
1995         gtk_paint_layout (GTK_WIDGET (view)->style,
1996                           GTK_WIDGET (view)->window,
1997                           GTK_WIDGET_STATE (view),
1998                           FALSE,
1999                           page_area,
2000                           GTK_WIDGET (view),
2001                           NULL,
2002                           page_area->x + (target_width/2),
2003                           page_area->y + (page_area->height - logical_rect.height) / 2,
2004                           layout);
2005
2006         pango_font_description_free (font_desc);
2007         g_object_unref (layout);
2008 }
2009
2010 static void
2011 draw_one_page (EvView          *view,
2012                gint             page,
2013                GdkRectangle    *page_area,
2014                GtkBorder       *border,
2015                GdkRectangle    *expose_area)
2016 {
2017         gint width, height;
2018         GdkPixbuf *current_pixbuf;
2019         GdkRectangle overlap;
2020         GdkRectangle real_page_area;
2021         EvViewSelection *selection;
2022
2023         g_assert (view->document);
2024         if (! gdk_rectangle_intersect (page_area, expose_area, &overlap))
2025                 return;
2026
2027         selection = find_selection_for_page (view, page);
2028         ev_page_cache_get_size (view->page_cache,
2029                                 page, view->rotation,
2030                                 view->scale,
2031                                 &width, &height);
2032         /* Render the document itself */
2033         real_page_area = *page_area;
2034
2035         real_page_area.x += border->left;
2036         real_page_area.y += border->top;
2037         real_page_area.width -= (border->left + border->right);
2038         real_page_area.height -= (border->top + border->bottom);
2039
2040         ev_document_misc_paint_one_page (GTK_WIDGET(view)->window,
2041                                          GTK_WIDGET (view),
2042                                          page_area, border);
2043
2044         if (gdk_rectangle_intersect (&real_page_area, expose_area, &overlap)) {
2045                 GdkPixbuf *selection_pixbuf = NULL;
2046                 GdkPixbuf *scaled_image;
2047                 GdkPixbuf *scaled_selection;
2048
2049                 current_pixbuf = ev_pixbuf_cache_get_pixbuf (view->pixbuf_cache, page);
2050
2051                 /* Get the selection pixbuf iff we have something to draw */
2052                 if (current_pixbuf && view->selection_mode == EV_VIEW_SELECTION_TEXT && selection)
2053                         selection_pixbuf = ev_pixbuf_cache_get_selection_pixbuf (view->pixbuf_cache,
2054                                                                                  page,
2055                                                                                  view->scale,
2056                                                                                  NULL);
2057
2058                 if (current_pixbuf == NULL)
2059                         scaled_image = NULL;
2060                 else if (width == gdk_pixbuf_get_width (current_pixbuf) &&
2061                          height == gdk_pixbuf_get_height (current_pixbuf))
2062                         scaled_image = g_object_ref (current_pixbuf);
2063                 else
2064                         /* FIXME: We don't want to scale the whole area, just the right
2065                          * area of it */
2066                         scaled_image = gdk_pixbuf_scale_simple (current_pixbuf,
2067                                                                 width, height,
2068                                                                 GDK_INTERP_NEAREST);
2069
2070                 if (selection_pixbuf == NULL)
2071                         scaled_selection = NULL;
2072                 else if (width == gdk_pixbuf_get_width (selection_pixbuf) &&
2073                          height == gdk_pixbuf_get_height (selection_pixbuf))
2074                         scaled_selection = g_object_ref (selection_pixbuf);
2075                 else
2076                         /* FIXME: We don't want to scale the whole area, just the right
2077                          * area of it */
2078                         scaled_selection = gdk_pixbuf_scale_simple (selection_pixbuf,
2079                                                                     width, height,
2080                                                                     GDK_INTERP_NEAREST);
2081
2082                 if (scaled_image) {
2083                         gdk_draw_pixbuf (GTK_WIDGET(view)->window,
2084                                          GTK_WIDGET (view)->style->fg_gc[GTK_STATE_NORMAL],
2085                                          scaled_image,
2086                                          overlap.x - real_page_area.x,
2087                                          overlap.y - real_page_area.y,
2088                                          overlap.x, overlap.y,
2089                                          overlap.width, overlap.height,
2090                                          GDK_RGB_DITHER_NORMAL,
2091                                          0, 0);
2092                         g_object_unref (scaled_image);
2093                 } else {
2094                         draw_loading_text (view,
2095                                            &real_page_area,
2096                                            expose_area);
2097                 }
2098
2099                 if (scaled_selection) {
2100                         gdk_draw_pixbuf (GTK_WIDGET(view)->window,
2101                                          GTK_WIDGET (view)->style->fg_gc[GTK_STATE_NORMAL],
2102                                          scaled_selection,
2103                                          overlap.x - real_page_area.x,
2104                                          overlap.y - real_page_area.y,
2105                                          overlap.x, overlap.y,
2106                                          overlap.width, overlap.height,
2107                                          GDK_RGB_DITHER_NORMAL,
2108                                          0, 0);
2109                         g_object_unref (scaled_selection);
2110                 }
2111         }
2112 }
2113
2114 /*** GObject functions ***/
2115
2116 static void
2117 ev_view_finalize (GObject *object)
2118 {
2119         EvView *view = EV_VIEW (object);
2120
2121         LOG ("Finalize");
2122
2123         g_free (view->status);
2124         g_free (view->find_status);
2125
2126         clear_selection (view);
2127
2128         G_OBJECT_CLASS (ev_view_parent_class)->finalize (object);
2129 }
2130
2131 static void
2132 ev_view_destroy (GtkObject *object)
2133 {
2134         EvView *view = EV_VIEW (object);
2135
2136         if (view->document) {
2137                 g_object_unref (view->document);
2138                 view->document = NULL;
2139         }
2140
2141         if (view->pixbuf_cache) {
2142                 g_object_unref (view->pixbuf_cache);
2143                 view->pixbuf_cache = NULL;
2144         }
2145
2146         if (view->link_tooltip) {
2147                 gtk_widget_destroy (view->link_tooltip);
2148         }
2149
2150         ev_view_set_scroll_adjustments (view, NULL, NULL);
2151
2152         GTK_OBJECT_CLASS (ev_view_parent_class)->destroy (object);
2153 }
2154
2155 static void
2156 ev_view_set_property (GObject      *object,
2157                       guint         prop_id,
2158                       const GValue *value,
2159                       GParamSpec   *pspec)
2160 {
2161         EvView *view = EV_VIEW (object);
2162
2163         switch (prop_id)
2164         {
2165         case PROP_CONTINUOUS:
2166                 ev_view_set_continuous (view, g_value_get_boolean (value));
2167                 break;
2168         case PROP_DUAL_PAGE:
2169                 ev_view_set_dual_page (view, g_value_get_boolean (value));
2170                 break;
2171         case PROP_FULLSCREEN:
2172                 ev_view_set_fullscreen (view, g_value_get_boolean (value));
2173                 break;
2174         case PROP_PRESENTATION:
2175                 ev_view_set_presentation (view, g_value_get_boolean (value));
2176                 break;
2177         case PROP_SIZING_MODE:
2178                 ev_view_set_sizing_mode (view, g_value_get_enum (value));
2179                 break;
2180         case PROP_ZOOM:
2181                 ev_view_set_zoom (view, g_value_get_double (value), FALSE);
2182                 break;
2183         case PROP_ROTATION:
2184                 ev_view_set_rotation (view, g_value_get_int (value));
2185                 break;
2186         default:
2187                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2188         }
2189 }
2190
2191 static void
2192 ev_view_get_property (GObject *object,
2193                       guint prop_id,
2194                       GValue *value,
2195                       GParamSpec *pspec)
2196 {
2197         EvView *view = EV_VIEW (object);
2198
2199         switch (prop_id)
2200         {
2201         case PROP_STATUS:
2202                 g_value_set_string (value, view->status);
2203                 break;
2204         case PROP_FIND_STATUS:
2205                 g_value_set_string (value, view->status);
2206                 break;
2207         case PROP_CONTINUOUS:
2208                 g_value_set_boolean (value, view->continuous);
2209                 break;
2210         case PROP_DUAL_PAGE:
2211                 g_value_set_boolean (value, view->dual_page);
2212                 break;
2213         case PROP_FULLSCREEN:
2214                 g_value_set_boolean (value, view->fullscreen);
2215                 break;
2216         case PROP_PRESENTATION:
2217                 g_value_set_boolean (value, view->presentation);
2218                 break;
2219         case PROP_SIZING_MODE:
2220                 g_value_set_enum (value, view->sizing_mode);
2221                 break;
2222         case PROP_ZOOM:
2223                 g_value_set_double (value, view->scale);
2224                 break;
2225         case PROP_ROTATION:
2226                 g_value_set_int (value, view->rotation);
2227                 break;
2228         default:
2229                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2230         }
2231 }
2232
2233 static void
2234 ev_view_class_init (EvViewClass *class)
2235 {
2236         GObjectClass *object_class = G_OBJECT_CLASS (class);
2237         GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (class);
2238         GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
2239         GtkBindingSet *binding_set;
2240
2241         object_class->finalize = ev_view_finalize;
2242         object_class->set_property = ev_view_set_property;
2243         object_class->get_property = ev_view_get_property;
2244
2245         widget_class->expose_event = ev_view_expose_event;
2246         widget_class->button_press_event = ev_view_button_press_event;
2247         widget_class->motion_notify_event = ev_view_motion_notify_event;
2248         widget_class->button_release_event = ev_view_button_release_event;
2249         widget_class->focus_in_event = ev_view_focus_in;
2250         widget_class->focus_out_event = ev_view_focus_out;
2251         widget_class->size_request = ev_view_size_request;
2252         widget_class->size_allocate = ev_view_size_allocate;
2253         widget_class->realize = ev_view_realize;
2254         widget_class->scroll_event = ev_view_scroll_event;
2255         widget_class->enter_notify_event = ev_view_enter_notify_event;
2256         widget_class->leave_notify_event = ev_view_leave_notify_event;
2257         widget_class->style_set = ev_view_style_set;
2258         gtk_object_class->destroy = ev_view_destroy;
2259
2260         class->set_scroll_adjustments = ev_view_set_scroll_adjustments;
2261         class->binding_activated = ev_view_binding_activated;
2262
2263         widget_class->set_scroll_adjustments_signal =
2264             g_signal_new ("set-scroll-adjustments",
2265                           G_OBJECT_CLASS_TYPE (object_class),
2266                           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
2267                           G_STRUCT_OFFSET (EvViewClass, set_scroll_adjustments),
2268                           NULL, NULL,
2269                           ev_marshal_VOID__OBJECT_OBJECT,
2270                           G_TYPE_NONE, 2,
2271                           GTK_TYPE_ADJUSTMENT,
2272                           GTK_TYPE_ADJUSTMENT);
2273
2274         signals[SIGNAL_BINDING_ACTIVATED] = g_signal_new ("binding_activated",
2275                          G_TYPE_FROM_CLASS (object_class),
2276                          G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
2277                          G_STRUCT_OFFSET (EvViewClass, binding_activated),
2278                          NULL, NULL,
2279                          ev_marshal_VOID__ENUM_BOOLEAN,
2280                          G_TYPE_NONE, 2,
2281                          GTK_TYPE_SCROLL_TYPE,
2282                          G_TYPE_BOOLEAN);
2283
2284         signals[SIGNAL_ZOOM_INVALID] = g_signal_new ("zoom-invalid",
2285                          G_TYPE_FROM_CLASS (object_class),
2286                          G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
2287                          G_STRUCT_OFFSET (EvViewClass, zoom_invalid),
2288                          NULL, NULL,
2289                          ev_marshal_VOID__VOID,
2290                          G_TYPE_NONE, 0, G_TYPE_NONE);
2291
2292         g_object_class_install_property (object_class,
2293                                          PROP_STATUS,
2294                                          g_param_spec_string ("status",
2295                                                               "Status Message",
2296                                                               "The status message",
2297                                                               NULL,
2298                                                               G_PARAM_READABLE));
2299
2300         g_object_class_install_property (object_class,
2301                                          PROP_FIND_STATUS,
2302                                          g_param_spec_string ("find-status",
2303                                                               "Find Status Message",
2304                                                               "The find status message",
2305                                                               NULL,
2306                                                               G_PARAM_READABLE));
2307
2308         g_object_class_install_property (object_class,
2309                                          PROP_CONTINUOUS,
2310                                          g_param_spec_boolean ("continuous",
2311                                                                "Continuous",
2312                                                                "Continuous scrolling mode",
2313                                                                TRUE,
2314                                                                G_PARAM_READWRITE));
2315
2316         g_object_class_install_property (object_class,
2317                                          PROP_DUAL_PAGE,
2318                                          g_param_spec_boolean ("dual-page",
2319                                                                "Dual Page",
2320                                                                "Two pages visible at once",
2321                                                                FALSE,
2322                                                                G_PARAM_READWRITE));
2323         g_object_class_install_property (object_class,
2324                                          PROP_FULLSCREEN,
2325                                          g_param_spec_boolean ("fullscreen",
2326                                                                "Full Screen",
2327                                                                "Draw page in a fullscreen fashion",
2328                                                                FALSE,
2329                                                                G_PARAM_READWRITE));
2330         g_object_class_install_property (object_class,
2331                                          PROP_PRESENTATION,
2332                                          g_param_spec_boolean ("presentation",
2333                                                                "Presentation",
2334                                                                "Draw page in presentation mode",
2335                                                                TRUE,
2336                                                                G_PARAM_READWRITE));
2337
2338         g_object_class_install_property (object_class,
2339                                          PROP_SIZING_MODE,
2340                                          g_param_spec_enum ("sizing-mode",
2341                                                             "Sizing Mode",
2342                                                             "Sizing Mode",
2343                                                             EV_TYPE_SIZING_MODE,
2344                                                             EV_SIZING_FIT_WIDTH,
2345                                                             G_PARAM_READWRITE));
2346
2347         g_object_class_install_property (object_class,
2348                                          PROP_ZOOM,
2349                                          g_param_spec_double ("zoom",
2350                                                               "Zoom factor",
2351                                                                "Zoom factor",
2352                                                                MIN_SCALE,
2353                                                                MAX_SCALE,
2354                                                                1.0,
2355                                                                G_PARAM_READWRITE));
2356         g_object_class_install_property (object_class,
2357                                          PROP_ROTATION,
2358                                          g_param_spec_double ("rotation",
2359                                                               "Rotation",
2360                                                                "Rotation",
2361                                                                0,
2362                                                                360,
2363                                                                0,
2364                                                                G_PARAM_READWRITE));
2365
2366         binding_set = gtk_binding_set_by_class (class);
2367
2368         add_scroll_binding_keypad (binding_set, GDK_Left,  GTK_SCROLL_STEP_BACKWARD, TRUE);
2369         add_scroll_binding_keypad (binding_set, GDK_Right, GTK_SCROLL_STEP_FORWARD,  TRUE);
2370         add_scroll_binding_keypad (binding_set, GDK_Up,    GTK_SCROLL_STEP_BACKWARD, FALSE);
2371         add_scroll_binding_keypad (binding_set, GDK_Down,  GTK_SCROLL_STEP_FORWARD,  FALSE);
2372 }
2373
2374 static void
2375 ev_view_init (EvView *view)
2376 {
2377         GTK_WIDGET_SET_FLAGS (view, GTK_CAN_FOCUS);
2378
2379         view->spacing = 5;
2380         view->scale = 1.0;
2381         view->current_page = 0;
2382         view->pressed_button = -1;
2383         view->cursor = EV_VIEW_CURSOR_NORMAL;
2384         view->drag_info.in_drag = FALSE;
2385         view->selection_info.in_selection = FALSE;
2386         view->selection_mode = EV_VIEW_SELECTION_TEXT;
2387         view->continuous = TRUE;
2388         view->dual_page = FALSE;
2389         view->presentation = FALSE;
2390         view->fullscreen = FALSE;
2391         view->sizing_mode = EV_SIZING_FIT_WIDTH;
2392         view->pending_scroll = SCROLL_TO_KEEP_POSITION;
2393 }
2394
2395 /*** Callbacks ***/
2396
2397 static void
2398 find_changed_cb (EvDocument *document, int page, EvView *view)
2399 {
2400         jump_to_find_page (view, EV_VIEW_FIND_NEXT);
2401         jump_to_find_result (view);
2402         update_find_status_message (view);
2403
2404         if (view->current_page == page)
2405                 gtk_widget_queue_draw (GTK_WIDGET (view));
2406 }
2407
2408 static void
2409 job_finished_cb (EvPixbufCache *pixbuf_cache,
2410                  EvView        *view)
2411 {
2412         gtk_widget_queue_draw (GTK_WIDGET (view));
2413 }
2414
2415 static void
2416 page_changed_cb (EvPageCache *page_cache,
2417                  int          new_page,
2418                  EvView      *view)
2419 {
2420         if (view->current_page != new_page) {
2421
2422                 view->current_page = new_page;
2423                 view->pending_scroll = SCROLL_TO_CURRENT_PAGE;
2424                 gtk_widget_queue_resize (GTK_WIDGET (view));
2425
2426                 if (EV_IS_DOCUMENT_FIND (view->document)) {
2427                         view->find_page = new_page;
2428                         view->find_result = 0;
2429                         update_find_status_message (view);
2430                 }
2431         }
2432 }
2433
2434 static void on_adjustment_value_changed (GtkAdjustment  *adjustment,
2435                                          EvView *view)
2436 {
2437         int dx = 0, dy = 0;
2438
2439         if (! GTK_WIDGET_REALIZED (view))
2440                 return;
2441
2442         if (view->hadjustment) {
2443                 dx = view->scroll_x - (int) view->hadjustment->value;
2444                 view->scroll_x = (int) view->hadjustment->value;
2445         } else {
2446                 view->scroll_x = 0;
2447         }
2448
2449         if (view->vadjustment) {
2450                 dy = view->scroll_y - (int) view->vadjustment->value;
2451                 view->scroll_y = (int) view->vadjustment->value;
2452         } else {
2453                 view->scroll_y = 0;
2454         }
2455
2456
2457         if (view->pending_resize)
2458                 gtk_widget_queue_draw (GTK_WIDGET (view));
2459         else
2460                 gdk_window_scroll (GTK_WIDGET (view)->window, dx, dy);
2461
2462
2463         if (view->document)
2464                 view_update_range_and_current_page (view);
2465 }
2466
2467 GtkWidget*
2468 ev_view_new (void)
2469 {
2470         GtkWidget *view;
2471
2472         view = g_object_new (EV_TYPE_VIEW, NULL);
2473
2474         return view;
2475 }
2476
2477 static void
2478 setup_caches (EvView *view)
2479 {
2480         view->page_cache = ev_page_cache_get (view->document);
2481         g_signal_connect (view->page_cache, "page-changed", G_CALLBACK (page_changed_cb), view);
2482         view->pixbuf_cache = ev_pixbuf_cache_new (GTK_WIDGET (view), view->document);
2483         g_signal_connect (view->pixbuf_cache, "job-finished", G_CALLBACK (job_finished_cb), view);
2484 }
2485
2486 static void
2487 clear_caches (EvView *view)
2488 {
2489         if (view->pixbuf_cache) {
2490                 g_object_unref (view->pixbuf_cache);
2491                 view->pixbuf_cache = NULL;
2492         }
2493
2494         if (view->page_cache) {
2495                 view->page_cache = NULL;
2496         }
2497 }
2498
2499 void
2500 ev_view_set_document (EvView     *view,
2501                       EvDocument *document)
2502 {
2503         g_return_if_fail (EV_IS_VIEW (view));
2504
2505         if (document != view->document) {
2506                 clear_caches (view);
2507
2508                 if (view->document) {
2509                         g_signal_handlers_disconnect_by_func (view->document,
2510                                                               find_changed_cb,
2511                                                               view);
2512                         g_object_unref (view->document);
2513                         view->page_cache = NULL;
2514
2515                 }
2516
2517                 view->document = document;
2518                 view->find_page = 0;
2519                 view->find_result = 0;
2520
2521                 if (view->document) {
2522                         g_object_ref (view->document);
2523                         if (EV_IS_DOCUMENT_FIND (view->document)) {
2524                                 g_signal_connect (view->document,
2525                                                   "find_changed",
2526                                                   G_CALLBACK (find_changed_cb),
2527                                                   view);
2528                         }
2529
2530                         setup_caches (view);
2531                 }
2532
2533                 gtk_widget_queue_resize (GTK_WIDGET (view));
2534         }
2535 }
2536
2537 /*** Zoom and sizing mode ***/
2538
2539 #define EPSILON 0.0000001
2540 void
2541 ev_view_set_zoom (EvView   *view,
2542                   double    factor,
2543                   gboolean  relative)
2544 {
2545         double scale;
2546
2547         if (relative)
2548                 scale = view->scale * factor;
2549         else
2550                 scale = factor;
2551
2552         scale = CLAMP (scale, MIN_SCALE, MAX_SCALE);
2553
2554         if (ABS (view->scale - scale) < EPSILON)
2555                 return;
2556
2557         view->scale = scale;
2558         view->pending_resize = TRUE;
2559
2560         gtk_widget_queue_resize (GTK_WIDGET (view));
2561
2562         g_object_notify (G_OBJECT (view), "zoom");
2563 }
2564
2565 double
2566 ev_view_get_zoom (EvView *view)
2567 {
2568         return view->scale;
2569 }
2570
2571 gboolean
2572 ev_view_get_continuous (EvView *view)
2573 {
2574         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
2575
2576         return view->continuous;
2577 }
2578
2579 void
2580 ev_view_set_continuous (EvView   *view,
2581                         gboolean  continuous)
2582 {
2583         g_return_if_fail (EV_IS_VIEW (view));
2584
2585         continuous = continuous != FALSE;
2586
2587         if (view->continuous != continuous) {
2588                 view->continuous = continuous;
2589                 view->pending_scroll = SCROLL_TO_CURRENT_PAGE;
2590                 gtk_widget_queue_resize (GTK_WIDGET (view));
2591         }
2592
2593         g_object_notify (G_OBJECT (view), "continuous");
2594 }
2595
2596 gboolean
2597 ev_view_get_dual_page (EvView *view)
2598 {
2599         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
2600
2601         return view->dual_page;
2602 }
2603
2604 void
2605 ev_view_set_dual_page (EvView   *view,
2606                        gboolean  dual_page)
2607 {
2608         g_return_if_fail (EV_IS_VIEW (view));
2609
2610         dual_page = dual_page != FALSE;
2611
2612         if (view->dual_page == dual_page)
2613                 return;
2614
2615         view->pending_scroll = SCROLL_TO_CURRENT_PAGE;
2616         view->dual_page = dual_page;
2617         /* FIXME: if we're keeping the pixbuf cache around, we should extend the
2618          * preload_cache_size to be 2 if dual_page is set.
2619          */
2620         gtk_widget_queue_resize (GTK_WIDGET (view));
2621
2622         g_object_notify (G_OBJECT (view), "dual-page");
2623 }
2624
2625 void
2626 ev_view_set_fullscreen (EvView   *view,
2627                          gboolean  fullscreen)
2628 {
2629         g_return_if_fail (EV_IS_VIEW (view));
2630
2631         fullscreen = fullscreen != FALSE;
2632
2633         if (view->fullscreen == fullscreen) 
2634                 return;
2635                 
2636         view->fullscreen = fullscreen;
2637         gtk_widget_queue_resize (GTK_WIDGET (view));
2638         
2639         g_object_notify (G_OBJECT (view), "fullscreen");
2640 }
2641
2642 gboolean
2643 ev_view_get_fullscreen (EvView *view)
2644 {
2645         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
2646
2647         return view->fullscreen;
2648 }
2649
2650 void
2651 ev_view_set_presentation (EvView   *view,
2652                           gboolean  presentation)
2653 {
2654         g_return_if_fail (EV_IS_VIEW (view));
2655
2656         presentation = presentation != FALSE;
2657
2658         if (view->presentation == presentation)
2659                 return;
2660
2661         view->presentation = presentation;
2662         view->pending_scroll = SCROLL_TO_CURRENT_PAGE;
2663         gtk_widget_queue_resize (GTK_WIDGET (view));
2664
2665         if (GTK_WIDGET_REALIZED (view)) {
2666                 if (view->presentation)
2667                         gdk_window_set_background (GTK_WIDGET(view)->window,
2668                                                    &GTK_WIDGET (view)->style->black);
2669                 else
2670                         gdk_window_set_background (GTK_WIDGET(view)->window,
2671                                                    &GTK_WIDGET (view)->style->mid [GTK_STATE_NORMAL]);
2672         }
2673
2674
2675         g_object_notify (G_OBJECT (view), "presentation");
2676 }
2677
2678 gboolean
2679 ev_view_get_presentation (EvView *view)
2680 {
2681         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
2682
2683         return view->presentation;
2684 }
2685
2686 void
2687 ev_view_set_sizing_mode (EvView       *view,
2688                          EvSizingMode  sizing_mode)
2689 {
2690         g_return_if_fail (EV_IS_VIEW (view));
2691
2692         if (view->sizing_mode == sizing_mode)
2693                 return;
2694
2695         view->sizing_mode = sizing_mode;
2696         gtk_widget_queue_resize (GTK_WIDGET (view));
2697
2698         g_object_notify (G_OBJECT (view), "sizing-mode");
2699 }
2700
2701 EvSizingMode
2702 ev_view_get_sizing_mode (EvView *view)
2703 {
2704         g_return_val_if_fail (EV_IS_VIEW (view), EV_SIZING_FREE);
2705
2706         return view->sizing_mode;
2707 }
2708
2709 gboolean
2710 ev_view_can_zoom_in (EvView *view)
2711 {
2712         return view->scale * ZOOM_IN_FACTOR <= MAX_SCALE;
2713 }
2714
2715 gboolean
2716 ev_view_can_zoom_out (EvView *view)
2717 {
2718         return view->scale * ZOOM_OUT_FACTOR >= MIN_SCALE;
2719 }
2720
2721 void
2722 ev_view_zoom_in (EvView *view)
2723 {
2724         g_return_if_fail (view->sizing_mode == EV_SIZING_FREE);
2725
2726         view->pending_scroll = SCROLL_TO_CENTER;
2727         ev_view_set_zoom (view, ZOOM_IN_FACTOR, TRUE);
2728 }
2729
2730 void
2731 ev_view_zoom_out (EvView *view)
2732 {
2733         g_return_if_fail (view->sizing_mode == EV_SIZING_FREE);
2734
2735         view->pending_scroll = SCROLL_TO_CENTER;
2736         ev_view_set_zoom (view, ZOOM_OUT_FACTOR, TRUE);
2737 }
2738
2739 void
2740 ev_view_rotate_right (EvView *view)
2741 {
2742         int rotation = view->rotation + 90;
2743
2744         if (rotation >= 360) {
2745                 rotation -= 360;
2746         }
2747
2748         ev_view_set_rotation (view, rotation);
2749 }
2750
2751 void
2752 ev_view_rotate_left (EvView *view)
2753 {
2754         int rotation = view->rotation - 90;
2755
2756         if (rotation < 0) {
2757                 rotation += 360;
2758         }
2759
2760         ev_view_set_rotation (view, rotation);
2761 }
2762
2763 void
2764 ev_view_set_rotation (EvView *view, int rotation)
2765 {
2766         view->rotation = rotation;
2767
2768         if (view->pixbuf_cache) {
2769                 ev_pixbuf_cache_clear (view->pixbuf_cache);
2770                 gtk_widget_queue_resize (GTK_WIDGET (view));
2771         }
2772
2773         if (rotation != 0)
2774                 clear_selection (view);
2775
2776         g_object_notify (G_OBJECT (view), "rotation");
2777 }
2778
2779 int
2780 ev_view_get_rotation (EvView *view)
2781 {
2782         return view->rotation;
2783 }
2784
2785 static double
2786 zoom_for_size_fit_width (int doc_width,
2787                          int doc_height,
2788                          int target_width,
2789                          int target_height,
2790                          int vsb_width)
2791 {
2792         double scale;
2793
2794         scale = (double)target_width / doc_width;
2795
2796         if (doc_height * scale > target_height)
2797                 scale = (double) (target_width - vsb_width) / doc_width;
2798
2799         return scale;
2800 }
2801
2802 static double
2803 zoom_for_size_fit_height (int doc_width,
2804                           int doc_height,
2805                           int target_width,
2806                           int target_height,
2807                           int vsb_height)
2808 {
2809         double scale;
2810
2811         scale = (double)target_height / doc_height;
2812
2813         if (doc_width * scale > target_width)
2814                 scale = (double) (target_height - vsb_height) / doc_height;
2815
2816         return scale;
2817 }
2818
2819 static double
2820 zoom_for_size_best_fit (int doc_width,
2821                         int doc_height,
2822                         int target_width,
2823                         int target_height,
2824                         int vsb_width,
2825                         int hsb_width)
2826 {
2827         double w_scale;
2828         double h_scale;
2829
2830         w_scale = (double)target_width / doc_width;
2831         h_scale = (double)target_height / doc_height;
2832
2833         if (doc_height * w_scale > target_height)
2834                 w_scale = (double) (target_width - vsb_width) / doc_width;
2835         if (doc_width * h_scale > target_width)
2836                 h_scale = (double) (target_height - hsb_width) / doc_height;
2837
2838         return MIN (w_scale, h_scale);
2839 }
2840
2841
2842 static void
2843 ev_view_zoom_for_size_presentation (EvView *view,
2844                                     int     width,
2845                                     int     height)
2846 {
2847         int doc_width, doc_height;
2848         gdouble scale;
2849
2850         ev_page_cache_get_size (view->page_cache,
2851                                 view->current_page,
2852                                 view->rotation,
2853                                 1.0,
2854                                 &doc_width,
2855                                 &doc_height);
2856         scale = zoom_for_size_best_fit (doc_width, doc_height, width, height, 0, 0);
2857         ev_view_set_zoom (view, scale, FALSE);
2858 }
2859
2860 static void
2861 ev_view_zoom_for_size_continuous_and_dual_page (EvView *view,
2862                            int     width,
2863                            int     height,
2864                            int     vsb_width,
2865                            int     hsb_height)
2866 {
2867         int doc_width, doc_height;
2868         GtkBorder border;
2869         gdouble scale;
2870
2871         ev_page_cache_get_max_width (view->page_cache,
2872                                      view->rotation,
2873                                      1.0,
2874                                      &doc_width);
2875         ev_page_cache_get_max_height (view->page_cache,
2876                                       view->rotation,
2877                                       1.0,
2878                                       &doc_height);
2879         compute_border (view, doc_width, doc_height, &border);
2880
2881         doc_width = doc_width * 2;
2882         width -= (2 * (border.left + border.right) + 3 * view->spacing);
2883         height -= (border.top + border.bottom + 2 * view->spacing - 1);
2884
2885         /* FIXME: We really need to calculate the overall height here, not the
2886          * page height.  We assume there's always a vertical scrollbar for
2887          * now.  We need to fix this. */
2888         if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
2889                 scale = zoom_for_size_fit_width (doc_width, doc_height, width - vsb_width, height, 0);
2890         else if (view->sizing_mode == EV_SIZING_BEST_FIT)
2891                 scale = zoom_for_size_best_fit (doc_width, doc_height, width - vsb_width, height, 0, hsb_height);
2892         else
2893                 g_assert_not_reached ();
2894
2895         ev_view_set_zoom (view, scale, FALSE);
2896 }
2897
2898 static void
2899 ev_view_zoom_for_size_continuous (EvView *view,
2900                                   int     width,
2901                                   int     height,
2902                                   int     vsb_width,
2903                                   int     hsb_height)
2904 {
2905         int doc_width, doc_height;
2906         GtkBorder border;
2907         gdouble scale;
2908
2909         ev_page_cache_get_max_width (view->page_cache,
2910                                      view->rotation,
2911                                      1.0,
2912                                      &doc_width);
2913         ev_page_cache_get_max_height (view->page_cache,
2914                                       view->rotation,
2915                                       1.0,
2916                                       &doc_height);
2917         compute_border (view, doc_width, doc_height, &border);
2918
2919         width -= (border.left + border.right + 2 * view->spacing);
2920         height -= (border.top + border.bottom + 2 * view->spacing - 1);
2921
2922         /* FIXME: We really need to calculate the overall height here, not the
2923          * page height.  We assume there's always a vertical scrollbar for
2924          * now.  We need to fix this. */
2925         if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
2926                 scale = zoom_for_size_fit_width (doc_width, doc_height, width - vsb_width, height, 0);
2927         else if (view->sizing_mode == EV_SIZING_BEST_FIT)
2928                 scale = zoom_for_size_best_fit (doc_width, doc_height, width - vsb_width, height, 0, hsb_height);
2929         else
2930                 g_assert_not_reached ();
2931
2932         ev_view_set_zoom (view, scale, FALSE);
2933 }
2934
2935 static void
2936 ev_view_zoom_for_size_dual_page (EvView *view,
2937                                  int     width,
2938                                  int     height,
2939                                  int     vsb_width,
2940                                  int     hsb_height)
2941 {
2942         GtkBorder border;
2943         gint doc_width, doc_height;
2944         gdouble scale;
2945         gint other_page;
2946
2947         other_page = view->current_page ^ 1;
2948
2949         /* Find the largest of the two. */
2950         ev_page_cache_get_size (view->page_cache,
2951                                 view->current_page,
2952                                 view->rotation,
2953                                 1.0,
2954                                 &doc_width, &doc_height);
2955
2956         if (other_page < ev_page_cache_get_n_pages (view->page_cache)) {
2957                 gint width_2, height_2;
2958                 ev_page_cache_get_size (view->page_cache,
2959                                         other_page,
2960                                         view->rotation,
2961                                         1.0,
2962                                         &width_2, &height_2);
2963                 if (width_2 > doc_width)
2964                         doc_width = width_2;
2965                 if (height_2 > doc_height)
2966                         doc_height = height_2;
2967         }
2968         compute_border (view, doc_width, doc_height, &border);
2969
2970         doc_width = doc_width * 2;
2971         width -= ((border.left + border.right)* 2 + 3 * view->spacing);
2972         height -= (border.top + border.bottom + 2 * view->spacing);
2973
2974         if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
2975                 scale = zoom_for_size_fit_width (doc_width, doc_height, width, height, vsb_width);
2976         else if (view->sizing_mode == EV_SIZING_BEST_FIT)
2977                 scale = zoom_for_size_best_fit (doc_width, doc_height, width, height, vsb_width, hsb_height);
2978         else
2979                 g_assert_not_reached ();
2980
2981         ev_view_set_zoom (view, scale, FALSE);
2982 }
2983
2984 static void
2985 ev_view_zoom_for_size_single_page (EvView *view,
2986                                    int     width,
2987                                    int     height,
2988                                    int     vsb_width,
2989                                    int     hsb_height)
2990 {
2991         int doc_width, doc_height;
2992         GtkBorder border;
2993         gdouble scale;
2994
2995         ev_page_cache_get_size (view->page_cache,
2996                                 view->current_page,
2997                                 view->rotation,
2998                                 1.0,
2999                                 &doc_width,
3000                                 &doc_height);
3001         /* Get an approximate border */
3002         compute_border (view, width, height, &border);
3003
3004         width -= (border.left + border.right + 2 * view->spacing);
3005         height -= (border.top + border.bottom + 2 * view->spacing);
3006
3007         if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
3008                 scale = zoom_for_size_fit_width (doc_width, doc_height, width, height, vsb_width);
3009         else if (view->sizing_mode == EV_SIZING_BEST_FIT)
3010                 scale = zoom_for_size_best_fit (doc_width, doc_height, width, height, vsb_width, hsb_height);
3011         else
3012                 g_assert_not_reached ();
3013
3014         ev_view_set_zoom (view, scale, FALSE);
3015 }
3016
3017 void
3018 ev_view_set_zoom_for_size (EvView *view,
3019                            int     width,
3020                            int     height,
3021                            int     vsb_width,
3022                            int     hsb_height)
3023 {
3024         g_return_if_fail (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
3025                           view->sizing_mode == EV_SIZING_BEST_FIT);
3026         g_return_if_fail (width >= 0);
3027         g_return_if_fail (height >= 0);
3028
3029         if (view->document == NULL)
3030                 return;
3031
3032         if (view->presentation)
3033                 ev_view_zoom_for_size_presentation (view, width, height);
3034         else if (view->continuous && view->dual_page)
3035                 ev_view_zoom_for_size_continuous_and_dual_page (view, width, height, vsb_width, hsb_height);
3036         else if (view->continuous)
3037                 ev_view_zoom_for_size_continuous (view, width, height, vsb_width, hsb_height);
3038         else if (view->dual_page)
3039                 ev_view_zoom_for_size_dual_page (view, width, height, vsb_width, hsb_height);
3040         else
3041                 ev_view_zoom_for_size_single_page (view, width, height, vsb_width, hsb_height);
3042 }
3043
3044 /*** Status text messages ***/
3045
3046 const char *
3047 ev_view_get_status (EvView *view)
3048 {
3049         g_return_val_if_fail (EV_IS_VIEW (view), NULL);
3050
3051         return view->status;
3052 }
3053
3054 static void
3055 ev_view_set_status (EvView *view, const char *message)
3056 {
3057         g_return_if_fail (EV_IS_VIEW (view));
3058
3059         if (message != view->status) {
3060                 g_free (view->status);
3061                 view->status = g_strdup (message);
3062                 g_object_notify (G_OBJECT (view), "status");
3063         }
3064 }
3065
3066 static void
3067 update_find_status_message (EvView *view)
3068 {
3069         char *message;
3070
3071         if (view->current_page == view->find_page) {
3072                 int results;
3073
3074                 results = ev_document_find_get_n_results
3075                                 (EV_DOCUMENT_FIND (view->document),
3076                                  view->current_page);
3077                 /* TRANS: Sometimes this could be better translated as
3078                    "%d hit(s) on this page".  Therefore this string
3079                    contains plural cases. */
3080                 message = g_strdup_printf (ngettext ("%d found on this page",
3081                                                      "%d found on this page",
3082                                                      results),
3083                                            results);
3084         } else {
3085                 double percent;
3086
3087                 percent = ev_document_find_get_progress
3088                                 (EV_DOCUMENT_FIND (view->document));
3089                 if (percent >= (1.0 - 1e-10)) {
3090                         message = g_strdup (_("Not found"));
3091                 } else {
3092                         message = g_strdup_printf (_("%3d%% remaining to search"),
3093                                                    (int) ((1.0 - percent) * 100));
3094                 }
3095
3096         }
3097         ev_view_set_find_status (view, message);
3098         g_free (message);
3099 }
3100
3101 const char *
3102 ev_view_get_find_status (EvView *view)
3103 {
3104         g_return_val_if_fail (EV_IS_VIEW (view), NULL);
3105
3106         return view->find_status;
3107 }
3108
3109 static void
3110 ev_view_set_find_status (EvView *view, const char *message)
3111 {
3112         g_return_if_fail (EV_IS_VIEW (view));
3113
3114         g_free (view->find_status);
3115         view->find_status = g_strdup (message);
3116         g_object_notify (G_OBJECT (view), "find-status");
3117 }
3118
3119 /*** Find ***/
3120
3121 static void
3122 jump_to_find_result (EvView *view)
3123 {
3124         EvDocumentFind *find = EV_DOCUMENT_FIND (view->document);
3125         EvRectangle rect;
3126         GdkRectangle view_rect;
3127         int n_results;
3128         int page = view->find_page;
3129
3130         n_results = ev_document_find_get_n_results (find, page);
3131
3132         if (n_results > 0  && view->find_result < n_results) {
3133                 ev_document_find_get_result
3134                         (find, page, view->find_result, &rect);
3135
3136                 doc_rect_to_view_rect (view, page, &rect, &view_rect);
3137                 ensure_rectangle_is_visible (view, &view_rect);
3138         }
3139 }
3140
3141 static void
3142 jump_to_find_page (EvView *view, EvViewFindDirection direction)
3143 {
3144         int n_pages, i;
3145
3146         n_pages = ev_page_cache_get_n_pages (view->page_cache);
3147
3148         for (i = 0; i < n_pages; i++) {
3149                 int has_results;
3150                 int page;
3151                 
3152                 if (direction == EV_VIEW_FIND_NEXT)
3153                         page = view->find_page + i;
3154                 else
3155                         page = view->find_page - i;
3156
3157
3158                 if (page >= n_pages) {
3159                         page = page - n_pages;
3160                 }
3161                 if (page < 0) 
3162                         page = page + n_pages;
3163                 
3164                 has_results = ev_document_find_page_has_results
3165                                 (EV_DOCUMENT_FIND (view->document), page);
3166                 if (has_results == -1) {
3167                         view->find_page = page;
3168                         break;
3169                 } else if (has_results == 1) {
3170                         ev_page_cache_set_current_page (view->page_cache, page);
3171                         break;
3172                 }
3173         }
3174 }
3175
3176 gboolean
3177 ev_view_can_find_next (EvView *view)
3178 {
3179         if (EV_IS_DOCUMENT_FIND (view->document)) {
3180                 EvDocumentFind *find = EV_DOCUMENT_FIND (view->document);
3181                 int i, n_pages;
3182
3183                 n_pages = ev_page_cache_get_n_pages (view->page_cache);
3184                 for (i = 0; i < n_pages; i++) {
3185                         if (ev_document_find_get_n_results (find, i) > 0) {
3186                                 return TRUE;
3187                         }
3188                 }
3189         }
3190
3191         return FALSE;
3192 }
3193
3194 void
3195 ev_view_find_next (EvView *view)
3196 {
3197         int n_results, n_pages;
3198         EvDocumentFind *find = EV_DOCUMENT_FIND (view->document);
3199
3200         n_results = ev_document_find_get_n_results (find, view->current_page);
3201
3202         n_pages = ev_page_cache_get_n_pages (view->page_cache);
3203
3204         view->find_result++;
3205
3206         if (view->find_result >= n_results) {
3207
3208                 view->find_result = 0;
3209                 view->find_page++;
3210                 if (view->find_page >= n_pages) {
3211                         view->find_page = 0;
3212                 }
3213
3214                 jump_to_find_page (view, EV_VIEW_FIND_NEXT);
3215                 jump_to_find_result (view);
3216         } else {
3217                 jump_to_find_result (view);
3218                 gtk_widget_queue_draw (GTK_WIDGET (view));
3219         }
3220 }
3221
3222 void
3223 ev_view_find_previous (EvView *view)
3224 {
3225         int n_results, n_pages;
3226         EvDocumentFind *find = EV_DOCUMENT_FIND (view->document);
3227         EvPageCache *page_cache;
3228
3229         page_cache = ev_page_cache_get (view->document);
3230
3231         n_results = ev_document_find_get_n_results (find, view->current_page);
3232
3233         n_pages = ev_page_cache_get_n_pages (page_cache);
3234
3235         view->find_result--;
3236
3237         if (view->find_result < 0) {
3238
3239                 view->find_page--;
3240                 if (view->find_page < 0) {
3241                         view->find_page = n_pages - 1;
3242                 }
3243
3244                 jump_to_find_page (view, EV_VIEW_FIND_PREV);
3245                 view->find_result = ev_document_find_get_n_results (find, view->current_page) - 1;
3246                 jump_to_find_result (view);
3247         } else {
3248                 jump_to_find_result (view);
3249                 gtk_widget_queue_draw (GTK_WIDGET (view));
3250         }
3251 }
3252
3253 /*** Selections ***/
3254
3255 /* compute_new_selection_rect/text calculates the area currently selected by
3256  * view_rect.  each handles a different mode;
3257  */
3258 static GList *
3259 compute_new_selection_rect (EvView       *view,
3260                             GdkPoint     *start,
3261                             GdkPoint     *stop)
3262 {
3263         GdkRectangle view_rect;
3264         int n_pages, i;
3265         GList *list = NULL;
3266
3267         g_assert (view->selection_mode == EV_VIEW_SELECTION_RECTANGLE);
3268         
3269         view_rect.x = MIN (start->x, stop->x);
3270         view_rect.y = MIN (start->y, stop->y);
3271         view_rect.width = MAX (start->x, stop->x) - view_rect.x;
3272         view_rect.width = MAX (start->y, stop->y) - view_rect.y;
3273
3274         n_pages = ev_page_cache_get_n_pages (view->page_cache);
3275
3276         for (i = 0; i < n_pages; i++) {
3277                 GdkRectangle page_area;
3278                 GtkBorder border;
3279                 
3280                 if (get_page_extents (view, i, &page_area, &border)) {
3281                         GdkRectangle overlap;
3282
3283                         if (gdk_rectangle_intersect (&page_area, &view_rect, &overlap)) {
3284                                 EvViewSelection *selection;
3285
3286                                 selection = g_new0 (EvViewSelection, 1);
3287                                 selection->page = i;
3288                                 view_rect_to_doc_rect (view, &overlap, &page_area,
3289                                                        &(selection->rect));
3290
3291                                 list = g_list_append (list, selection);
3292                         }
3293                 }
3294         }
3295
3296         return list;
3297 }
3298
3299 static gboolean
3300 gdk_rectangle_point_in (GdkRectangle *rectangle,
3301                         GdkPoint     *point)
3302 {
3303         return rectangle->x <= point->x &&
3304                 rectangle->y <= point->y &&
3305                 point->x < rectangle->x + rectangle->width &&
3306                 point->y < rectangle->y + rectangle->height;
3307 }
3308
3309 static GList *
3310 compute_new_selection_text (EvView   *view,
3311                             GdkPoint *start,
3312                             GdkPoint *stop)
3313 {
3314         int n_pages, i, first, last;
3315         GList *list = NULL;
3316         EvViewSelection *selection;
3317         gint width, height;
3318         int start_page, end_page;
3319
3320         g_assert (view->selection_mode == EV_VIEW_SELECTION_TEXT);
3321
3322         n_pages = ev_page_cache_get_n_pages (view->page_cache);
3323
3324         /* First figure out the range of pages the selection
3325          * affects. */
3326         first = n_pages;
3327         last = 0;
3328         if (view->continuous) {
3329                 start_page = 0;
3330                 end_page = n_pages;
3331         } else if (view->dual_page) {
3332                 start_page = view->start_page;
3333                 end_page = view->end_page + 1;
3334         } else {
3335                 start_page = view->current_page;
3336                 end_page = view->current_page + 1;
3337         }
3338
3339         for (i = start_page; i < end_page; i++) {
3340                 GdkRectangle page_area;
3341                 GtkBorder border;
3342                 
3343                 get_page_extents (view, i, &page_area, &border);
3344                 if (gdk_rectangle_point_in (&page_area, start) || 
3345                     gdk_rectangle_point_in (&page_area, stop)) {
3346                         if (first == n_pages)
3347                                 first = i;
3348                         last = i;
3349                 }
3350
3351         }
3352
3353
3354
3355         /* Now create a list of EvViewSelection's for the affected
3356          * pages.  This could be an empty list, a list of just one
3357          * page or a number of pages.*/
3358         for (i = first; i < last + 1; i++) {
3359                 GdkRectangle page_area;
3360                 GtkBorder border;
3361                 GdkPoint *point;
3362
3363                 ev_page_cache_get_size (view->page_cache, i,
3364                                         view->rotation,
3365                                         1.0, &width, &height);
3366
3367                 selection = g_new0 (EvViewSelection, 1);
3368                 selection->page = i;
3369                 selection->rect.x1 = selection->rect.y1 = 0;
3370                 selection->rect.x2 = width;
3371                 selection->rect.y2 = height;
3372
3373                 get_page_extents (view, i, &page_area, &border);
3374
3375                 if (gdk_rectangle_point_in (&page_area, start))
3376                         point = start;
3377                 else
3378                         point = stop;
3379
3380                 if (i == first)
3381                         view_point_to_doc_point (view, point, &page_area,
3382                                                  &selection->rect.x1,
3383                                                  &selection->rect.y1);
3384
3385                 /* If the selection is contained within just one page,
3386                  * make sure we don't write 'start' into both points
3387                  * in selection->rect. */
3388                 if (first == last)
3389                         point = stop;
3390
3391                 if (i == last)
3392                         view_point_to_doc_point (view, point, &page_area,
3393                                                  &selection->rect.x2,
3394                                                  &selection->rect.y2);
3395
3396                 list = g_list_append (list, selection);
3397         }
3398
3399         return list;
3400 }
3401
3402 /* This function takes the newly calculated list, and figures out which regions
3403  * have changed.  It then queues a redraw approporiately.
3404  */
3405 static void
3406 merge_selection_region (EvView *view,
3407                         GList  *new_list)
3408 {
3409         GList *old_list;
3410         GList *new_list_ptr, *old_list_ptr;
3411
3412         /* Update the selection */
3413         old_list = ev_pixbuf_cache_get_selection_list (view->pixbuf_cache);
3414         g_list_foreach (view->selection_info.selections, (GFunc)selection_free, NULL);
3415         view->selection_info.selections = new_list;
3416         ev_pixbuf_cache_set_selection_list (view->pixbuf_cache, new_list);
3417
3418         new_list_ptr = new_list;
3419         old_list_ptr = old_list;
3420
3421         while (new_list_ptr || old_list_ptr) {
3422                 EvViewSelection *old_sel, *new_sel;
3423                 int cur_page;
3424                 GdkRegion *region = NULL;
3425
3426                 new_sel = (new_list_ptr) ? (new_list_ptr->data) : NULL;
3427                 old_sel = (old_list_ptr) ? (old_list_ptr->data) : NULL;
3428
3429                 /* Assume that the lists are in order, and we run through them
3430                  * comparing them, one page at a time.  We come out with the
3431                  * first page we see. */
3432                 if (new_sel && old_sel) {
3433                         if (new_sel->page < old_sel->page) {
3434                                 new_list_ptr = new_list_ptr->next;
3435                                 old_sel = NULL;
3436                         } else if (new_sel->page > old_sel->page) {
3437                                 old_list_ptr = old_list_ptr->next;
3438                                 new_sel = NULL;
3439                         } else {
3440                                 new_list_ptr = new_list_ptr->next;
3441                                 old_list_ptr = old_list_ptr->next;
3442                         }
3443                 } else if (new_sel) {
3444                         new_list_ptr = new_list_ptr->next;
3445                 } else if (old_sel) {
3446                         old_list_ptr = old_list_ptr->next;
3447                 }
3448
3449                 g_assert (new_sel || old_sel);
3450
3451                 /* is the page we're looking at on the screen?*/
3452                 cur_page = new_sel ? new_sel->page : old_sel->page;
3453                 if (cur_page < view->start_page || cur_page > view->end_page)
3454                         continue;
3455
3456                 /* seed the cache with a new page.  We are going to need the new
3457                  * region too. */
3458                 if (new_sel) {
3459                         GdkRegion *tmp_region = NULL;
3460                         ev_pixbuf_cache_get_selection_pixbuf (view->pixbuf_cache,
3461                                                               cur_page,
3462                                                               view->scale,
3463                                                               &tmp_region);
3464                         if (tmp_region) {
3465                                 new_sel->covered_region = gdk_region_copy (tmp_region);
3466                         }
3467                 }
3468
3469                 /* Now we figure out what needs redrawing */
3470                 if (old_sel && new_sel) {
3471                         if (old_sel->covered_region &&
3472                             new_sel->covered_region) {
3473                                 /* We only want to redraw the areas that have
3474                                  * changed, so we xor the old and new regions
3475                                  * and redraw if it's different */
3476                                 region = gdk_region_copy (old_sel->covered_region);
3477                                 gdk_region_xor (region, new_sel->covered_region);
3478                                 if (gdk_region_empty (region)) {
3479                                         gdk_region_destroy (region);
3480                                         region = NULL;
3481                                 }
3482                         } else if (old_sel->covered_region) {
3483                                 region = gdk_region_copy (old_sel->covered_region);
3484                         } else if (new_sel->covered_region) {
3485                                 region = gdk_region_copy (new_sel->covered_region);
3486                         }
3487                 } else if (old_sel && !new_sel) {
3488                         if (old_sel->covered_region && !gdk_region_empty (old_sel->covered_region)) {
3489                                 region = gdk_region_copy (old_sel->covered_region);
3490                         }
3491                 } else if (!old_sel && new_sel) {
3492                         if (new_sel->covered_region && !gdk_region_empty (new_sel->covered_region)) {
3493                                 region = gdk_region_copy (new_sel->covered_region);
3494                         }
3495                 } else {
3496                         g_assert_not_reached ();
3497                 }
3498
3499                 /* Redraw the damaged region! */
3500                 if (region) {
3501                         GdkRectangle page_area;
3502                         GtkBorder border;
3503
3504                         get_page_extents (view, cur_page, &page_area, &border);
3505                         gdk_region_offset (region,
3506                                            page_area.x + border.left - view->scroll_x,
3507                                            page_area.y + border.top - view->scroll_y);
3508                         gdk_window_invalidate_region (GTK_WIDGET (view)->window, region, TRUE);
3509                         gdk_region_destroy (region);
3510                 }
3511         }
3512
3513         /* Free the old list, now that we're done with it. */
3514         g_list_foreach (old_list, (GFunc) selection_free, NULL);
3515 }
3516
3517 static void
3518 compute_selections (EvView   *view,
3519                     GdkPoint *start,
3520                     GdkPoint *stop)
3521 {
3522         GList *list;
3523
3524         if (view->selection_mode == EV_VIEW_SELECTION_RECTANGLE)
3525                 list = compute_new_selection_rect (view, start, stop);
3526         else
3527                 list = compute_new_selection_text (view, start, stop);
3528         merge_selection_region (view, list);
3529 }
3530
3531 /* Free's the selection.  It's up to the caller to queue redraws if needed.
3532  */
3533 static void
3534 selection_free (EvViewSelection *selection)
3535 {
3536         if (selection->covered_region)
3537                 gdk_region_destroy (selection->covered_region);
3538         g_free (selection);
3539 }
3540
3541 static void
3542 clear_selection (EvView *view)
3543 {
3544         g_list_foreach (view->selection_info.selections, (GFunc)selection_free, NULL);
3545         view->selection_info.selections = NULL;
3546         view->selection_info.in_selection = FALSE;
3547 }
3548
3549
3550 void
3551 ev_view_select_all (EvView *view)
3552 {
3553         int n_pages, i;
3554
3555         /* Disable selection on rotated pages for the 0.4.0 series */
3556         if (view->rotation != 0)
3557                 return;
3558
3559         clear_selection (view);
3560
3561         n_pages = ev_page_cache_get_n_pages (view->page_cache);
3562         for (i = 0; i < n_pages; i++) {
3563                 int width, height;
3564                 EvViewSelection *selection;
3565
3566                 ev_page_cache_get_size (view->page_cache,
3567                                         i,
3568                                         view->rotation,
3569                                         1.0, &width, &height);
3570
3571                 selection = g_new0 (EvViewSelection, 1);
3572                 selection->page = i;
3573                 selection->rect.x1 = selection->rect.y1 = 0;
3574                 selection->rect.x2 = width;
3575                 selection->rect.y2 = height;
3576
3577                 view->selection_info.selections = g_list_append (view->selection_info.selections, selection);
3578         }
3579
3580         ev_pixbuf_cache_set_selection_list (view->pixbuf_cache, view->selection_info.selections);
3581         gtk_widget_queue_draw (GTK_WIDGET (view));
3582 }
3583
3584 static char *
3585 get_selected_text (EvView *ev_view)
3586 {
3587         GString *text;
3588         GList *l;
3589
3590         text = g_string_new (NULL);
3591
3592         ev_document_doc_mutex_lock ();
3593
3594         for (l = ev_view->selection_info.selections; l != NULL; l = l->next) {
3595                 EvViewSelection *selection = (EvViewSelection *)l->data;
3596                 char *tmp;
3597
3598                 tmp = ev_document_get_text (ev_view->document,
3599                                             selection->page,
3600                                             &selection->rect);
3601                 g_string_append (text, tmp);
3602                 g_free (tmp);
3603         }
3604
3605         ev_document_doc_mutex_unlock ();
3606
3607         return g_string_free (text, FALSE);
3608 }
3609
3610 void
3611 ev_view_copy (EvView *ev_view)
3612 {
3613         GtkClipboard *clipboard;
3614         char *text;
3615
3616         if (!ev_document_can_get_text (ev_view->document)) {
3617                 return;
3618         }
3619
3620         text = get_selected_text (ev_view);
3621         clipboard = gtk_widget_get_clipboard (GTK_WIDGET (ev_view),
3622                                               GDK_SELECTION_CLIPBOARD);
3623         gtk_clipboard_set_text (clipboard, text, -1);
3624         g_free (text);
3625 }
3626
3627 static void
3628 ev_view_primary_get_cb (GtkClipboard     *clipboard,
3629                         GtkSelectionData *selection_data,
3630                         guint             info,
3631                         gpointer          data)
3632 {
3633         EvView *ev_view = EV_VIEW (data);
3634         char *text;
3635
3636         if (!ev_document_can_get_text (ev_view->document)) {
3637                 return;
3638         }
3639
3640         text = get_selected_text (ev_view);
3641         gtk_selection_data_set_text (selection_data, text, -1);
3642         g_free (text);
3643 }
3644
3645 static void
3646 ev_view_primary_clear_cb (GtkClipboard *clipboard,
3647                           gpointer      data)
3648 {
3649         EvView *view = EV_VIEW (data);
3650
3651         clear_selection (view);
3652 }
3653
3654 static void
3655 ev_view_update_primary_selection (EvView *ev_view)
3656 {
3657         GtkClipboard *clipboard;
3658
3659         clipboard = gtk_widget_get_clipboard (GTK_WIDGET (ev_view),
3660                                               GDK_SELECTION_PRIMARY);
3661
3662         if (ev_view->selection_info.selections) {
3663                 if (!gtk_clipboard_set_with_owner (clipboard,
3664                                                    targets,
3665                                                    G_N_ELEMENTS (targets),
3666                                                    ev_view_primary_get_cb,
3667                                                    ev_view_primary_clear_cb,
3668                                                    G_OBJECT (ev_view)))
3669                         ev_view_primary_clear_cb (clipboard, ev_view);
3670         } else {
3671                 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (ev_view))
3672                         gtk_clipboard_clear (clipboard);
3673         }
3674 }
3675
3676 /*** Cursor operations ***/
3677
3678 static GdkCursor *
3679 ev_view_create_invisible_cursor(void)
3680 {
3681        GdkBitmap *empty;
3682        GdkColor black = { 0, 0, 0, 0 };
3683        static char bits[] = { 0x00 };
3684
3685        empty = gdk_bitmap_create_from_data (NULL, bits, 1, 1);
3686
3687        return gdk_cursor_new_from_pixmap (empty, empty, &black, &black, 0, 0);
3688 }
3689
3690 static void
3691 ev_view_set_cursor (EvView *view, EvViewCursor new_cursor)
3692 {
3693         GdkCursor *cursor = NULL;
3694         GdkDisplay *display;
3695         GtkWidget *widget;
3696
3697         if (view->cursor == new_cursor) {
3698                 return;
3699         }
3700
3701         widget = gtk_widget_get_toplevel (GTK_WIDGET (view));
3702         display = gtk_widget_get_display (widget);
3703         view->cursor = new_cursor;
3704
3705         switch (new_cursor) {
3706                 case EV_VIEW_CURSOR_NORMAL:
3707                         gdk_window_set_cursor (widget->window, NULL);
3708                         break;
3709                 case EV_VIEW_CURSOR_IBEAM:
3710                         cursor = gdk_cursor_new_for_display (display, GDK_XTERM);
3711                         break;
3712                 case EV_VIEW_CURSOR_LINK:
3713                         cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
3714                         break;
3715                 case EV_VIEW_CURSOR_WAIT:
3716                         cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
3717                         break;
3718                 case EV_VIEW_CURSOR_HIDDEN:
3719                         cursor = ev_view_create_invisible_cursor ();
3720                         break;
3721                 case EV_VIEW_CURSOR_DRAG:
3722                         cursor = gdk_cursor_new_for_display (display, GDK_FLEUR);
3723                         break;
3724         }
3725
3726         if (cursor) {
3727                 gdk_window_set_cursor (widget->window, cursor);
3728                 gdk_cursor_unref (cursor);
3729                 gdk_flush();
3730         }
3731 }
3732
3733 void
3734 ev_view_hide_cursor (EvView *view)
3735 {
3736        ev_view_set_cursor (view, EV_VIEW_CURSOR_HIDDEN);
3737 }
3738
3739 void
3740 ev_view_show_cursor (EvView *view)
3741 {
3742        ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
3743 }
3744
3745 gboolean
3746 ev_view_next_page (EvView *view)
3747 {
3748         int page;
3749
3750         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
3751
3752         page = ev_page_cache_get_current_page (view->page_cache);
3753         page = ev_view_get_dual_page (view) ? page + 2 : page + 1;
3754
3755         if (page < ev_page_cache_get_n_pages (view->page_cache)) {
3756                 ev_page_cache_set_current_page (view->page_cache, page);
3757                 return TRUE;
3758         } else {
3759                 return FALSE;
3760         }
3761 }
3762
3763 gboolean
3764 ev_view_previous_page (EvView *view)
3765 {
3766         int page;
3767
3768         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
3769
3770         page = ev_page_cache_get_current_page (view->page_cache);
3771         page = ev_view_get_dual_page (view) ? page - 2 : page - 1;
3772
3773         if (page >= 0) {
3774                 ev_page_cache_set_current_page (view->page_cache, page);
3775                 return TRUE;
3776         } else {
3777                 return FALSE;
3778         }
3779 }
3780
3781 /*** Enum description for usage in signal ***/
3782
3783 GType
3784 ev_sizing_mode_get_type (void)
3785 {
3786   static GType etype = 0;
3787   if (etype == 0) {
3788     static const GEnumValue values[] = {
3789       { EV_SIZING_FIT_WIDTH, "EV_SIZING_FIT_WIDTH", "fit-width" },
3790       { EV_SIZING_BEST_FIT, "EV_SIZING_BEST_FIT", "best-fit" },
3791       { EV_SIZING_FREE, "EV_SIZING_FREE", "free" },
3792       { 0, NULL, NULL }
3793     };
3794     etype = g_enum_register_static ("EvSizingMode", values);
3795   }
3796   return etype;
3797 }