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