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