]> www.fi.muni.cz Git - evince.git/blob - shell/ev-view.c
Release ref on the pixbuf cache when changing document.
[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-document-find.h"
33 #include "ev-document-misc.h"
34 #include "ev-debug.h"
35 #include "ev-job-queue.h"
36 #include "ev-page-cache.h"
37 #include "ev-pixbuf-cache.h"
38
39 #define EV_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_VIEW, EvViewClass))
40 #define EV_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_VIEW))
41 #define EV_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_VIEW, EvViewClass))
42
43 enum {
44         PROP_0,
45         PROP_STATUS,
46         PROP_FIND_STATUS,
47         PROP_CONTINUOUS,
48         PROP_DUAL_PAGE,
49         PROP_FULLSCREEN,
50         PROP_PRESENTATION,
51         PROP_SIZING_MODE,
52         PROP_ZOOM,
53 };
54
55 enum {
56         SIGNAL_SCROLL_VIEW,
57         SIGNAL_ZOOM_INVALID,
58         N_SIGNALS,
59 };
60
61 enum {
62         TARGET_STRING,
63         TARGET_TEXT,
64         TARGET_COMPOUND_TEXT,
65         TARGET_UTF8_STRING,
66         TARGET_TEXT_BUFFER_CONTENTS
67 };
68
69 static const GtkTargetEntry targets[] = {
70         { "STRING", 0, TARGET_STRING },
71         { "TEXT",   0, TARGET_TEXT },
72         { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
73         { "UTF8_STRING", 0, TARGET_UTF8_STRING },
74 };
75
76 static guint signals[N_SIGNALS];
77
78 typedef enum {
79         EV_VIEW_CURSOR_NORMAL,
80         EV_VIEW_CURSOR_LINK,
81         EV_VIEW_CURSOR_WAIT,
82         EV_VIEW_CURSOR_HIDDEN,
83         EV_VIEW_CURSOR_DRAG
84 } EvViewCursor;
85
86 #define ZOOM_IN_FACTOR  1.2
87 #define ZOOM_OUT_FACTOR (1.0/ZOOM_IN_FACTOR)
88
89 #define MIN_SCALE 0.05409
90 #define MAX_SCALE 4.0
91
92 typedef struct {
93         EvRectangle rect;
94         int page;
95 } EvViewSelection;
96
97 typedef struct {
98         gboolean dragging;
99         GdkPoint start;
100         gdouble hadj;
101         gdouble vadj;
102 } DragInfo;
103
104 typedef enum {
105         SCROLL_TO_KEEP_POSITION,
106         SCROLL_TO_CURRENT_PAGE,
107         SCROLL_TO_CENTER
108 } PendingScroll;
109
110 struct _EvView {
111         GtkWidget parent_instance;
112
113         EvDocument *document;
114
115         char *status;
116         char *find_status;
117
118         gint scroll_x;
119         gint scroll_y;
120
121         DragInfo drag_info;
122         gboolean pressed_button;
123         GdkPoint selection_start;
124         GList *selections;
125         EvViewCursor cursor;
126
127         GtkAdjustment *hadjustment;
128         GtkAdjustment *vadjustment;
129
130         EvPageCache *page_cache;
131         EvPixbufCache *pixbuf_cache;
132
133         gint start_page;
134         gint end_page;
135         gint current_page;
136
137         EvJobRender *current_job;
138
139         int find_page;
140         int find_result;
141         int spacing;
142
143         double scale;
144         GtkBorder border;
145
146         gboolean continuous;
147         gboolean dual_page;
148         gboolean fullscreen;
149         gboolean presentation;
150         EvSizingMode sizing_mode;
151         
152         PendingScroll pending_scroll;
153         gboolean pending_resize;
154 };
155
156 struct _EvViewClass {
157         GtkWidgetClass parent_class;
158
159         void    (*set_scroll_adjustments) (EvView         *view,
160                                            GtkAdjustment  *hadjustment,
161                                            GtkAdjustment  *vadjustment);
162         void    (*scroll_view)            (EvView         *view,
163                                            GtkScrollType   scroll,
164                                            gboolean        horizontal);
165         void    (*zoom_invalid)           (EvView         *view);
166 };
167
168 /*** Scrolling ***/
169 static void       ev_view_set_scroll_adjustments             (EvView             *view,
170                                                               GtkAdjustment      *hadjustment,
171                                                               GtkAdjustment      *vadjustment);
172 static void       view_update_range_and_current_page         (EvView             *view);
173 static void       set_scroll_adjustment                      (EvView             *view,
174                                                               GtkOrientation      orientation,
175                                                               GtkAdjustment      *adjustment);
176 static void       ev_view_set_scroll_adjustments             (EvView             *view,
177                                                               GtkAdjustment      *hadjustment,
178                                                               GtkAdjustment      *vadjustment);
179 static void       add_scroll_binding_keypad                  (GtkBindingSet      *binding_set,
180                                                               guint               keyval,
181                                                               GtkScrollType       scroll,
182                                                               gboolean            horizontal);
183 static void       ev_view_scroll_view                        (EvView             *view,
184                                                               GtkScrollType       scroll,
185                                                               gboolean            horizontal);
186 static void       ensure_rectangle_is_visible                (EvView             *view,
187                                                               GdkRectangle       *rect);
188
189 /*** Geometry computations ***/
190 static void       compute_border                             (EvView             *view,
191                                                               int                 width,
192                                                               int                 height,
193                                                               GtkBorder          *border);
194 static gboolean   get_page_extents                           (EvView             *view,
195                                                               gint                page,
196                                                               GdkRectangle       *page_area,
197                                                               GtkBorder          *border);
198 static void       view_rect_to_doc_rect                      (EvView             *view,
199                                                               GdkRectangle       *view_rect,
200                                                               GdkRectangle       *page_area,
201                                                               EvRectangle        *doc_rect);
202 static void       doc_rect_to_view_rect                      (EvView             *view,
203                                                               int                 page,
204                                                               EvRectangle        *doc_rect,
205                                                               GdkRectangle       *view_rect);
206 static void       get_bounding_box_size                      (EvView             *view,
207                                                               int                *max_width,
208                                                               int                *max_height);
209 static void       find_page_at_location                      (EvView             *view,
210                                                               gdouble             x,
211                                                               gdouble             y,
212                                                               gint               *page,
213                                                               gint               *x_offset,
214                                                               gint               *y_offset);
215
216 /*** Hyperrefs ***/
217 static EvLink*    get_link_at_location                       (EvView             *view,
218                                                               gdouble             x,
219                                                               gdouble             y);
220 static void       go_to_link                                 (EvView             *view,
221                                                               EvLink             *link);
222 static char*      status_message_from_link                   (EvView             *view,
223                                                               EvLink             *link);
224
225 /*** GtkWidget implementation ***/
226 static void       ev_view_size_request_continuous_dual_page  (EvView             *view,
227                                                               GtkRequisition     *requisition);
228 static void       ev_view_size_request_continuous            (EvView             *view,
229                                                               GtkRequisition     *requisition);
230 static void       ev_view_size_request_dual_page             (EvView             *view,
231                                                               GtkRequisition     *requisition);
232 static void       ev_view_size_request_single_page           (EvView             *view,
233                                                               GtkRequisition     *requisition);
234 static void       ev_view_size_request                       (GtkWidget          *widget,
235                                                               GtkRequisition     *requisition);
236 static void       ev_view_size_allocate                      (GtkWidget          *widget,
237                                                               GtkAllocation      *allocation);
238 static void       ev_view_realize                            (GtkWidget          *widget);
239 static void       ev_view_unrealize                          (GtkWidget          *widget);
240 static gboolean   ev_view_scroll_event                       (GtkWidget          *widget,
241                                                               GdkEventScroll     *event);
242 static gboolean   ev_view_expose_event                       (GtkWidget          *widget,
243                                                               GdkEventExpose     *event);
244 static gboolean   ev_view_button_press_event                 (GtkWidget          *widget,
245                                                               GdkEventButton     *event);
246 static gboolean   ev_view_motion_notify_event                (GtkWidget          *widget,
247                                                               GdkEventMotion     *event);
248 static gboolean   ev_view_button_release_event               (GtkWidget          *widget,
249                                                               GdkEventButton     *event);
250
251 /*** Drawing ***/
252 static guint32    ev_gdk_color_to_rgb                        (const GdkColor     *color);
253 static void       draw_rubberband                            (GtkWidget          *widget,
254                                                               GdkWindow          *window,
255                                                               const GdkRectangle *rect,
256                                                               guchar              alpha);
257 static void       highlight_find_results                     (EvView             *view,
258                                                               int                 page);
259 static void       draw_one_page                              (EvView             *view,
260                                                               gint                page,
261                                                               GdkRectangle       *page_area,
262                                                               GtkBorder          *border,
263                                                               GdkRectangle       *expose_area);
264
265 /*** Callbacks ***/
266 static void       find_changed_cb                            (EvDocument         *document,
267                                                               int                 page,
268                                                               EvView             *view);
269 static void       job_finished_cb                            (EvPixbufCache      *pixbuf_cache,
270                                                               EvView             *view);
271 static void       page_changed_cb                            (EvPageCache        *page_cache,
272                                                               int                 new_page,
273                                                               EvView             *view);
274 static void       on_adjustment_value_changed                (GtkAdjustment      *adjustment,
275                                                               EvView             *view);
276
277 /*** GObject ***/
278 static void       ev_view_finalize                           (GObject            *object);
279 static void       ev_view_destroy                            (GtkObject          *object);
280 static void       ev_view_set_property                       (GObject            *object,
281                                                               guint               prop_id,
282                                                               const GValue       *value,
283                                                               GParamSpec         *pspec);
284 static void       ev_view_get_property                       (GObject            *object,
285                                                               guint               prop_id,
286                                                               GValue             *value,
287                                                               GParamSpec         *pspec);
288 static void       ev_view_class_init                         (EvViewClass        *class);
289 static void       ev_view_init                               (EvView             *view);
290
291 /*** Zoom and sizing ***/
292 static double   zoom_for_size_fit_width                      (int doc_width,
293                                                               int doc_height,
294                                                               int target_width,
295                                                               int target_height,
296                                                               int vsb_width);
297 static double   zoom_for_size_best_fit                       (int doc_width,
298                                                               int doc_height,
299                                                               int target_width,
300                                                               int target_height,
301                                                               int vsb_width,
302                                                               int hsb_width);
303 static void     ev_view_zoom_for_size_presentation           (EvView *view,
304                                                               int     width,
305                                                               int     height);
306 static void     ev_view_zoom_for_size_continuous_and_dual_page (EvView *view,
307                                                                 int     width,
308                                                                 int     height,
309                                                                 int     vsb_width,
310                                                                 int     hsb_height);
311 static void     ev_view_zoom_for_size_continuous               (EvView *view,
312                                                                 int     width,
313                                                                 int     height,
314                                                                 int     vsb_width,
315                                                                 int     hsb_height);
316 static void     ev_view_zoom_for_size_dual_page                (EvView *view,
317                                                                 int     width,
318                                                                 int     height,
319                                                                 int     vsb_width,
320                                                                 int     hsb_height);
321 static void     ev_view_zoom_for_size_single_page              (EvView *view,
322                                                                 int     width,
323                                                                 int     height,
324                                                                 int     vsb_width,
325                                                                 int     hsb_height);
326 /*** Cursors ***/
327 static GdkCursor* ev_view_create_invisible_cursor            (void);
328 static void       ev_view_set_cursor                         (EvView             *view,
329                                                               EvViewCursor        new_cursor);
330
331 /*** Status messages ***/
332 static void       ev_view_set_status                         (EvView             *view,
333                                                               const char         *message);
334 static void       update_find_status_message                 (EvView             *view);
335 static void       ev_view_set_find_status                    (EvView             *view,
336                                                               const char         *message);
337 /*** Find ***/
338 static void       jump_to_find_result                        (EvView             *view);
339 static void       jump_to_find_page                          (EvView             *view);
340
341 /*** Selection ***/
342 static void       compute_selections                         (EvView             *view,
343                                                               GdkRectangle       *view_rect);
344 static void       clear_selection                            (EvView             *view);
345 static char*      get_selected_text                          (EvView             *ev_view);
346 static void       ev_view_primary_get_cb                     (GtkClipboard       *clipboard,
347                                                               GtkSelectionData   *selection_data,
348                                                               guint               info,
349                                                               gpointer            data);
350 static void       ev_view_primary_clear_cb                   (GtkClipboard       *clipboard,
351                                                               gpointer            data);
352 static void       ev_view_update_primary_selection           (EvView             *ev_view);
353
354                                                 
355 G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_WIDGET)
356
357 static void
358 scroll_to_current_page (EvView *view, GtkOrientation orientation)
359 {
360         int max_width, max_height, n_rows;
361         
362         get_bounding_box_size (view, &max_width, &max_height);
363         
364         if (orientation == GTK_ORIENTATION_VERTICAL) {  
365                 if (view->continuous) {
366                         n_rows = view->dual_page ? view->current_page / 2 : view->current_page;
367
368                         gtk_adjustment_clamp_page (view->vadjustment,
369                                                    (max_height + view->spacing) * n_rows,
370                                                    (max_height + view->spacing) * n_rows +
371                                                    view->vadjustment->page_size);
372                 } else {
373                         gtk_adjustment_set_value (view->vadjustment,
374                                                   view->vadjustment->lower);
375                 }
376         } else {
377                 if (view->dual_page) {
378                         if (view->current_page % 2 == 0) {
379                                 gtk_adjustment_set_value (view->hadjustment,
380                                                           view->hadjustment->lower);
381                         } else {
382                                 gtk_adjustment_clamp_page (view->hadjustment,
383                                                            view->hadjustment->lower + 
384                                                            max_width + view->spacing, 
385                                                            view->hadjustment->lower +
386                                                            max_width + view->spacing +
387                                                            view->hadjustment->page_size);
388                         }
389                 } else {
390                         gtk_adjustment_set_value (view->hadjustment,
391                                                   CLAMP (view->hadjustment->value, 
392                                                   view->hadjustment->lower,
393                                                   view->hadjustment->upper - 
394                                                   view->hadjustment->page_size));
395                 }
396         }
397 }
398
399 static void
400 view_set_adjustment_values (EvView         *view,
401                             GtkOrientation  orientation)
402 {
403         GtkWidget *widget = GTK_WIDGET (view);
404         GtkAdjustment *adjustment;
405         int requisition;
406         int allocation;
407
408         double factor;
409         gint new_value;
410
411         if (orientation == GTK_ORIENTATION_HORIZONTAL)  {
412                 requisition = widget->requisition.width;
413                 allocation = widget->allocation.width;
414                 adjustment = view->hadjustment;
415         } else {
416                 requisition = widget->requisition.height;
417                 allocation = widget->allocation.height;
418                 adjustment = view->vadjustment;
419         }
420
421         if (!adjustment)
422                 return;
423         
424         factor = 1.0;
425         switch (view->pending_scroll) {
426                 case SCROLL_TO_KEEP_POSITION: 
427                         factor = adjustment->value / adjustment->upper;
428                         break;
429                 case SCROLL_TO_CURRENT_PAGE: 
430                         break;
431                 case SCROLL_TO_CENTER: 
432                         factor = (adjustment->value + adjustment->page_size * 0.5) / adjustment->upper;
433                         break;
434         }
435
436         adjustment->page_size = allocation;
437         adjustment->step_increment = allocation * 0.1;
438         adjustment->page_increment = allocation * 0.9;
439         adjustment->lower = 0;
440         adjustment->upper = MAX (allocation, requisition);
441
442         switch (view->pending_scroll) {
443                 case SCROLL_TO_KEEP_POSITION: 
444                         new_value = CLAMP (adjustment->upper * factor, 0, adjustment->upper - adjustment->page_size);
445                         gtk_adjustment_set_value (adjustment, (int)new_value);
446                         break;
447                 case SCROLL_TO_CURRENT_PAGE: 
448                         scroll_to_current_page (view, orientation);
449                         break;
450                 case SCROLL_TO_CENTER: 
451                         new_value = CLAMP (adjustment->upper * factor - adjustment->page_size * 0.5,
452                                            0, adjustment->upper - adjustment->page_size);
453                         gtk_adjustment_set_value (adjustment, (int)new_value);
454                         break;
455         }
456
457         gtk_adjustment_changed (adjustment);
458 }
459
460 static void
461 view_update_range_and_current_page (EvView *view)
462 {
463         /* Presentation trumps all other modes */
464         if (view->presentation) {
465                 view->start_page = view->current_page;
466                 view->end_page = view->current_page;
467         } else if (view->continuous) {
468                 GdkRectangle current_area, unused, page_area;
469                 gint current_page;
470                 gboolean found = FALSE;
471                 int i;
472                 
473                 get_bounding_box_size (view, &(page_area.width), &(page_area.height));
474                 page_area.x = view->spacing;
475                 page_area.y = view->spacing;
476
477                 if (view->hadjustment) {
478                         current_area.x = view->hadjustment->value;
479                         current_area.width = view->hadjustment->page_size;
480                 } else {
481                         current_area.x = page_area.x;
482                         current_area.width = page_area.width;
483                 }
484
485                 if (view->vadjustment) {
486                         current_area.y = view->vadjustment->value;
487                         current_area.height = view->vadjustment->page_size;
488                 } else {
489                         current_area.y = page_area.y;
490                         current_area.height = page_area.height;
491                 }
492
493                 for (i = 0; i < ev_page_cache_get_n_pages (view->page_cache); i++) {
494                         if (gdk_rectangle_intersect (&current_area, &page_area, &unused)) {
495                                 if (! found) {
496                                         view->start_page = i;
497                                         found = TRUE;
498                                         
499                                 }
500                                 view->end_page = i;
501                         } else if (found) {
502                                 break;
503                         }
504                         if (view->dual_page) {
505                                 if (i % 2 == 0) {
506                                         page_area.x += page_area.width + view->spacing;
507                                 } else {
508                                         page_area.x = view->spacing;
509                                         page_area.y += page_area.height + view->spacing;
510                                 }
511                         } else {
512                                 page_area.y += page_area.height + view->spacing;
513                         }
514                 }
515
516                 current_page = ev_page_cache_get_current_page (view->page_cache);
517
518                 if (current_page < view->start_page || current_page > view->end_page) {
519                         view->current_page = view->start_page;
520                         ev_page_cache_set_current_page (view->page_cache, view->start_page);
521                 }                       
522         } else {
523                 if (view->dual_page) {
524                         if (view->current_page % 2 == 0) {
525                                 view->start_page = view->current_page;
526                                 if (view->current_page + 1 < ev_page_cache_get_n_pages (view->page_cache))
527                                         view->end_page = view->start_page + 1;
528                         } else {
529                                 view->start_page = view->current_page - 1;
530                                 view->end_page = view->current_page;
531                         }
532                 } else {
533                         view->start_page = view->current_page;
534                         view->end_page = view->current_page;
535                 }
536         }
537
538         ev_pixbuf_cache_set_page_range (view->pixbuf_cache,
539                                         view->start_page,
540                                         view->end_page,
541                                         view->scale);   
542 }
543
544 static void
545 set_scroll_adjustment (EvView *view,
546                        GtkOrientation  orientation,
547                        GtkAdjustment  *adjustment)
548 {
549         GtkAdjustment **to_set;
550
551         if (orientation == GTK_ORIENTATION_HORIZONTAL)
552                 to_set = &view->hadjustment;
553         else
554                 to_set = &view->vadjustment;
555
556         if (*to_set != adjustment) {
557                 if (*to_set) {
558                         g_signal_handlers_disconnect_by_func (*to_set,
559                                                               (gpointer) on_adjustment_value_changed,
560                                                               view);
561                         g_object_unref (*to_set);
562                 }
563
564                 *to_set = adjustment;
565                 view_set_adjustment_values (view, orientation);
566
567                 if (*to_set) {
568                         g_object_ref (*to_set);
569                         g_signal_connect (*to_set, "value_changed",
570                                           G_CALLBACK (on_adjustment_value_changed), view);
571                 }
572         }
573 }
574
575 static void
576 ev_view_set_scroll_adjustments (EvView *view,
577                                 GtkAdjustment  *hadjustment,
578                                 GtkAdjustment  *vadjustment)
579 {
580         set_scroll_adjustment (view, GTK_ORIENTATION_HORIZONTAL, hadjustment);
581         set_scroll_adjustment (view, GTK_ORIENTATION_VERTICAL, vadjustment);
582
583         on_adjustment_value_changed (NULL, view);
584 }
585
586 static void
587 add_scroll_binding_keypad (GtkBindingSet  *binding_set,
588                            guint           keyval,
589                            GtkScrollType   scroll,
590                            gboolean        horizontal)
591 {
592   guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
593
594   gtk_binding_entry_add_signal (binding_set, keyval, 0,
595                                 "scroll_view", 2,
596                                 GTK_TYPE_SCROLL_TYPE, scroll,
597                                 G_TYPE_BOOLEAN, horizontal);
598   gtk_binding_entry_add_signal (binding_set, keypad_keyval, 0,
599                                 "scroll_view", 2,
600                                 GTK_TYPE_SCROLL_TYPE, scroll,
601                                 G_TYPE_BOOLEAN, horizontal);
602 }
603
604 void
605 ev_view_scroll (EvView        *view,
606                 EvScrollType   scroll)
607 {
608         GtkAdjustment *adjustment;
609         double value, increment;
610         gboolean first_page = FALSE;
611         gboolean last_page = FALSE;
612
613         /* Assign values for increment and vertical adjustment */
614         adjustment = view->vadjustment;
615         increment = adjustment->page_size * 0.75;
616         value = adjustment->value;
617
618         /* Assign boolean for first and last page */
619         if (view->current_page == 0)
620                 first_page = TRUE;
621         if (view->current_page == ev_page_cache_get_n_pages (view->page_cache) - 1)
622                 last_page = TRUE;
623
624         switch (scroll) {
625                 case EV_SCROLL_PAGE_BACKWARD:
626                         /* Do not jump backwards if at the first page */
627                         if (value == (adjustment->lower) && first_page) {
628                                 /* Do nothing */
629                                 /* At the top of a page, assign the upper bound limit of previous page */
630                         } else if (value == (adjustment->lower)) {
631                                 value = adjustment->upper - adjustment->page_size;
632                                 ev_page_cache_set_current_page (view->page_cache, view->current_page - 1);
633                                 /* Jump to the top */
634                         } else {
635                                 value = MAX (value - increment, adjustment->lower);
636                         }
637                         break;
638                 case EV_SCROLL_PAGE_FORWARD:
639                         /* Do not jump forward if at the last page */
640                         if (value == (adjustment->upper - adjustment->page_size) && last_page) {
641                                 /* Do nothing */
642                         /* At the bottom of a page, assign the lower bound limit of next page */
643                         } else if (value == (adjustment->upper - adjustment->page_size)) {
644                                 value = 0;
645                                 ev_page_cache_set_current_page (view->page_cache, view->current_page + 1);
646                         /* Jump to the bottom */
647                         } else {
648                                 value = MIN (value + increment, adjustment->upper - adjustment->page_size);
649                         }
650                         break;
651                 default:
652                         break;
653         }
654
655         gtk_adjustment_set_value (adjustment, value);
656 }
657
658 static void
659 ev_view_scroll_view (EvView *view,
660                      GtkScrollType scroll,
661                      gboolean horizontal)
662 {
663         GtkAdjustment *adjustment;
664         double value;
665
666         if (horizontal) {
667                 adjustment = view->hadjustment;
668         } else {
669                 adjustment = view->vadjustment;
670         }
671
672         value = adjustment->value;
673
674         switch (scroll) {
675                 case GTK_SCROLL_STEP_BACKWARD:
676                         value -= adjustment->step_increment;
677                         break;
678                 case GTK_SCROLL_STEP_FORWARD:
679                         value += adjustment->step_increment;
680                         break;
681                 default:
682                         break;
683         }
684
685         value = CLAMP (value, adjustment->lower,
686                        adjustment->upper - adjustment->page_size);
687
688         gtk_adjustment_set_value (adjustment, value);
689 }
690
691 #define MARGIN 5
692
693 static void
694 ensure_rectangle_is_visible (EvView *view, GdkRectangle *rect)
695 {
696         GtkWidget *widget = GTK_WIDGET (view);
697         GtkAdjustment *adjustment;
698         int value;
699
700         adjustment = view->vadjustment;
701
702         if (rect->y < adjustment->value) {
703                 value = MAX (adjustment->lower, rect->y - MARGIN);
704                 gtk_adjustment_set_value (view->vadjustment, value);
705         } else if (rect->y + rect->height >
706                    adjustment->value + widget->allocation.height) {
707                 value = MIN (adjustment->upper, rect->y + rect->height -
708                              widget->allocation.height + MARGIN);
709                 gtk_adjustment_set_value (view->vadjustment, value);
710         }
711
712         adjustment = view->hadjustment;
713
714         if (rect->x < adjustment->value) {
715                 value = MAX (adjustment->lower, rect->x - MARGIN);
716                 gtk_adjustment_set_value (view->hadjustment, value);
717         } else if (rect->x + rect->height >
718                    adjustment->value + widget->allocation.width) {
719                 value = MIN (adjustment->upper, rect->x + rect->width -
720                              widget->allocation.width + MARGIN);
721                 gtk_adjustment_set_value (view->hadjustment, value);
722         }
723 }
724
725 /*** Geometry computations ***/
726
727 static void
728 compute_border (EvView *view, int width, int height, GtkBorder *border)
729 {
730         if (view->presentation) {
731                 border->left = 0;
732                 border->right = 0;
733                 border->top = 0;
734                 border->bottom = 0;
735         } else {
736                 ev_document_misc_get_page_border_size (width, height, border);
737         }
738 }
739
740 static gboolean
741 get_page_extents (EvView       *view,
742                   gint          page,
743                   GdkRectangle *page_area,
744                   GtkBorder    *border)
745 {
746         GtkWidget *widget;
747         int width, height;
748
749         widget = GTK_WIDGET (view);
750
751         /* Quick sanity check */
752         if (view->presentation) {
753                 if (view->current_page != page)
754                         return FALSE;
755         } else if (view->continuous) {
756                 if (page < view->start_page ||
757                     page > view->end_page)
758                         return FALSE;
759         } else if (view->dual_page) {
760                 if (ABS (page - view->current_page) > 1)
761                         return FALSE;
762         } else {
763                 if (view->current_page != page)
764                         return FALSE;
765         }
766
767         /* Get the size of the page */
768         ev_page_cache_get_size (view->page_cache, page,
769                                 view->scale,
770                                 &width, &height);
771         compute_border (view, width, height, border);
772         page_area->width = width + border->left + border->right;
773         page_area->height = height + border->top + border->bottom;
774
775         if (view->presentation) {
776                 page_area->x = (MAX (0, widget->allocation.width - width))/2;
777                 page_area->y = (MAX (0, widget->allocation.height - height))/2;
778         } else if (view->continuous) {
779                 gint max_width, max_height;
780                 gint x, y;
781
782                 get_bounding_box_size (view, &max_width, &max_height);
783                 /* Get the location of the bounding box */
784                 if (view->dual_page) {
785                         x = view->spacing + (page % 2) * (max_width + view->spacing);
786                         y = view->spacing + (page / 2) * (max_height + view->spacing);
787                         x = x + MAX (0, widget->allocation.width - (max_width * 2 + view->spacing * 3))/2;
788                 } else {
789                         x = view->spacing;
790                         y = view->spacing + page * (max_height + view->spacing);
791                         x = x + MAX (0, widget->allocation.width - (max_width + view->spacing * 2))/2;
792                 }
793                 page_area->x = x;
794                 page_area->y = y;
795         } else {
796                 gint x, y;
797                 if (view->dual_page) {
798                         gint width_2, height_2;
799                         gint max_width = width;
800                         gint max_height = height;
801                         GtkBorder overall_border;
802                         gint other_page;
803
804                         other_page = page ^ 1;
805
806                         /* First, we get the bounding box of the two pages */
807                         if (other_page < ev_page_cache_get_n_pages (view->page_cache)) {
808                                 ev_page_cache_get_size (view->page_cache,
809                                                         page + 1,
810                                                         view->scale,
811                                                         &width_2, &height_2);
812                                 if (width_2 > width)
813                                         max_width = width_2;
814                                 if (height_2 > height)
815                                         max_height = height_2;
816                         }
817                         compute_border (view, max_width, max_height, &overall_border);
818
819                         /* Find the offsets */
820                         x = view->spacing;
821                         y = view->spacing;
822
823                         /* Adjust for being the left or right page */
824                         if (page % 2 == 0)
825                                 x = x + max_width - width;
826                         else
827                                 x = x + (max_width + overall_border.left + overall_border.right) + view->spacing;
828
829                         y = y + (max_height - height)/2;
830
831                         /* Adjust for extra allocation */
832                         x = x + MAX (0, widget->allocation.width -
833                                      ((max_width + overall_border.left + overall_border.right) * 2 + view->spacing * 3))/2;
834                         y = y + MAX (0, widget->allocation.height - (height + view->spacing * 2))/2;
835                 } else {
836                         x = view->spacing;
837                         y = view->spacing;
838
839                         /* Adjust for extra allocation */
840                         x = x + MAX (0, widget->allocation.width - (width + border->left + border->right + view->spacing * 2))/2;
841                         y = y + MAX (0, widget->allocation.height - (height + border->top + border->bottom +  view->spacing * 2))/2;
842                 }
843
844                 page_area->x = x;
845                 page_area->y = y;
846         }
847
848         return TRUE;
849 }
850
851 static void
852 view_rect_to_doc_rect (EvView *view,
853                        GdkRectangle *view_rect,
854                        GdkRectangle *page_area,
855                        EvRectangle  *doc_rect)
856 {
857         doc_rect->x1 = floor ((view_rect->x - page_area->x) / view->scale);
858         doc_rect->y1 = floor ((view_rect->y - page_area->y) / view->scale);
859         doc_rect->x2 = doc_rect->x1 + ceil (view_rect->width / view->scale);
860         doc_rect->y2 = doc_rect->y1 + ceil (view_rect->height / view->scale);
861 }
862
863 static void
864 doc_rect_to_view_rect (EvView       *view,
865                        int           page,
866                        EvRectangle  *doc_rect,
867                        GdkRectangle *view_rect)
868 {
869         GdkRectangle page_area;
870         GtkBorder border;
871         int width, height;
872
873         get_page_extents (view, page, &page_area, &border);
874
875         width = doc_rect->x2 - doc_rect->x1;
876         height = doc_rect->y2 - doc_rect->y1;
877         view_rect->x = floor (doc_rect->x1 * view->scale) + page_area.x;
878         view_rect->y = floor (doc_rect->y1 * view->scale) + page_area.y;
879         view_rect->width = ceil (width * view->scale);
880         view_rect->height = ceil (height * view->scale);
881 }
882
883 static void
884 get_bounding_box_size (EvView *view, int *max_width, int *max_height)
885 {
886         GtkBorder border;
887         int width, height;
888
889         if (max_width) {
890                 ev_page_cache_get_max_width_size (view->page_cache,
891                                                   view->scale,
892                                                   &width, &height);
893                 compute_border (view, width, height, &border);
894                 *max_width = width + border.left + border.right;
895         }
896
897
898         if (max_height) {
899                 ev_page_cache_get_max_height_size (view->page_cache,
900                                                    view->scale,
901                                                    &width, &height);
902                 compute_border (view, width, height, &border);
903                 *max_height = height + border.top + border.bottom;
904         }
905 }
906
907 static void
908 find_page_at_location (EvView  *view,
909                        gdouble  x,
910                        gdouble  y,
911                        gint    *page,
912                        gint    *x_offset,
913                        gint    *y_offset)
914 {
915         int i;
916
917         if (view->document == NULL)
918                 return;
919
920         g_assert (page);
921         g_assert (x_offset);
922         g_assert (y_offset);
923
924         for (i = view->start_page; i <= view->end_page; i++) {
925                 GdkRectangle page_area;
926                 GtkBorder border;
927
928                 if (! get_page_extents (view, i, &page_area, &border))
929                         continue;
930
931                 if ((x >= page_area.x + border.left) &&
932                     (x < page_area.x + page_area.width - border.right) &&
933                     (y >= page_area.y + border.top) &&
934                     (y < page_area.y + page_area.height - border.bottom)) {
935                         *page = i;
936                         *x_offset = x - (page_area.x + border.left);
937                         *y_offset = y - (page_area.y + border.top);
938                         return;
939                 }
940         }
941
942         *page = -1;
943 }
944
945 /*** Hyperref ***/
946 static EvLink *
947 get_link_at_location (EvView  *view,
948                       gdouble  x,
949                       gdouble  y)
950 {
951         gint page = -1;
952         gint x_offset = 0, y_offset = 0;
953         GList *link_mapping;
954
955         find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
956
957         if (page == -1)
958                 return NULL;
959
960         link_mapping = ev_pixbuf_cache_get_link_mapping (view->pixbuf_cache, page);
961
962         if (link_mapping)
963                 return ev_link_mapping_find (link_mapping, x_offset / view->scale, y_offset / view->scale);
964         else
965                 return NULL;
966 }
967
968 /* FIXME: standardize this sometime */
969 static void
970 go_to_link (EvView *view, EvLink *link)
971 {
972         EvLinkType type;
973         const char *uri;
974         int page;
975
976         type = ev_link_get_link_type (link);
977
978         switch (type) {
979                 case EV_LINK_TYPE_TITLE:
980                         break;
981                 case EV_LINK_TYPE_PAGE:
982                         page = ev_link_get_page (link);
983                         ev_page_cache_set_current_page (view->page_cache, page);
984                         break;
985                 case EV_LINK_TYPE_EXTERNAL_URI:
986                         uri = ev_link_get_uri (link);
987                         gnome_vfs_url_show (uri);
988                         break;
989         }
990 }
991
992 static char *
993 status_message_from_link (EvView *view, EvLink *link)
994 {
995         EvLinkType type;
996         char *msg = NULL;
997         char *page_label;
998
999         type = ev_link_get_link_type (link);
1000
1001         switch (type) {
1002                 case EV_LINK_TYPE_TITLE:
1003                         if (ev_link_get_title (link))
1004                                 msg = g_strdup (ev_link_get_title (link));
1005                         break;
1006                 case EV_LINK_TYPE_PAGE:
1007                         page_label = ev_page_cache_get_page_label (view->page_cache, ev_link_get_page (link));
1008                         msg = g_strdup_printf (_("Go to page %s"), page_label);
1009                         g_free (page_label);
1010                         break;
1011                 case EV_LINK_TYPE_EXTERNAL_URI:
1012                         msg = g_strdup (ev_link_get_uri (link));
1013                         break;
1014                 default:
1015                         break;
1016         }
1017
1018         return msg;
1019 }
1020
1021
1022 /*** GtkWidget implementation ***/
1023
1024 static void
1025 ev_view_size_request_continuous_dual_page (EvView         *view,
1026                                                GtkRequisition *requisition)
1027 {
1028         int max_width, max_height;
1029         int n_rows;
1030
1031         get_bounding_box_size (view, &max_width, &max_height);
1032
1033         n_rows = (1 + ev_page_cache_get_n_pages (view->page_cache)) / 2;
1034
1035         requisition->width = (max_width * 2) + (view->spacing * 3);
1036         requisition->height = max_height * n_rows + (view->spacing * (n_rows + 1));
1037
1038         if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
1039                 requisition->width = 1;
1040         } else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
1041                 requisition->width = 1;
1042                 /* FIXME: This could actually be set on one page docs or docs
1043                  * with a strange aspect ratio. */
1044                 /* requisition->height = 1;*/
1045         }
1046 }
1047
1048 static void
1049 ev_view_size_request_continuous (EvView         *view,
1050                                  GtkRequisition *requisition)
1051 {
1052         int max_width, max_height;
1053         int n_pages;
1054
1055         get_bounding_box_size (view, &max_width, &max_height);
1056
1057         n_pages = ev_page_cache_get_n_pages (view->page_cache);
1058
1059         requisition->width = max_width + (view->spacing * 2);
1060         requisition->height = max_height * n_pages + (view->spacing * (n_pages + 1));
1061
1062         if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
1063                 requisition->width = 1;
1064         } else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
1065                 requisition->width = 1;
1066                 /* FIXME: This could actually be set on one page docs or docs
1067                  * with a strange aspect ratio. */
1068                 /* requisition->height = 1;*/
1069         }
1070 }
1071
1072 static void
1073 ev_view_size_request_dual_page (EvView         *view,
1074                                 GtkRequisition *requisition)
1075 {
1076         GtkBorder border;
1077         gint width, height;
1078
1079         /* Find the largest of the two. */
1080         ev_page_cache_get_size (view->page_cache,
1081                                 view->current_page,
1082                                 view->scale,
1083                                 &width, &height);
1084         if (view->current_page + 1 < ev_page_cache_get_n_pages (view->page_cache)) {
1085                 gint width_2, height_2;
1086                 ev_page_cache_get_size (view->page_cache,
1087                                         view->current_page + 1,
1088                                         view->scale,
1089                                         &width_2, &height_2);
1090                 if (width_2 > width) {
1091                         width = width_2;
1092                         height = height_2;
1093                 }
1094         }
1095         compute_border (view, width, height, &border);
1096
1097         requisition->width = ((width + border.left + border.right) * 2) +
1098                 (view->spacing * 3);
1099         requisition->height = (height + border.top + border.bottom) +
1100                 (view->spacing * 2);
1101
1102         if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
1103                 requisition->width = 1;
1104         } else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
1105                 requisition->width = 1;
1106                 requisition->height = 1;
1107         }
1108 }
1109
1110 static void
1111 ev_view_size_request_single_page (EvView         *view,
1112                                   GtkRequisition *requisition)
1113 {
1114         GtkBorder border;
1115         gint width, height;
1116
1117         ev_page_cache_get_size (view->page_cache,
1118                                 view->current_page,
1119                                 view->scale,
1120                                 &width, &height);
1121         compute_border (view, width, height, &border);
1122
1123         requisition->width = width + border.left + border.right + (2 * view->spacing);
1124         requisition->height = height + border.top + border.bottom + (2 * view->spacing);
1125
1126         if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
1127                 requisition->width = 1;
1128                 requisition->height = height + border.top + border.bottom + (2 * view->spacing);
1129         } else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
1130                 requisition->width = 1;
1131                 requisition->height = 1;
1132         }
1133 }
1134
1135 static void
1136 ev_view_size_request (GtkWidget      *widget,
1137                       GtkRequisition *requisition)
1138 {
1139         EvView *view = EV_VIEW (widget);
1140
1141         if (view->document == NULL) {
1142                 requisition->width = 1;
1143                 requisition->height = 1;
1144                 return;
1145         }
1146
1147         if (view->presentation) {
1148                 requisition->width = 1;
1149                 requisition->height = 1;
1150                 return;
1151         }
1152
1153         if (view->continuous && view->dual_page)
1154                 ev_view_size_request_continuous_dual_page (view, requisition);
1155         else if (view->continuous)
1156                 ev_view_size_request_continuous (view, requisition);
1157         else if (view->dual_page)
1158                 ev_view_size_request_dual_page (view, requisition);
1159         else
1160                 ev_view_size_request_single_page (view, requisition);
1161 }
1162
1163 static void
1164 ev_view_size_allocate (GtkWidget      *widget,
1165                        GtkAllocation  *allocation)
1166 {
1167         EvView *view = EV_VIEW (widget);
1168         
1169         if (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
1170                   view->sizing_mode == EV_SIZING_BEST_FIT) {
1171
1172                 g_signal_emit (view, signals[SIGNAL_ZOOM_INVALID], 0);
1173                 
1174                 ev_view_size_request (widget, &widget->requisition);
1175         }
1176         
1177         view_set_adjustment_values (view, GTK_ORIENTATION_HORIZONTAL);
1178         view_set_adjustment_values (view, GTK_ORIENTATION_VERTICAL);
1179
1180         view->pending_scroll = SCROLL_TO_KEEP_POSITION;
1181         view->pending_resize = FALSE;
1182
1183         if (view->document)
1184                 view_update_range_and_current_page (view);              
1185
1186         GTK_WIDGET_CLASS (ev_view_parent_class)->size_allocate (widget, allocation);
1187 }
1188
1189 static void
1190 ev_view_realize (GtkWidget *widget)
1191 {
1192         EvView *view = EV_VIEW (widget);
1193         GdkWindowAttr attributes;
1194
1195         GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1196
1197
1198         attributes.window_type = GDK_WINDOW_CHILD;
1199         attributes.wclass = GDK_INPUT_OUTPUT;
1200         attributes.visual = gtk_widget_get_visual (widget);
1201         attributes.colormap = gtk_widget_get_colormap (widget);
1202
1203         attributes.x = widget->allocation.x;
1204         attributes.y = widget->allocation.y;
1205         attributes.width = widget->allocation.width;
1206         attributes.height = widget->allocation.height;
1207         attributes.event_mask = GDK_EXPOSURE_MASK |
1208                                 GDK_BUTTON_PRESS_MASK |
1209                                 GDK_BUTTON_RELEASE_MASK |
1210                                 GDK_SCROLL_MASK |
1211                                 GDK_KEY_PRESS_MASK |
1212                                 GDK_POINTER_MOTION_MASK |
1213                                 GDK_LEAVE_NOTIFY_MASK;
1214
1215         widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1216                                          &attributes,
1217                                          GDK_WA_X | GDK_WA_Y |
1218                                          GDK_WA_COLORMAP |
1219                                          GDK_WA_VISUAL);
1220         gdk_window_set_user_data (widget->window, widget);
1221         widget->style = gtk_style_attach (widget->style, widget->window);
1222
1223         if (view->presentation)
1224                 gdk_window_set_background (widget->window, &widget->style->black);
1225         else
1226                 gdk_window_set_background (widget->window, &widget->style->mid [GTK_STATE_NORMAL]);
1227 }
1228
1229 static void
1230 ev_view_unrealize (GtkWidget *widget)
1231 {
1232         GTK_WIDGET_CLASS (ev_view_parent_class)->unrealize (widget);
1233 }
1234
1235 static gboolean
1236 ev_view_scroll_event (GtkWidget *widget, GdkEventScroll *event)
1237 {
1238         EvView *view = EV_VIEW (widget); 
1239
1240         if ((event->state & GDK_CONTROL_MASK) != 0) {   
1241
1242                  ev_view_set_sizing_mode (view, EV_SIZING_FREE);         
1243
1244                  if (event->direction == GDK_SCROLL_UP || 
1245                         event->direction == GDK_SCROLL_LEFT) {
1246                             if (ev_view_can_zoom_in (view)) {
1247                                     ev_view_zoom_in (view);
1248                             }
1249                  } else {
1250                             if (ev_view_can_zoom_out (view)) {
1251                                     ev_view_zoom_out (view);
1252                             }   
1253                  }
1254                  return TRUE;
1255         }
1256         
1257         if ((event->state & GDK_SHIFT_MASK) != 0) {     
1258                 if (event->direction == GDK_SCROLL_UP)
1259                         event->direction = GDK_SCROLL_LEFT;
1260                 if (event->direction == GDK_SCROLL_DOWN)
1261                         event->direction = GDK_SCROLL_RIGHT;
1262         }
1263
1264         return FALSE;
1265 }
1266
1267 static gboolean
1268 ev_view_expose_event (GtkWidget      *widget,
1269                       GdkEventExpose *event)
1270 {
1271         EvView *view = EV_VIEW (widget);
1272         GdkRectangle rubberband;
1273         GList *l;
1274         int i;
1275
1276         if (view->document == NULL)
1277                 return FALSE;
1278
1279         for (i = view->start_page; i <= view->end_page; i++) {
1280                 GdkRectangle page_area;
1281                 GtkBorder border;
1282
1283                 if (!get_page_extents (view, i, &page_area, &border))
1284                         continue;
1285                     
1286                 page_area.x -= view->scroll_x;
1287                 page_area.y -= view->scroll_y;
1288                     
1289                 draw_one_page (view, i, &page_area, &border, &(event->area));
1290
1291                 if (EV_IS_DOCUMENT_FIND (view->document)) {
1292                         highlight_find_results (view, i);
1293                 }
1294         }
1295
1296         for (l = view->selections; l != NULL; l = l->next) {
1297                 EvViewSelection *selection = (EvViewSelection *)l->data;
1298
1299                 doc_rect_to_view_rect (view, selection->page,
1300                                        &selection->rect, &rubberband);
1301                 if (rubberband.width > 0 && rubberband.height > 0) {
1302                         draw_rubberband (GTK_WIDGET (view), GTK_WIDGET(view)->window,
1303                                          &rubberband, 0x40);
1304                 }
1305         }
1306
1307         return FALSE;
1308 }
1309
1310 static gboolean
1311 ev_view_button_press_event (GtkWidget      *widget,
1312                             GdkEventButton *event)
1313 {
1314         EvView *view = EV_VIEW (widget);
1315
1316         if (!GTK_WIDGET_HAS_FOCUS (widget)) {
1317                 gtk_widget_grab_focus (widget);
1318         }
1319
1320         view->pressed_button = event->button;
1321
1322         switch (event->button) {
1323                 case 1:
1324                         if (view->selections) {
1325                                 clear_selection (view);
1326                                 gtk_widget_queue_draw (widget);
1327                         }
1328
1329                         view->selection_start.x = event->x;
1330                         view->selection_start.y = event->y;
1331                         return TRUE;
1332                 case 2:
1333                         /* use root coordinates as reference point because
1334                          * scrolling changes window relative coordinates */
1335                         view->drag_info.start.x = event->x_root;
1336                         view->drag_info.start.y = event->y_root;
1337                         view->drag_info.hadj = gtk_adjustment_get_value (view->hadjustment);
1338                         view->drag_info.vadj = gtk_adjustment_get_value (view->vadjustment);
1339
1340                         ev_view_set_cursor (view, EV_VIEW_CURSOR_DRAG);
1341
1342                         return TRUE;
1343         }
1344
1345         return FALSE;
1346 }
1347
1348 static gboolean
1349 ev_view_motion_notify_event (GtkWidget      *widget,
1350                              GdkEventMotion *event)
1351 {
1352         EvView *view = EV_VIEW (widget);
1353
1354         if (view->pressed_button == 1) {
1355                 GdkRectangle selection;
1356
1357                 selection.x = MIN (view->selection_start.x, event->x) + view->scroll_x;
1358                 selection.y = MIN (view->selection_start.y, event->y) + view->scroll_y;
1359                 selection.width = ABS (view->selection_start.x - event->x) + 1;
1360                 selection.height = ABS (view->selection_start.y - event->y) + 1;
1361
1362                 compute_selections (view, &selection);
1363
1364                 gtk_widget_queue_draw (widget);
1365
1366                 return TRUE;
1367         } else if (view->pressed_button == 2) {
1368                 if (!view->drag_info.dragging) {
1369                         gboolean start;
1370
1371                         start = gtk_drag_check_threshold (widget,
1372                                                           view->drag_info.start.x,
1373                                                           view->drag_info.start.y,
1374                                                           event->x_root,
1375                                                           event->y_root);
1376                         view->drag_info.dragging = start;
1377                 }
1378
1379                 if (view->drag_info.dragging) {
1380                         int dx, dy;
1381                         gdouble dhadj_value, dvadj_value;
1382
1383                         dx = event->x_root - view->drag_info.start.x;
1384                         dy = event->y_root - view->drag_info.start.y;
1385
1386                         dhadj_value = view->hadjustment->page_size *
1387                                       (gdouble)dx / widget->allocation.width;
1388                         dvadj_value = view->vadjustment->page_size *
1389                                       (gdouble)dy / widget->allocation.height;
1390
1391                         /* clamp scrolling to visible area */
1392                         gtk_adjustment_set_value (view->hadjustment,
1393                                                   MIN(view->drag_info.hadj - dhadj_value,
1394                                                       view->hadjustment->upper -
1395                                                       view->hadjustment->page_size));
1396                         gtk_adjustment_set_value (view->vadjustment,
1397                                                   MIN(view->drag_info.vadj - dvadj_value,
1398                                                       view->vadjustment->upper -
1399                                                       view->vadjustment->page_size));
1400
1401                         return TRUE;
1402                 }
1403         } else if (view->pressed_button <= 0 && view->document) {
1404                 EvLink *link;
1405
1406                 link = get_link_at_location (view, event->x + view->scroll_x, event->y + view->scroll_y);
1407                 if (link) {
1408                         char *msg;
1409
1410                         msg = status_message_from_link (view, link);
1411                         ev_view_set_status (view, msg);
1412                         ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK);
1413                         g_free (msg);
1414                 } else {
1415                         ev_view_set_status (view, NULL);
1416                         if (view->cursor == EV_VIEW_CURSOR_LINK) {
1417                                 ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
1418                         }
1419                 }
1420                 return TRUE;
1421         }
1422
1423         return FALSE;
1424 }
1425
1426 static gboolean
1427 ev_view_button_release_event (GtkWidget      *widget,
1428                               GdkEventButton *event)
1429 {
1430         EvView *view = EV_VIEW (widget);
1431
1432         if (view->pressed_button == 2) {
1433                 ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
1434         }
1435
1436         view->pressed_button = -1;
1437         view->drag_info.dragging = FALSE;
1438
1439         if (view->selections) {
1440                 ev_view_update_primary_selection (view);
1441         } else if (view->document) {
1442                 EvLink *link;
1443
1444                 link = get_link_at_location (view, event->x + view->scroll_x, event->y + view->scroll_y);
1445                 if (link) {
1446                         go_to_link (view, link);
1447                 }
1448         }
1449
1450         return FALSE;
1451 }
1452
1453 /*** Drawing ***/
1454
1455 static guint32
1456 ev_gdk_color_to_rgb (const GdkColor *color)
1457 {
1458   guint32 result;
1459   result = (0xff0000 | (color->red & 0xff00));
1460   result <<= 8;
1461   result |= ((color->green & 0xff00) | (color->blue >> 8));
1462   return result;
1463 }
1464
1465 static void
1466 draw_rubberband (GtkWidget *widget, GdkWindow *window,
1467                  const GdkRectangle *rect, guchar alpha)
1468 {
1469         GdkGC *gc;
1470         GdkPixbuf *pixbuf;
1471         GdkColor *fill_color_gdk;
1472         guint fill_color;
1473         
1474         fill_color_gdk = gdk_color_copy (&GTK_WIDGET (widget)->style->base[GTK_STATE_SELECTED]);
1475         fill_color = ev_gdk_color_to_rgb (fill_color_gdk) << 8 | alpha;
1476
1477         pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
1478                                  rect->width, rect->height);
1479         gdk_pixbuf_fill (pixbuf, fill_color);
1480
1481         gdk_draw_pixbuf (window, NULL, pixbuf,
1482                          0, 0,
1483                          rect->x - EV_VIEW (widget)->scroll_x, rect->y - EV_VIEW (widget)->scroll_y,
1484                          rect->width, rect->height,
1485                          GDK_RGB_DITHER_NONE,
1486                          0, 0);
1487
1488         g_object_unref (pixbuf);
1489
1490         gc = gdk_gc_new (window);
1491         gdk_gc_set_rgb_fg_color (gc, fill_color_gdk);
1492         gdk_draw_rectangle (window, gc, FALSE,
1493                             rect->x - EV_VIEW (widget)->scroll_x, rect->y - EV_VIEW (widget)->scroll_y,
1494                             rect->width - 1,
1495                             rect->height - 1);
1496         g_object_unref (gc);
1497
1498         gdk_color_free (fill_color_gdk);
1499 }
1500
1501
1502 static void
1503 highlight_find_results (EvView *view, int page)
1504 {
1505         EvDocumentFind *find;
1506         int i, results = 0;
1507
1508         g_return_if_fail (EV_IS_DOCUMENT_FIND (view->document));
1509
1510         find = EV_DOCUMENT_FIND (view->document);
1511
1512         results = ev_document_find_get_n_results (find, page);
1513
1514         for (i = 0; i < results; i++) {
1515                 EvRectangle rectangle;
1516                 GdkRectangle view_rectangle;
1517                 guchar alpha;
1518
1519                 if (i == view->find_result && page == view->find_page) {
1520                         alpha = 0x90;
1521                 } else {
1522                         alpha = 0x20;
1523                 }
1524
1525                 ev_document_find_get_result (find, page,
1526                                              i, &rectangle);
1527                 doc_rect_to_view_rect (view, page, &rectangle, &view_rectangle);
1528                 draw_rubberband (GTK_WIDGET (view), GTK_WIDGET(view)->window,
1529                                  &view_rectangle, alpha);
1530         }
1531 }
1532
1533 static void
1534 draw_one_page (EvView       *view,
1535                gint          page,
1536                GdkRectangle *page_area,
1537                GtkBorder    *border,
1538                GdkRectangle *expose_area)
1539 {
1540         gint width, height;
1541         GdkPixbuf *scaled_image;
1542         GdkPixbuf *current_pixbuf;
1543         GdkRectangle overlap;
1544         GdkRectangle real_page_area;
1545
1546         g_assert (view->document);
1547         if (! gdk_rectangle_intersect (page_area, expose_area, &overlap))
1548                 return;
1549
1550         ev_page_cache_get_size (view->page_cache,
1551                                 page, view->scale,
1552                                 &width, &height);
1553         /* Render the document itself */
1554         real_page_area = *page_area;
1555
1556         real_page_area.x += border->left;
1557         real_page_area.y += border->top;
1558         real_page_area.width -= (border->left + border->right);
1559         real_page_area.height -= (border->top + border->bottom);
1560
1561         ev_document_misc_paint_one_page (GTK_WIDGET(view)->window,
1562                                          GTK_WIDGET (view),
1563                                          page_area, border);
1564
1565         if (gdk_rectangle_intersect (&real_page_area, expose_area, &overlap)) {
1566                 current_pixbuf = ev_pixbuf_cache_get_pixbuf (view->pixbuf_cache, page);
1567
1568                 if (current_pixbuf == NULL)
1569                         scaled_image = NULL;
1570                 else if (width == gdk_pixbuf_get_width (current_pixbuf) &&
1571                          height == gdk_pixbuf_get_height (current_pixbuf))
1572                         scaled_image = g_object_ref (current_pixbuf);
1573                 else
1574                         /* FIXME: We don't want to scale the whole area, just the right
1575                          * area of it */
1576                         scaled_image = gdk_pixbuf_scale_simple (current_pixbuf,
1577                                                                 width, height,
1578                                                                 GDK_INTERP_NEAREST);
1579
1580                 if (scaled_image) {
1581                         gdk_draw_pixbuf (GTK_WIDGET(view)->window,
1582                                          GTK_WIDGET (view)->style->fg_gc[GTK_STATE_NORMAL],
1583                                          scaled_image,
1584                                          overlap.x - real_page_area.x,
1585                                          overlap.y - real_page_area.y,
1586                                          overlap.x, overlap.y,
1587                                          overlap.width, overlap.height,
1588                                          GDK_RGB_DITHER_NORMAL,
1589                                          0, 0);
1590                         g_object_unref (scaled_image);
1591                 }
1592         }
1593 }
1594
1595 /*** GObject functions ***/
1596
1597 static void
1598 ev_view_finalize (GObject *object)
1599 {
1600         EvView *view = EV_VIEW (object);
1601
1602         LOG ("Finalize");
1603
1604         g_free (view->status);
1605         g_free (view->find_status);
1606
1607         clear_selection (view);
1608
1609         G_OBJECT_CLASS (ev_view_parent_class)->finalize (object);
1610 }
1611
1612 static void
1613 ev_view_destroy (GtkObject *object)
1614 {
1615         EvView *view = EV_VIEW (object);
1616
1617         if (view->document) {
1618                 g_object_unref (view->document);
1619                 view->document = NULL;
1620         }
1621         if (view->pixbuf_cache) {
1622                 g_object_unref (view->pixbuf_cache);
1623                 view->pixbuf_cache = NULL;
1624         }
1625         ev_view_set_scroll_adjustments (view, NULL, NULL);
1626
1627         GTK_OBJECT_CLASS (ev_view_parent_class)->destroy (object);
1628 }
1629
1630 static void
1631 ev_view_set_property (GObject      *object,
1632                       guint         prop_id,
1633                       const GValue *value,
1634                       GParamSpec   *pspec)
1635 {
1636         EvView *view = EV_VIEW (object);
1637
1638         switch (prop_id)
1639         {
1640         case PROP_CONTINUOUS:
1641                 ev_view_set_continuous (view, g_value_get_boolean (value));
1642                 break;
1643         case PROP_DUAL_PAGE:
1644                 ev_view_set_dual_page (view, g_value_get_boolean (value));
1645                 break;
1646         case PROP_FULLSCREEN:
1647                 ev_view_set_fullscreen (view, g_value_get_boolean (value));
1648                 break;
1649         case PROP_PRESENTATION:
1650                 ev_view_set_presentation (view, g_value_get_boolean (value));
1651                 break;
1652         case PROP_SIZING_MODE:
1653                 ev_view_set_sizing_mode (view, g_value_get_enum (value));
1654                 break;
1655         case PROP_ZOOM:
1656                 ev_view_set_zoom (view, g_value_get_double (value), FALSE);
1657                 break;
1658         default:
1659                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1660         }
1661 }
1662
1663 static void
1664 ev_view_get_property (GObject *object,
1665                       guint prop_id,
1666                       GValue *value,
1667                       GParamSpec *pspec)
1668 {
1669         EvView *view = EV_VIEW (object);
1670
1671         switch (prop_id)
1672         {
1673         case PROP_STATUS:
1674                 g_value_set_string (value, view->status);
1675                 break;
1676         case PROP_FIND_STATUS:
1677                 g_value_set_string (value, view->status);
1678                 break;
1679         case PROP_CONTINUOUS:
1680                 g_value_set_boolean (value, view->continuous);
1681                 break;
1682         case PROP_DUAL_PAGE:
1683                 g_value_set_boolean (value, view->dual_page);
1684                 break;
1685         case PROP_FULLSCREEN:
1686                 g_value_set_boolean (value, view->fullscreen);
1687                 break;
1688         case PROP_PRESENTATION:
1689                 g_value_set_boolean (value, view->presentation);
1690                 break;
1691         case PROP_SIZING_MODE:
1692                 g_value_set_enum (value, view->sizing_mode);
1693                 break;
1694         case PROP_ZOOM:
1695                 g_value_set_double (value, view->scale);
1696                 break;
1697         default:
1698                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1699         }
1700 }
1701
1702 static void
1703 ev_view_class_init (EvViewClass *class)
1704 {
1705         GObjectClass *object_class = G_OBJECT_CLASS (class);
1706         GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (class);
1707         GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
1708         GtkBindingSet *binding_set;
1709
1710         object_class->finalize = ev_view_finalize;
1711         object_class->set_property = ev_view_set_property;
1712         object_class->get_property = ev_view_get_property;
1713
1714         widget_class->expose_event = ev_view_expose_event;
1715         widget_class->button_press_event = ev_view_button_press_event;
1716         widget_class->motion_notify_event = ev_view_motion_notify_event;
1717         widget_class->button_release_event = ev_view_button_release_event;
1718         widget_class->size_request = ev_view_size_request;
1719         widget_class->size_allocate = ev_view_size_allocate;
1720         widget_class->realize = ev_view_realize;
1721         widget_class->unrealize = ev_view_unrealize;
1722         widget_class->scroll_event = ev_view_scroll_event;
1723         gtk_object_class->destroy = ev_view_destroy;
1724
1725         class->set_scroll_adjustments = ev_view_set_scroll_adjustments;
1726         class->scroll_view = ev_view_scroll_view;
1727
1728         widget_class->set_scroll_adjustments_signal =  
1729             g_signal_new ("set-scroll-adjustments",
1730                           G_OBJECT_CLASS_TYPE (object_class),
1731                           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1732                           G_STRUCT_OFFSET (EvViewClass, set_scroll_adjustments),
1733                           NULL, NULL,
1734                           ev_marshal_VOID__OBJECT_OBJECT,
1735                           G_TYPE_NONE, 2,
1736                           GTK_TYPE_ADJUSTMENT,
1737                           GTK_TYPE_ADJUSTMENT);
1738
1739         signals[SIGNAL_SCROLL_VIEW] = g_signal_new ("scroll-view",
1740                          G_TYPE_FROM_CLASS (object_class),
1741                          G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1742                          G_STRUCT_OFFSET (EvViewClass, scroll_view),
1743                          NULL, NULL,
1744                          ev_marshal_VOID__ENUM_BOOLEAN,
1745                          G_TYPE_NONE, 2,
1746                          GTK_TYPE_SCROLL_TYPE,
1747                          G_TYPE_BOOLEAN);
1748
1749         signals[SIGNAL_ZOOM_INVALID] = g_signal_new ("zoom-invalid",
1750                          G_TYPE_FROM_CLASS (object_class),
1751                          G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1752                          G_STRUCT_OFFSET (EvViewClass, zoom_invalid),
1753                          NULL, NULL,
1754                          ev_marshal_VOID__VOID,
1755                          G_TYPE_NONE, 0, G_TYPE_NONE);
1756
1757         g_object_class_install_property (object_class,
1758                                          PROP_STATUS,
1759                                          g_param_spec_string ("status",
1760                                                               "Status Message",
1761                                                               "The status message",
1762                                                               NULL,
1763                                                               G_PARAM_READABLE));
1764
1765         g_object_class_install_property (object_class,
1766                                          PROP_FIND_STATUS,
1767                                          g_param_spec_string ("find-status",
1768                                                               "Find Status Message",
1769                                                               "The find status message",
1770                                                               NULL,
1771                                                               G_PARAM_READABLE));
1772
1773         g_object_class_install_property (object_class,
1774                                          PROP_CONTINUOUS,
1775                                          g_param_spec_boolean ("continuous",
1776                                                                "Continuous",
1777                                                                "Continuous scrolling mode",
1778                                                                TRUE,
1779                                                                G_PARAM_READWRITE));
1780
1781         g_object_class_install_property (object_class,
1782                                          PROP_DUAL_PAGE,
1783                                          g_param_spec_boolean ("dual-page",
1784                                                                "Dual Page",
1785                                                                "Two pages visible at once",
1786                                                                FALSE,
1787                                                                G_PARAM_READWRITE));
1788         g_object_class_install_property (object_class,
1789                                          PROP_FULLSCREEN,
1790                                          g_param_spec_boolean ("fullscreen",
1791                                                                "Full Screen",
1792                                                                "Draw page in a fullscreen fashion",
1793                                                                FALSE,
1794                                                                G_PARAM_READWRITE));
1795         g_object_class_install_property (object_class,
1796                                          PROP_PRESENTATION,
1797                                          g_param_spec_boolean ("presentation",
1798                                                                "Presentation",
1799                                                                "Draw page in presentation mode",
1800                                                                TRUE,
1801                                                                G_PARAM_READWRITE));
1802
1803         g_object_class_install_property (object_class,
1804                                          PROP_SIZING_MODE,
1805                                          g_param_spec_enum ("sizing-mode",
1806                                                             "Sizing Mode",
1807                                                             "Sizing Mode",
1808                                                             EV_TYPE_SIZING_MODE,
1809                                                             EV_SIZING_FIT_WIDTH,
1810                                                             G_PARAM_READWRITE));
1811
1812         g_object_class_install_property (object_class,
1813                                          PROP_ZOOM,
1814                                          g_param_spec_double ("zoom",
1815                                                               "Zoom factor",
1816                                                                "Zoom factor",
1817                                                                MIN_SCALE, 
1818                                                                MAX_SCALE,
1819                                                                1.0,
1820                                                                G_PARAM_READWRITE));
1821
1822         binding_set = gtk_binding_set_by_class (class);
1823
1824         add_scroll_binding_keypad (binding_set, GDK_Left,  GTK_SCROLL_STEP_BACKWARD, TRUE);
1825         add_scroll_binding_keypad (binding_set, GDK_Right, GTK_SCROLL_STEP_FORWARD,  TRUE);
1826         add_scroll_binding_keypad (binding_set, GDK_Up,    GTK_SCROLL_STEP_BACKWARD, FALSE);
1827         add_scroll_binding_keypad (binding_set, GDK_Down,  GTK_SCROLL_STEP_FORWARD,  FALSE);
1828 }
1829
1830 static void
1831 ev_view_init (EvView *view)
1832 {
1833         GTK_WIDGET_SET_FLAGS (view, GTK_CAN_FOCUS);
1834
1835         view->spacing = 5;
1836         view->scale = 1.0;
1837         view->current_page = 0;
1838         view->pressed_button = -1;
1839         view->cursor = EV_VIEW_CURSOR_NORMAL;
1840         view->drag_info.dragging = FALSE;
1841
1842         view->continuous = TRUE;
1843         view->dual_page = FALSE;
1844         view->presentation = FALSE;
1845         view->fullscreen = FALSE;
1846         view->sizing_mode = EV_SIZING_FIT_WIDTH;
1847         view->pending_scroll = SCROLL_TO_KEEP_POSITION;
1848 }
1849
1850 /*** Callbacks ***/
1851
1852 static void
1853 find_changed_cb (EvDocument *document, int page, EvView *view)
1854 {
1855         jump_to_find_page (view);
1856         jump_to_find_result (view);
1857         update_find_status_message (view);
1858
1859         if (view->current_page == page)
1860                 gtk_widget_queue_draw (GTK_WIDGET (view));
1861 }
1862
1863 static void
1864 job_finished_cb (EvPixbufCache *pixbuf_cache,
1865                  EvView        *view)
1866 {
1867         gtk_widget_queue_draw (GTK_WIDGET (view));
1868 }
1869
1870 static void
1871 page_changed_cb (EvPageCache *page_cache,
1872                  int          new_page,
1873                  EvView      *view)
1874 {
1875         if (view->current_page != new_page) {
1876                 
1877                 view->current_page = new_page;
1878                 view->pending_scroll = SCROLL_TO_CURRENT_PAGE;
1879                 gtk_widget_queue_resize (GTK_WIDGET (view));
1880
1881                 if (EV_IS_DOCUMENT_FIND (view->document)) {
1882                         view->find_page = new_page;
1883                         view->find_result = 0;
1884                         update_find_status_message (view);
1885                 }
1886         }
1887 }
1888
1889 static void on_adjustment_value_changed (GtkAdjustment  *adjustment,
1890                                          EvView *view)
1891 {
1892         int dx = 0, dy = 0;
1893
1894         if (! GTK_WIDGET_REALIZED (view))
1895                 return;
1896
1897         if (view->hadjustment) {
1898                 dx = view->scroll_x - (int) view->hadjustment->value;
1899                 view->scroll_x = (int) view->hadjustment->value;
1900         } else {
1901                 view->scroll_x = 0;
1902         }
1903
1904         if (view->vadjustment) {
1905                 dy = view->scroll_y - (int) view->vadjustment->value;
1906                 view->scroll_y = (int) view->vadjustment->value;
1907         } else {
1908                 view->scroll_y = 0;
1909         }
1910         
1911         
1912         if (view->pending_resize)       
1913                 gtk_widget_queue_draw (GTK_WIDGET (view));
1914         else
1915                 gdk_window_scroll (GTK_WIDGET (view)->window, dx, dy);
1916
1917
1918         if (view->document)
1919                 view_update_range_and_current_page (view);}
1920
1921 GtkWidget*
1922 ev_view_new (void)
1923 {
1924         GtkWidget *view;
1925
1926         view = g_object_new (EV_TYPE_VIEW, NULL);
1927
1928         return view;
1929 }
1930
1931 void
1932 ev_view_set_document (EvView     *view,
1933                       EvDocument *document)
1934 {
1935         g_return_if_fail (EV_IS_VIEW (view));
1936
1937         if (document != view->document) {
1938                 if (view->document) {
1939                         g_signal_handlers_disconnect_by_func (view->document,
1940                                                               find_changed_cb,
1941                                                               view);
1942                         g_object_unref (view->document);
1943                         view->page_cache = NULL;
1944
1945                 }
1946
1947                 if (view->pixbuf_cache) {
1948                         g_object_unref (view->pixbuf_cache);
1949                         view->pixbuf_cache = NULL;
1950                 }
1951
1952                 view->document = document;
1953                 view->find_page = 0;
1954                 view->find_result = 0;
1955
1956                 if (view->document) {
1957                         g_object_ref (view->document);
1958                         if (EV_IS_DOCUMENT_FIND (view->document)) {
1959                                 g_signal_connect (view->document,
1960                                                   "find_changed",
1961                                                   G_CALLBACK (find_changed_cb),
1962                                                   view);
1963                         }
1964                         view->page_cache = ev_document_get_page_cache (view->document);
1965                         g_signal_connect (view->page_cache, "page-changed", G_CALLBACK (page_changed_cb), view);
1966                         view->pixbuf_cache = ev_pixbuf_cache_new (view->document);
1967                         g_signal_connect (view->pixbuf_cache, "job-finished", G_CALLBACK (job_finished_cb), view);
1968                 }
1969
1970                 gtk_widget_queue_resize (GTK_WIDGET (view));
1971         }
1972 }
1973
1974 /*** Zoom and sizing mode ***/
1975
1976 #define EPSILON 0.0000001
1977 void
1978 ev_view_set_zoom (EvView   *view,
1979                   double    factor,
1980                   gboolean  relative)
1981 {
1982         double scale;
1983
1984         if (relative)
1985                 scale = view->scale * factor;
1986         else
1987                 scale = factor;
1988
1989         scale = CLAMP (scale, MIN_SCALE, MAX_SCALE);
1990
1991         if (ABS (view->scale - scale) < EPSILON)
1992                 return;
1993
1994         view->scale = scale;
1995         view->pending_resize = TRUE;
1996         
1997         gtk_widget_queue_resize (GTK_WIDGET (view));
1998
1999         g_object_notify (G_OBJECT (view), "zoom");
2000 }
2001
2002 double
2003 ev_view_get_zoom (EvView *view)
2004 {
2005         return view->scale;
2006 }
2007
2008 void
2009 ev_view_set_continuous (EvView   *view,
2010                         gboolean  continuous)
2011 {
2012         g_return_if_fail (EV_IS_VIEW (view));
2013
2014         continuous = continuous != FALSE;
2015
2016         if (view->continuous != continuous) {
2017                 view->continuous = continuous;
2018                 view->pending_scroll = SCROLL_TO_CURRENT_PAGE;
2019                 gtk_widget_queue_resize (GTK_WIDGET (view));
2020         }
2021
2022         g_object_notify (G_OBJECT (view), "continuous");
2023 }
2024
2025 void
2026 ev_view_set_dual_page (EvView   *view,
2027                        gboolean  dual_page)
2028 {
2029         g_return_if_fail (EV_IS_VIEW (view));
2030
2031         dual_page = dual_page != FALSE;
2032
2033         if (view->dual_page == dual_page)
2034                 return;
2035     
2036         view->pending_scroll = SCROLL_TO_CURRENT_PAGE;
2037         view->dual_page = dual_page;
2038         /* FIXME: if we're keeping the pixbuf cache around, we should extend the
2039          * preload_cache_size to be 2 if dual_page is set.
2040          */
2041         gtk_widget_queue_resize (GTK_WIDGET (view));
2042
2043         g_object_notify (G_OBJECT (view), "dual-page");
2044 }
2045
2046 void
2047 ev_view_set_fullscreen (EvView   *view,
2048                          gboolean  fullscreen)
2049 {
2050         g_return_if_fail (EV_IS_VIEW (view));
2051
2052         fullscreen = fullscreen != FALSE;
2053
2054         if (view->fullscreen != fullscreen) {
2055                 view->fullscreen = fullscreen;
2056                 gtk_widget_queue_resize (GTK_WIDGET (view));
2057         }
2058
2059         g_object_notify (G_OBJECT (view), "fullscreen");
2060 }
2061
2062 gboolean
2063 ev_view_get_fullscreen (EvView *view)
2064 {
2065         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
2066
2067         return view->fullscreen;
2068 }
2069
2070 void
2071 ev_view_set_presentation (EvView   *view,
2072                           gboolean  presentation)
2073 {
2074         g_return_if_fail (EV_IS_VIEW (view));
2075
2076         presentation = presentation != FALSE;
2077
2078         if (view->presentation == presentation)
2079                 return;
2080
2081         view->presentation = presentation;
2082         gtk_widget_queue_resize (GTK_WIDGET (view));
2083         if (GTK_WIDGET_REALIZED (view)) {
2084                 if (view->presentation)
2085                         gdk_window_set_background (GTK_WIDGET(view)->window,
2086                                                    &GTK_WIDGET (view)->style->black);
2087                 else
2088                         gdk_window_set_background (GTK_WIDGET(view)->window,
2089                                                    &GTK_WIDGET (view)->style->mid [GTK_STATE_NORMAL]);
2090         }
2091
2092
2093         g_object_notify (G_OBJECT (view), "presentation");
2094 }
2095
2096 gboolean
2097 ev_view_get_presentation (EvView *view)
2098 {
2099         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
2100
2101         return view->presentation;
2102 }
2103
2104 void
2105 ev_view_set_sizing_mode (EvView       *view,
2106                          EvSizingMode  sizing_mode)
2107 {
2108         g_return_if_fail (EV_IS_VIEW (view));
2109
2110         if (view->sizing_mode == sizing_mode)
2111                 return;
2112
2113         view->sizing_mode = sizing_mode;
2114         gtk_widget_queue_resize (GTK_WIDGET (view));
2115         
2116         g_object_notify (G_OBJECT (view), "sizing-mode");
2117 }
2118
2119 EvSizingMode
2120 ev_view_get_sizing_mode (EvView *view)
2121 {
2122         g_return_val_if_fail (EV_IS_VIEW (view), EV_SIZING_FREE);
2123
2124         return view->sizing_mode;
2125 }
2126
2127 gboolean
2128 ev_view_can_zoom_in (EvView *view)
2129 {
2130         return view->scale * ZOOM_IN_FACTOR <= MAX_SCALE;
2131 }
2132
2133 gboolean
2134 ev_view_can_zoom_out (EvView *view)
2135 {
2136         return view->scale * ZOOM_OUT_FACTOR >= MIN_SCALE;
2137 }
2138
2139 void
2140 ev_view_zoom_in (EvView *view)
2141 {
2142         g_return_if_fail (view->sizing_mode == EV_SIZING_FREE);
2143         
2144         view->pending_scroll = SCROLL_TO_CENTER;
2145         ev_view_set_zoom (view, ZOOM_IN_FACTOR, TRUE);
2146 }
2147
2148 void
2149 ev_view_zoom_out (EvView *view)
2150 {
2151         g_return_if_fail (view->sizing_mode == EV_SIZING_FREE);
2152
2153         view->pending_scroll = SCROLL_TO_CENTER;
2154         ev_view_set_zoom (view, ZOOM_OUT_FACTOR, TRUE);
2155 }
2156
2157 static double
2158 zoom_for_size_fit_width (int doc_width,
2159                          int doc_height,
2160                          int target_width,
2161                          int target_height,
2162                          int vsb_width)
2163 {
2164         double scale;
2165
2166         scale = (double)target_width / doc_width;
2167
2168         if (doc_height * scale > target_height)
2169                 scale = (double) (target_width - vsb_width) / doc_width;
2170
2171         return scale;
2172 }
2173
2174 static double
2175 zoom_for_size_best_fit (int doc_width,
2176                         int doc_height,
2177                         int target_width,
2178                         int target_height,
2179                         int vsb_width,
2180                         int hsb_width)
2181 {
2182         double w_scale;
2183         double h_scale;
2184
2185         w_scale = (double)target_width / doc_width;
2186         h_scale = (double)target_height / doc_height;
2187
2188         if (doc_height * w_scale > target_height)
2189                 w_scale = (double) (target_width - vsb_width) / doc_width;
2190         if (doc_width * h_scale > target_width)
2191                 h_scale = (double) (target_height - hsb_width) / doc_height;
2192
2193         return MIN (w_scale, h_scale);
2194 }
2195
2196
2197 static void
2198 ev_view_zoom_for_size_presentation (EvView *view,
2199                                     int     width,
2200                                     int     height)
2201 {
2202         int doc_width, doc_height;
2203         gdouble scale;
2204
2205         ev_page_cache_get_size (view->page_cache,
2206                                 view->current_page,
2207                                 1.0,
2208                                 &doc_width,
2209                                 &doc_height);
2210         scale = zoom_for_size_best_fit (doc_width, doc_height, width, height, 0, 0);
2211         ev_view_set_zoom (view, scale, FALSE);
2212 }
2213
2214 static void
2215 ev_view_zoom_for_size_continuous_and_dual_page (EvView *view,
2216                            int     width,
2217                            int     height,
2218                            int     vsb_width,
2219                            int     hsb_height)
2220 {
2221         int doc_width, doc_height;
2222         GtkBorder border;
2223         gdouble scale;
2224
2225         ev_page_cache_get_max_width_size (view->page_cache,
2226                                           1.0,
2227                                           &doc_width, NULL);
2228         ev_page_cache_get_max_height_size (view->page_cache,
2229                                            1.0,
2230                                            NULL, &doc_height);
2231         compute_border (view, doc_width, doc_height, &border);
2232
2233         doc_width = doc_width * 2;
2234         width -= (2 * (border.left + border.right) + 3 * view->spacing);
2235         height -= (border.top + border.bottom + 2 * view->spacing - 1);
2236
2237         /* FIXME: We really need to calculate the overall height here, not the
2238          * page height.  We assume there's always a vertical scrollbar for
2239          * now.  We need to fix this. */
2240         if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
2241                 scale = zoom_for_size_fit_width (doc_width, doc_height, width - vsb_width, height, 0);
2242         else if (view->sizing_mode == EV_SIZING_BEST_FIT)
2243                 scale = zoom_for_size_best_fit (doc_width, doc_height, width - vsb_width, height, 0, hsb_height);
2244         else
2245                 g_assert_not_reached ();
2246
2247         ev_view_set_zoom (view, scale, FALSE);
2248 }
2249
2250 static void
2251 ev_view_zoom_for_size_continuous (EvView *view,
2252                                   int     width,
2253                                   int     height,
2254                                   int     vsb_width,
2255                                   int     hsb_height)
2256 {
2257         int doc_width, doc_height;
2258         GtkBorder border;
2259         gdouble scale;
2260
2261         ev_page_cache_get_max_width_size (view->page_cache,
2262                                           1.0,
2263                                           &doc_width, NULL);
2264         ev_page_cache_get_max_height_size (view->page_cache,
2265                                            1.0,
2266                                            NULL, &doc_height);
2267         compute_border (view, doc_width, doc_height, &border);
2268
2269         width -= (border.left + border.right + 2 * view->spacing);
2270         height -= (border.top + border.bottom + 2 * view->spacing - 1);
2271
2272         /* FIXME: We really need to calculate the overall height here, not the
2273          * page height.  We assume there's always a vertical scrollbar for
2274          * now.  We need to fix this. */
2275         if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
2276                 scale = zoom_for_size_fit_width (doc_width, doc_height, width - vsb_width, height, 0);
2277         else if (view->sizing_mode == EV_SIZING_BEST_FIT)
2278                 scale = zoom_for_size_best_fit (doc_width, doc_height, width - vsb_width, height, 0, hsb_height);
2279         else
2280                 g_assert_not_reached ();
2281
2282         ev_view_set_zoom (view, scale, FALSE);
2283 }
2284
2285 static void
2286 ev_view_zoom_for_size_dual_page (EvView *view,
2287                                  int     width,
2288                                  int     height,
2289                                  int     vsb_width,
2290                                  int     hsb_height)
2291 {
2292         GtkBorder border;
2293         gint doc_width, doc_height;
2294         gdouble scale;
2295         gint other_page;
2296
2297         other_page = view->current_page ^ 1;
2298
2299         /* Find the largest of the two. */
2300         ev_page_cache_get_size (view->page_cache,
2301                                 view->current_page,
2302                                 1.0,
2303                                 &doc_width, &doc_height);
2304
2305         if (other_page < ev_page_cache_get_n_pages (view->page_cache)) {
2306                 gint width_2, height_2;
2307                 ev_page_cache_get_size (view->page_cache,
2308                                         other_page,
2309                                         1.0,
2310                                         &width_2, &height_2);
2311                 if (width_2 > doc_width)
2312                         doc_width = width_2;
2313                 if (height_2 > doc_height)
2314                         doc_height = height_2;
2315         }
2316         compute_border (view, doc_width, doc_height, &border);
2317
2318         doc_width = doc_width * 2;
2319         width -= ((border.left + border.right)* 2 + 3 * view->spacing);
2320         height -= (border.top + border.bottom + 2 * view->spacing);
2321
2322         if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
2323                 scale = zoom_for_size_fit_width (doc_width, doc_height, width, height, vsb_width);
2324         else if (view->sizing_mode == EV_SIZING_BEST_FIT)
2325                 scale = zoom_for_size_best_fit (doc_width, doc_height, width, height, vsb_width, hsb_height);
2326         else
2327                 g_assert_not_reached ();
2328
2329         ev_view_set_zoom (view, scale, FALSE);
2330 }
2331
2332 static void
2333 ev_view_zoom_for_size_single_page (EvView *view,
2334                                    int     width,
2335                                    int     height,
2336                                    int     vsb_width,
2337                                    int     hsb_height)
2338 {
2339         int doc_width, doc_height;
2340         GtkBorder border;
2341         gdouble scale;
2342
2343         ev_page_cache_get_size (view->page_cache,
2344                                 view->current_page,
2345                                 1.0,
2346                                 &doc_width,
2347                                 &doc_height);
2348         /* Get an approximate border */
2349         compute_border (view, width, height, &border);
2350
2351         width -= (border.left + border.right + 2 * view->spacing);
2352         height -= (border.top + border.bottom + 2 * view->spacing);
2353
2354         if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
2355                 scale = zoom_for_size_fit_width (doc_width, doc_height, width, height, vsb_width);
2356         else if (view->sizing_mode == EV_SIZING_BEST_FIT)
2357                 scale = zoom_for_size_best_fit (doc_width, doc_height, width, height, vsb_width, hsb_height);
2358         else
2359                 g_assert_not_reached ();
2360
2361         ev_view_set_zoom (view, scale, FALSE);
2362 }
2363
2364 void
2365 ev_view_set_zoom_for_size (EvView *view,
2366                            int     width,
2367                            int     height,
2368                            int     vsb_width,
2369                            int     hsb_height)
2370 {       
2371         g_return_if_fail (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
2372                           view->sizing_mode == EV_SIZING_BEST_FIT);
2373         g_return_if_fail (width >= 0);
2374         g_return_if_fail (height >= 0);
2375
2376         if (view->document == NULL)
2377                 return;
2378
2379         if (view->presentation)
2380                 ev_view_zoom_for_size_presentation (view, width, height);
2381         else if (view->continuous && view->dual_page)
2382                 ev_view_zoom_for_size_continuous_and_dual_page (view, width, height, vsb_width, hsb_height);
2383         else if (view->continuous)
2384                 ev_view_zoom_for_size_continuous (view, width, height, vsb_width, hsb_height);
2385         else if (view->dual_page)
2386                 ev_view_zoom_for_size_dual_page (view, width, height, vsb_width, hsb_height);
2387         else
2388                 ev_view_zoom_for_size_single_page (view, width, height, vsb_width, hsb_height);
2389 }
2390
2391 /*** Status text messages ***/
2392
2393 const char *
2394 ev_view_get_status (EvView *view)
2395 {
2396         g_return_val_if_fail (EV_IS_VIEW (view), NULL);
2397
2398         return view->status;
2399 }
2400
2401 static void
2402 ev_view_set_status (EvView *view, const char *message)
2403 {
2404         g_return_if_fail (EV_IS_VIEW (view));
2405
2406         if (message != view->status) {
2407                 g_free (view->status);
2408                 view->status = g_strdup (message);
2409                 g_object_notify (G_OBJECT (view), "status");
2410         }
2411 }
2412
2413 static void
2414 update_find_status_message (EvView *view)
2415 {
2416         char *message;
2417
2418         if (view->current_page == view->find_page) {
2419                 int results;
2420
2421                 results = ev_document_find_get_n_results
2422                                 (EV_DOCUMENT_FIND (view->document),
2423                                  view->current_page);
2424                 /* TRANS: Sometimes this could be better translated as
2425                    "%d hit(s) on this page".  Therefore this string
2426                    contains plural cases. */
2427                 message = g_strdup_printf (ngettext ("%d found on this page",
2428                                                      "%d found on this page",
2429                                                      results),
2430                                            results);
2431         } else {
2432                 double percent;
2433
2434                 percent = ev_document_find_get_progress
2435                                 (EV_DOCUMENT_FIND (view->document));
2436                 if (percent >= (1.0 - 1e-10)) {
2437                         message = g_strdup (_("Not found"));
2438                 } else {
2439                         message = g_strdup_printf (_("%3d%% remaining to search"),
2440                                                    (int) ((1.0 - percent) * 100));
2441                 }
2442
2443         }
2444         ev_view_set_find_status (view, message);
2445 }
2446
2447 const char *
2448 ev_view_get_find_status (EvView *view)
2449 {
2450         g_return_val_if_fail (EV_IS_VIEW (view), NULL);
2451
2452         return view->find_status;
2453 }
2454
2455 static void
2456 ev_view_set_find_status (EvView *view, const char *message)
2457 {
2458         g_return_if_fail (EV_IS_VIEW (view));
2459
2460         g_free (view->find_status);
2461         view->find_status = g_strdup (message);
2462         g_object_notify (G_OBJECT (view), "find-status");
2463 }
2464
2465 /*** Find ***/
2466
2467 static void
2468 jump_to_find_result (EvView *view)
2469 {
2470         EvDocumentFind *find = EV_DOCUMENT_FIND (view->document);
2471         EvRectangle rect;
2472         GdkRectangle view_rect;
2473         int n_results;
2474         int page = view->find_page;
2475
2476         n_results = ev_document_find_get_n_results (find, page);
2477
2478         if (n_results > view->find_result) {
2479                 ev_document_find_get_result
2480                         (find, page, view->find_result, &rect);
2481
2482                 doc_rect_to_view_rect (view, page, &rect, &view_rect);
2483                 ensure_rectangle_is_visible (view, &view_rect);
2484         }
2485 }
2486
2487 static void
2488 jump_to_find_page (EvView *view)
2489 {
2490         int n_pages, i;
2491
2492         n_pages = ev_page_cache_get_n_pages (view->page_cache);
2493
2494         for (i = 0; i < n_pages; i++) {
2495                 int has_results;
2496                 int page;
2497
2498                 page = i + view->find_page;
2499                 if (page >= n_pages) {
2500                         page = page - n_pages;
2501                 }
2502
2503                 has_results = ev_document_find_page_has_results
2504                                 (EV_DOCUMENT_FIND (view->document), page);
2505                 if (has_results == -1) {
2506                         view->find_page = page;
2507                         break;
2508                 } else if (has_results == 1) {
2509                         ev_page_cache_set_current_page (view->page_cache, page);
2510                         jump_to_find_result (view);
2511                         break;
2512                 }
2513         }
2514 }
2515
2516 gboolean
2517 ev_view_can_find_next (EvView *view)
2518 {
2519         int n_results = 0;
2520
2521         if (EV_IS_DOCUMENT_FIND (view->document)) {
2522                 EvDocumentFind *find = EV_DOCUMENT_FIND (view->document);
2523
2524                 n_results = ev_document_find_get_n_results (find, view->current_page);
2525         }
2526
2527         return n_results > 0;
2528 }
2529
2530 void
2531 ev_view_find_next (EvView *view)
2532 {
2533         EvPageCache *page_cache;
2534         int n_results, n_pages;
2535         EvDocumentFind *find = EV_DOCUMENT_FIND (view->document);
2536
2537         page_cache = ev_document_get_page_cache (view->document);
2538         n_results = ev_document_find_get_n_results (find, view->current_page);
2539
2540         n_pages = ev_page_cache_get_n_pages (page_cache);
2541
2542         view->find_result++;
2543
2544         if (view->find_result >= n_results) {
2545                 view->find_result = 0;
2546                 view->find_page++;
2547
2548                 if (view->find_page >= n_pages) {
2549                         view->find_page = 0;
2550                 }
2551
2552                 jump_to_find_page (view);
2553         } else {
2554                 jump_to_find_result (view);
2555                 gtk_widget_queue_draw (GTK_WIDGET (view));
2556         }
2557 }
2558
2559 void
2560 ev_view_find_previous (EvView *view)
2561 {
2562         int n_results, n_pages;
2563         EvDocumentFind *find = EV_DOCUMENT_FIND (view->document);
2564         EvPageCache *page_cache;
2565
2566         page_cache = ev_document_get_page_cache (view->document);
2567
2568         n_results = ev_document_find_get_n_results (find, view->current_page);
2569
2570         n_pages = ev_page_cache_get_n_pages (page_cache);
2571
2572         view->find_result--;
2573
2574         if (view->find_result < 0) {
2575                 view->find_result = 0;
2576                 view->find_page--;
2577
2578                 if (view->find_page < 0) {
2579                         view->find_page = n_pages - 1;
2580                 }
2581
2582                 jump_to_find_page (view);
2583         } else {
2584                 jump_to_find_result (view);
2585                 gtk_widget_queue_draw (GTK_WIDGET (view));
2586         }
2587 }
2588
2589 /*** Selections ***/
2590
2591 static void
2592 compute_selections (EvView *view, GdkRectangle *view_rect)
2593 {
2594         int n_pages, i;
2595
2596         clear_selection (view);
2597
2598         n_pages = ev_page_cache_get_n_pages (view->page_cache);
2599         for (i = 0; i < n_pages; i++) {
2600                 GdkRectangle page_area;
2601                 GtkBorder border;
2602
2603                 if (get_page_extents (view, i, &page_area, &border)) {
2604                         GdkRectangle overlap;
2605
2606                         if (gdk_rectangle_intersect (&page_area, view_rect, &overlap)) {
2607                                 EvViewSelection *selection;
2608
2609                                 selection = g_new0 (EvViewSelection, 1);
2610                                 selection->page = i;
2611                                 view_rect_to_doc_rect (view, &overlap, &page_area,
2612                                                        &(selection->rect));
2613
2614                                 view->selections = g_list_append
2615                                                 (view->selections, selection);
2616                         }
2617                 }
2618         }
2619 }
2620
2621 static void
2622 clear_selection (EvView *view)
2623 {
2624         g_list_foreach (view->selections, (GFunc)g_free, NULL);
2625         view->selections = NULL;
2626 }
2627
2628
2629 void
2630 ev_view_select_all (EvView *view)
2631 {
2632         int n_pages, i;
2633
2634         clear_selection (view);
2635
2636         n_pages = ev_page_cache_get_n_pages (view->page_cache);
2637         for (i = 0; i < n_pages; i++) {
2638                 int width, height;
2639                 EvViewSelection *selection;
2640
2641                 ev_page_cache_get_size (view->page_cache,
2642                                         i, 1.0, &width, &height);
2643
2644                 selection = g_new0 (EvViewSelection, 1);
2645                 selection->page = i;
2646                 selection->rect.x1 = selection->rect.y1 = 0;
2647                 selection->rect.x2 = width;
2648                 selection->rect.y2 = height;
2649
2650                 view->selections = g_list_append (view->selections, selection);
2651         }
2652
2653         gtk_widget_queue_draw (GTK_WIDGET (view));
2654 }
2655
2656 static char *
2657 get_selected_text (EvView *ev_view)
2658 {
2659         GString *text;
2660         GList *l;
2661
2662         text = g_string_new (NULL);
2663
2664         ev_document_doc_mutex_lock ();
2665
2666         for (l = ev_view->selections; l != NULL; l = l->next) {
2667                 EvViewSelection *selection = (EvViewSelection *)l->data;
2668                 char *tmp;
2669
2670                 tmp = ev_document_get_text (ev_view->document,
2671                                             selection->page,
2672                                             &selection->rect);
2673                 g_string_append (text, tmp);
2674                 g_free (tmp);
2675         }
2676
2677         ev_document_doc_mutex_unlock ();
2678
2679         return g_string_free (text, FALSE);
2680 }
2681
2682 void
2683 ev_view_copy (EvView *ev_view)
2684 {
2685         GtkClipboard *clipboard;
2686         char *text;
2687
2688         if (!ev_document_can_get_text (ev_view->document)) {
2689                 return;
2690         }
2691
2692         text = get_selected_text (ev_view);
2693         clipboard = gtk_widget_get_clipboard (GTK_WIDGET (ev_view),
2694                                               GDK_SELECTION_CLIPBOARD);
2695         gtk_clipboard_set_text (clipboard, text, -1);
2696         g_free (text);
2697 }
2698
2699 static void
2700 ev_view_primary_get_cb (GtkClipboard     *clipboard,
2701                         GtkSelectionData *selection_data,
2702                         guint             info,
2703                         gpointer          data)
2704 {
2705         EvView *ev_view = EV_VIEW (data);
2706         char *text;
2707
2708         if (!ev_document_can_get_text (ev_view->document)) {
2709                 return;
2710         }
2711
2712         text = get_selected_text (ev_view);
2713         gtk_selection_data_set_text (selection_data, text, -1);
2714         g_free (text);
2715 }
2716
2717 static void
2718 ev_view_primary_clear_cb (GtkClipboard *clipboard,
2719                           gpointer      data)
2720 {
2721         EvView *view = EV_VIEW (data);
2722
2723         clear_selection (view);
2724 }
2725
2726 static void
2727 ev_view_update_primary_selection (EvView *ev_view)
2728 {
2729         GtkClipboard *clipboard;
2730
2731         clipboard = gtk_widget_get_clipboard (GTK_WIDGET (ev_view),
2732                                               GDK_SELECTION_PRIMARY);
2733
2734         if (ev_view->selections) {
2735                 if (!gtk_clipboard_set_with_owner (clipboard,
2736                                                    targets,
2737                                                    G_N_ELEMENTS (targets),
2738                                                    ev_view_primary_get_cb,
2739                                                    ev_view_primary_clear_cb,
2740                                                    G_OBJECT (ev_view)))
2741                         ev_view_primary_clear_cb (clipboard, ev_view);
2742         } else {
2743                 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (ev_view))
2744                         gtk_clipboard_clear (clipboard);
2745         }
2746 }
2747
2748 /*** Cursor operations ***/
2749
2750 static GdkCursor *
2751 ev_view_create_invisible_cursor(void)
2752 {
2753        GdkBitmap *empty;
2754        GdkColor black = { 0, 0, 0, 0 };
2755        static char bits[] = { 0x00 };
2756
2757        empty = gdk_bitmap_create_from_data (NULL, bits, 1, 1);
2758
2759        return gdk_cursor_new_from_pixmap (empty, empty, &black, &black, 0, 0);
2760 }
2761
2762 static void
2763 ev_view_set_cursor (EvView *view, EvViewCursor new_cursor)
2764 {
2765         GdkCursor *cursor = NULL;
2766         GdkDisplay *display;
2767         GtkWidget *widget;
2768
2769         if (view->cursor == new_cursor) {
2770                 return;
2771         }
2772
2773         widget = gtk_widget_get_toplevel (GTK_WIDGET (view));
2774         display = gtk_widget_get_display (widget);
2775         view->cursor = new_cursor;
2776
2777         switch (new_cursor) {
2778                 case EV_VIEW_CURSOR_NORMAL:
2779                         gdk_window_set_cursor (widget->window, NULL);
2780                         break;
2781                 case EV_VIEW_CURSOR_LINK:
2782                         cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
2783                         break;
2784                 case EV_VIEW_CURSOR_WAIT:
2785                         cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
2786                         break;
2787                 case EV_VIEW_CURSOR_HIDDEN:
2788                         cursor = ev_view_create_invisible_cursor ();
2789                         break;
2790                 case EV_VIEW_CURSOR_DRAG:
2791                         cursor = gdk_cursor_new_for_display (display, GDK_FLEUR);
2792                         break;
2793         }
2794
2795         if (cursor) {
2796                 gdk_window_set_cursor (widget->window, cursor);
2797                 gdk_cursor_unref (cursor);
2798                 gdk_flush();
2799         }
2800 }
2801
2802 void
2803 ev_view_hide_cursor (EvView *view)
2804 {
2805        ev_view_set_cursor (view, EV_VIEW_CURSOR_HIDDEN);
2806 }
2807
2808 void
2809 ev_view_show_cursor (EvView *view)
2810 {
2811        ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
2812 }
2813
2814 /*** Enum description for usage in signal ***/
2815
2816 GType
2817 ev_sizing_mode_get_type (void)
2818 {
2819   static GType etype = 0;
2820   if (etype == 0) {
2821     static const GEnumValue values[] = {
2822       { EV_SIZING_FIT_WIDTH, "EV_SIZING_FIT_WIDTH", "fit-width" },
2823       { EV_SIZING_BEST_FIT, "EV_SIZING_BEST_FIT", "best-fit" },
2824       { EV_SIZING_FREE, "EV_SIZING_FREE", "free" },
2825       { 0, NULL, NULL }
2826     };
2827     etype = g_enum_register_static ("EvSizingMode", values);
2828   }
2829   return etype;
2830 }
2831