]> www.fi.muni.cz Git - evince.git/blob - shell/ev-view.c
468a8946acd72e84f6efe5429320872f80e90691
[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 <stdlib.h>
22 #include <math.h>
23 #include <string.h>
24 #include <gtk/gtkalignment.h>
25 #include <glib/gi18n.h>
26 #include <gtk/gtkbindings.h>
27 #include <gtk/gtkselection.h>
28 #include <gtk/gtkclipboard.h>
29 #include <gdk/gdkkeysyms.h>
30
31 #include "ev-marshal.h"
32 #include "ev-view.h"
33 #include "ev-view-private.h"
34 #include "ev-utils.h"
35 #include "ev-selection.h"
36 #include "ev-document-links.h"
37 #include "ev-document-images.h"
38 #include "ev-document-find.h"
39 #include "ev-document-transition.h"
40 #include "ev-document-forms.h"
41 #include "ev-document-misc.h"
42 #include "ev-job-queue.h"
43 #include "ev-page-cache.h"
44 #include "ev-pixbuf-cache.h"
45 #include "ev-tooltip.h"
46 #include "ev-application.h"
47
48 #define EV_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_VIEW, EvViewClass))
49 #define EV_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_VIEW))
50 #define EV_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_VIEW, EvViewClass))
51
52
53 enum {
54         PROP_0,
55         PROP_STATUS,
56         PROP_FIND_STATUS,
57         PROP_CONTINUOUS,
58         PROP_DUAL_PAGE,
59         PROP_FULLSCREEN,
60         PROP_PRESENTATION,
61         PROP_SIZING_MODE,
62         PROP_ZOOM,
63         PROP_ROTATION,
64         PROP_HAS_SELECTION,
65 };
66
67 enum {
68         SIGNAL_BINDING_ACTIVATED,
69         SIGNAL_ZOOM_INVALID,
70         SIGNAL_HANDLE_LINK,
71         SIGNAL_EXTERNAL_LINK,
72         SIGNAL_POPUP_MENU,
73         N_SIGNALS,
74 };
75
76 enum {
77         TARGET_DND_URI,
78         TARGET_DND_TEXT,
79         TARGET_DND_IMAGE
80 };
81
82 enum {
83         TARGET_STRING,
84         TARGET_TEXT,
85         TARGET_COMPOUND_TEXT,
86         TARGET_UTF8_STRING,
87         TARGET_TEXT_BUFFER_CONTENTS
88 };
89
90 static const GtkTargetEntry clipboard_targets[] = {
91         { "STRING", 0, TARGET_STRING },
92         { "TEXT",   0, TARGET_TEXT },
93         { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
94         { "UTF8_STRING", 0, TARGET_UTF8_STRING },
95 };
96
97 static const GtkTargetEntry view_drop_targets[] = {
98         { "text/uri-list", 0, 0 }
99 };
100
101 static guint signals[N_SIGNALS];
102
103 typedef enum {
104         EV_VIEW_FIND_NEXT,
105         EV_VIEW_FIND_PREV
106 } EvViewFindDirection;
107
108 #define ZOOM_IN_FACTOR  1.2
109 #define ZOOM_OUT_FACTOR (1.0/ZOOM_IN_FACTOR)
110
111 #define MIN_SCALE 0.05409
112 #define MAX_SCALE 4.0
113
114 #define SCROLL_TIME 150
115
116 /*** Scrolling ***/
117 static void       scroll_to_current_page                     (EvView *view,
118                                                               GtkOrientation orientation);
119 static void       ev_view_set_scroll_adjustments             (GtkLayout          *layout,
120                                                               GtkAdjustment      *hadjustment,
121                                                               GtkAdjustment      *vadjustment);
122 static void       view_update_range_and_current_page         (EvView             *view);
123 static void       set_scroll_adjustment                      (EvView             *view,
124                                                               GtkOrientation      orientation,
125                                                               GtkAdjustment      *adjustment);
126 static void       add_scroll_binding_keypad                  (GtkBindingSet      *binding_set,
127                                                               guint               keyval,
128                                                               GdkModifierType modifiers,
129                                                               EvScrollType       scroll,
130                                                               gboolean            horizontal);
131 static void       ensure_rectangle_is_visible                (EvView             *view,
132                                                               GdkRectangle       *rect);
133
134 /*** Geometry computations ***/
135 static void       compute_border                             (EvView             *view,
136                                                               int                 width,
137                                                               int                 height,
138                                                               GtkBorder          *border);
139 static void       get_page_y_offset                          (EvView *view,
140                                                               int page,
141                                                               double zoom,
142                                                               int *y_offset);
143 static gboolean   get_page_extents                           (EvView             *view,
144                                                               gint                page,
145                                                               GdkRectangle       *page_area,
146                                                               GtkBorder          *border);
147 static void       view_rect_to_doc_rect                      (EvView             *view,
148                                                               GdkRectangle       *view_rect,
149                                                               GdkRectangle       *page_area,
150                                                               EvRectangle        *doc_rect);
151 static void       doc_rect_to_view_rect                      (EvView             *view,
152                                                               int                 page,
153                                                               EvRectangle        *doc_rect,
154                                                               GdkRectangle       *view_rect);
155 static void       find_page_at_location                      (EvView             *view,
156                                                               gdouble             x,
157                                                               gdouble             y,
158                                                               gint               *page,
159                                                               gint               *x_offset,
160                                                               gint               *y_offset);
161 static gboolean  doc_point_to_view_point                     (EvView             *view,
162                                                               int                 page,
163                                                               EvPoint            *doc_point,
164                                                               GdkPoint           *view_point);
165 /*** Hyperrefs ***/
166 static EvLink *   ev_view_get_link_at_location               (EvView             *view,
167                                                               gdouble             x,
168                                                               gdouble             y);
169 static char*      tip_from_link                              (EvView             *view,
170                                                               EvLink             *link);
171 /*** Forms ***/
172 static EvFormField *ev_view_get_form_field_at_location       (EvView             *view,
173                                                                gdouble            x,
174                                                                gdouble            y);
175
176 /*** GtkWidget implementation ***/
177 static void       ev_view_size_request_continuous_dual_page  (EvView             *view,
178                                                               GtkRequisition     *requisition);
179 static void       ev_view_size_request_continuous            (EvView             *view,
180                                                               GtkRequisition     *requisition);
181 static void       ev_view_size_request_dual_page             (EvView             *view,
182                                                               GtkRequisition     *requisition);
183 static void       ev_view_size_request_single_page           (EvView             *view,
184                                                               GtkRequisition     *requisition);
185 static void       ev_view_size_request                       (GtkWidget          *widget,
186                                                               GtkRequisition     *requisition);
187 static void       ev_view_size_allocate                      (GtkWidget          *widget,
188                                                               GtkAllocation      *allocation);
189 static void       ev_view_realize                            (GtkWidget          *widget);
190 static gboolean   ev_view_scroll_event                       (GtkWidget          *widget,
191                                                               GdkEventScroll     *event);
192 static gboolean   ev_view_expose_event                       (GtkWidget          *widget,
193                                                               GdkEventExpose     *event);
194 static gboolean   ev_view_popup_menu                         (GtkWidget          *widget);
195 static gboolean   ev_view_button_press_event                 (GtkWidget          *widget,
196                                                               GdkEventButton     *event);
197 static gboolean   ev_view_motion_notify_event                (GtkWidget          *widget,
198                                                               GdkEventMotion     *event);
199 static gboolean   ev_view_button_release_event               (GtkWidget          *widget,
200                                                               GdkEventButton     *event);
201 static gboolean   ev_view_enter_notify_event                 (GtkWidget          *widget,
202                                                               GdkEventCrossing   *event);
203 static gboolean   ev_view_leave_notify_event                 (GtkWidget          *widget,
204                                                               GdkEventCrossing   *event);
205 static void       ev_view_style_set                          (GtkWidget          *widget,
206                                                               GtkStyle           *old_style);
207 static void       ev_view_remove_all                         (EvView             *view);
208
209 static AtkObject *ev_view_get_accessible                     (GtkWidget *widget);
210
211 /*** Drawing ***/
212 static guint32    ev_gdk_color_to_rgb                        (const GdkColor     *color);
213 static void       draw_rubberband                            (GtkWidget          *widget,
214                                                               GdkWindow          *window,
215                                                               const GdkRectangle *rect,
216                                                               guchar              alpha);
217 static void       highlight_find_results                     (EvView             *view,
218                                                               int                 page);
219 static void       draw_one_page                              (EvView             *view,
220                                                               gint                page,
221                                                               GdkRectangle       *page_area,
222                                                               GtkBorder          *border,
223                                                               GdkRectangle       *expose_area,
224                                                               gboolean           *page_ready);
225 static void       draw_loading_text                          (EvView             *view,
226                                                               GdkRectangle       *page_area,
227                                                               GdkRectangle       *expose_area);
228
229 /*** Callbacks ***/
230 static void       find_changed_cb                            (EvDocument         *document,
231                                                               int                 page,
232                                                               EvView             *view);
233 static void       job_finished_cb                            (EvPixbufCache      *pixbuf_cache,
234                                                               EvView             *view);
235 static void       page_changed_cb                            (EvPageCache        *page_cache,
236                                                               int                 new_page,
237                                                               EvView             *view);
238 static void       on_adjustment_value_changed                (GtkAdjustment      *adjustment,
239                                                               EvView             *view);
240
241 /*** GObject ***/
242 static void       ev_view_finalize                           (GObject            *object);
243 static void       ev_view_destroy                            (GtkObject          *object);
244 static void       ev_view_set_property                       (GObject            *object,
245                                                               guint               prop_id,
246                                                               const GValue       *value,
247                                                               GParamSpec         *pspec);
248 static void       ev_view_get_property                       (GObject            *object,
249                                                               guint               prop_id,
250                                                               GValue             *value,
251                                                               GParamSpec         *pspec);
252 static void       ev_view_class_init                         (EvViewClass        *class);
253 static void       ev_view_init                               (EvView             *view);
254
255 /*** Zoom and sizing ***/
256 static double   zoom_for_size_fit_width                      (int doc_width,
257                                                               int doc_height,
258                                                               int target_width,
259                                                               int target_height,
260                                                               int vsb_width);
261 static double   zoom_for_size_fit_height                     (int doc_width,
262                                                               int doc_height,
263                                                               int target_width,
264                                                               int target_height,
265                                                               int vsb_height);
266 static double   zoom_for_size_best_fit                       (int doc_width,
267                                                               int doc_height,
268                                                               int target_width,
269                                                               int target_height,
270                                                               int vsb_width,
271                                                               int hsb_width);
272 static void     ev_view_zoom_for_size_presentation           (EvView *view,
273                                                               int     width,
274                                                               int     height);
275 static void     ev_view_zoom_for_size_continuous_and_dual_page (EvView *view,
276                                                                 int     width,
277                                                                 int     height,
278                                                                 int     vsb_width,
279                                                                 int     hsb_height);
280 static void     ev_view_zoom_for_size_continuous               (EvView *view,
281                                                                 int     width,
282                                                                 int     height,
283                                                                 int     vsb_width,
284                                                                 int     hsb_height);
285 static void     ev_view_zoom_for_size_dual_page                (EvView *view,
286                                                                 int     width,
287                                                                 int     height,
288                                                                 int     vsb_width,
289                                                                 int     hsb_height);
290 static void     ev_view_zoom_for_size_single_page              (EvView *view,
291                                                                 int     width,
292                                                                 int     height,
293                                                                 int     vsb_width,
294                                                                 int     hsb_height);
295 /*** Cursors ***/
296 static GdkCursor* ev_view_create_invisible_cursor            (void);
297 static void       ev_view_set_cursor                         (EvView             *view,
298                                                               EvViewCursor        new_cursor);
299 static void       ev_view_handle_cursor_over_xy              (EvView *view,
300                                                               gint x,
301                                                               gint y);
302
303 /*** Status messages ***/
304 static void       ev_view_set_status                         (EvView             *view,
305                                                               const char         *message);
306 static void       update_find_status_message                 (EvView             *view,
307                                                               gboolean            this_page);
308 static void       ev_view_set_find_status                    (EvView             *view,
309                                                               const char         *message);
310 /*** Find ***/
311 static void       jump_to_find_result                        (EvView             *view);
312 static void       jump_to_find_page                          (EvView             *view, 
313                                                               EvViewFindDirection direction,
314                                                               gint                shift);
315
316 /*** Selection ***/
317 static void       compute_selections                         (EvView             *view,
318                                                               GdkPoint           *start,
319                                                               GdkPoint           *stop);
320 static void       clear_selection                            (EvView             *view);
321 static void       selection_free                             (EvViewSelection    *selection);
322 static char*      get_selected_text                          (EvView             *ev_view);
323 static void       ev_view_primary_get_cb                     (GtkClipboard       *clipboard,
324                                                               GtkSelectionData   *selection_data,
325                                                               guint               info,
326                                                               gpointer            data);
327 static void       ev_view_primary_clear_cb                   (GtkClipboard       *clipboard,
328                                                               gpointer            data);
329 static void       ev_view_update_primary_selection           (EvView             *ev_view);
330
331 /*** Presentation ***/
332 static void       ev_view_presentation_transition_start      (EvView             *ev_view);
333 static void       ev_view_presentation_transition_stop       (EvView             *ev_view);
334
335
336 G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_LAYOUT)
337
338 static void
339 scroll_to_current_page (EvView *view, GtkOrientation orientation)
340 {
341         GdkPoint view_point;
342
343         if (view->document == NULL) {
344                 return;
345         }
346
347         doc_point_to_view_point (view, view->current_page, &view->pending_point, &view_point);
348
349         if (orientation == GTK_ORIENTATION_VERTICAL) {
350                 view->pending_point.y = 0;
351         } else {
352                 view->pending_point.x = 0;
353         }
354
355         if (orientation == GTK_ORIENTATION_VERTICAL) {
356                 if (view->continuous) {
357                         gtk_adjustment_clamp_page (view->vadjustment,
358                                                    view_point.y - view->spacing / 2,
359                                                    view_point.y + view->vadjustment->page_size);
360                 } else {
361                         gtk_adjustment_set_value (view->vadjustment,
362                                                   CLAMP (view_point.y,
363                                                   view->vadjustment->lower,
364                                                   view->vadjustment->upper -
365                                                   view->vadjustment->page_size));
366                 }
367         } else {
368                 if (view->dual_page) {
369                         gtk_adjustment_clamp_page (view->hadjustment,
370                                                    view_point.x,
371                                                    view_point.x + view->hadjustment->page_size);
372                 } else {
373                         gtk_adjustment_set_value (view->hadjustment,
374                                                   CLAMP (view_point.x,
375                                                   view->hadjustment->lower,
376                                                   view->hadjustment->upper -
377                                                   view->hadjustment->page_size));
378                 }
379         }
380 }
381
382 static void
383 view_set_adjustment_values (EvView         *view,
384                             GtkOrientation  orientation)
385 {
386         GtkWidget *widget = GTK_WIDGET (view);
387         GtkAdjustment *adjustment;
388         int requisition;
389         int allocation;
390
391         double factor;
392         gint new_value;
393
394         if (orientation == GTK_ORIENTATION_HORIZONTAL)  {
395                 requisition = widget->requisition.width;
396                 allocation = widget->allocation.width;
397                 adjustment = view->hadjustment;
398         } else {
399                 requisition = widget->requisition.height;
400                 allocation = widget->allocation.height;
401                 adjustment = view->vadjustment;
402         }
403
404         if (!adjustment)
405                 return;
406
407         factor = 1.0;
408         switch (view->pending_scroll) {
409                 case SCROLL_TO_KEEP_POSITION:
410                 case SCROLL_TO_FIND_LOCATION:
411                         factor = (adjustment->value) / adjustment->upper;
412                         break;
413                 case SCROLL_TO_PAGE_POSITION:
414                         break;
415                 case SCROLL_TO_CENTER:
416                         factor = (adjustment->value + adjustment->page_size * 0.5) / adjustment->upper;
417                         break;
418         }
419
420         adjustment->page_size = allocation;
421         adjustment->step_increment = allocation * 0.1;
422         adjustment->page_increment = allocation * 0.9;
423         adjustment->lower = 0;
424         adjustment->upper = MAX (allocation, requisition);
425
426         /*
427          * We add 0.5 to the values before to average out our rounding errors.
428          */
429         switch (view->pending_scroll) {
430                 case SCROLL_TO_KEEP_POSITION:
431                 case SCROLL_TO_FIND_LOCATION:
432                         new_value = CLAMP (adjustment->upper * factor + 0.5, 0, adjustment->upper - adjustment->page_size);
433                         gtk_adjustment_set_value (adjustment, (int)new_value);
434                         break;
435                 case SCROLL_TO_PAGE_POSITION:
436                         scroll_to_current_page (view, orientation);
437                         break;
438                 case SCROLL_TO_CENTER:
439                         new_value = CLAMP (adjustment->upper * factor - adjustment->page_size * 0.5 + 0.5,
440                                            0, adjustment->upper - adjustment->page_size);
441                         gtk_adjustment_set_value (adjustment, (int)new_value);
442                         break;
443         }
444
445         gtk_adjustment_changed (adjustment);
446 }
447
448 static void
449 view_update_range_and_current_page (EvView *view)
450 {
451         gint current_page;
452         gint best_current_page = -1;
453         
454         /* Presentation trumps all other modes */
455         if (view->presentation) {
456                 view->start_page = view->current_page;
457                 view->end_page = view->current_page;
458         } else if (view->continuous) {
459                 GdkRectangle current_area, unused, page_area;
460                 GtkBorder border;
461                 gboolean found = FALSE;
462                 gint area_max = -1, area;
463                 int i;
464
465                 if (!(view->vadjustment && view->hadjustment))
466                         return;
467
468                 current_area.x = view->hadjustment->value;
469                 current_area.width = view->hadjustment->upper;
470                 current_area.y = view->vadjustment->value;
471                 current_area.height = view->vadjustment->page_size;
472
473                 for (i = 0; i < ev_page_cache_get_n_pages (view->page_cache); i++) {
474
475                         get_page_extents (view, i, &page_area, &border);
476
477                         if (gdk_rectangle_intersect (&current_area, &page_area, &unused)) {
478                                 area = unused.width * unused.height;
479
480                                 if (!found) {
481                                         area_max = area;
482                                         view->start_page = i;
483                                         found = TRUE;
484                                         best_current_page = i;
485                                 }
486                                 if (area > area_max) {
487                                         best_current_page = (area == area_max) ? MIN (i, best_current_page) : i;
488                                         area_max = area;
489                                 }
490
491                                 view->end_page = i;
492                         } else if (found) {
493                                 break;
494                         }
495                 }
496
497         } else if (view->dual_page) {
498                 if (view->current_page % 2 == ev_page_cache_get_dual_even_left (view->page_cache)) {
499                         view->start_page = view->current_page;
500                         if (view->current_page + 1 < ev_page_cache_get_n_pages (view->page_cache))
501                                 view->end_page = view->start_page + 1;
502                         else 
503                                 view->end_page = view->start_page;
504                 } else {
505                         if (view->current_page < 1)
506                                 view->start_page = view->current_page;
507                         else
508                                 view->start_page = view->current_page - 1;
509                         view->end_page = view->current_page;
510                 }
511         } else {
512                 view->start_page = view->current_page;
513                 view->end_page = view->current_page;
514         }
515
516         best_current_page = MAX (best_current_page, view->start_page);
517         current_page = ev_page_cache_get_current_page (view->page_cache);
518
519         if ((current_page != best_current_page) && (view->pending_scroll == SCROLL_TO_KEEP_POSITION)) {
520                 view->current_page = best_current_page;
521                 ev_page_cache_set_current_page (view->page_cache, best_current_page);
522         }
523
524         ev_pixbuf_cache_set_page_range (view->pixbuf_cache,
525                                         view->start_page,
526                                         view->end_page,
527                                         view->rotation,
528                                         view->scale,
529                                         view->selection_info.selections);
530 }
531
532 static void
533 set_scroll_adjustment (EvView *view,
534                        GtkOrientation  orientation,
535                        GtkAdjustment  *adjustment)
536 {
537         GtkAdjustment **to_set;
538
539         if (orientation == GTK_ORIENTATION_HORIZONTAL)
540                 to_set = &view->hadjustment;
541         else
542                 to_set = &view->vadjustment;
543
544         if (*to_set != adjustment) {
545                 if (*to_set) {
546                         g_signal_handlers_disconnect_by_func (*to_set,
547                                                               (gpointer) on_adjustment_value_changed,
548                                                               view);
549                         g_object_unref (*to_set);
550                 }
551
552                 *to_set = adjustment;
553                 view_set_adjustment_values (view, orientation);
554
555                 if (*to_set) {
556                         g_object_ref (*to_set);
557                         g_signal_connect (*to_set, "value_changed",
558                                           G_CALLBACK (on_adjustment_value_changed), view);
559                 }
560         }
561 }
562
563 static void
564 ev_view_set_scroll_adjustments (GtkLayout      *layout,
565                                 GtkAdjustment  *hadjustment,
566                                 GtkAdjustment  *vadjustment)
567 {
568         EvView *view = EV_VIEW (layout);
569         
570         set_scroll_adjustment (view, GTK_ORIENTATION_HORIZONTAL, hadjustment);
571         set_scroll_adjustment (view, GTK_ORIENTATION_VERTICAL, vadjustment);
572         
573         on_adjustment_value_changed (NULL, view);
574 }
575
576 static void
577 add_scroll_binding_keypad (GtkBindingSet  *binding_set,
578                            guint           keyval,
579                            GdkModifierType modifiers,
580                            EvScrollType    scroll,
581                            gboolean        horizontal)
582 {
583   guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
584
585   gtk_binding_entry_add_signal (binding_set, keyval, modifiers,
586                                 "binding_activated", 2,
587                                 EV_TYPE_SCROLL_TYPE, scroll,
588                                 G_TYPE_BOOLEAN, horizontal);
589   gtk_binding_entry_add_signal (binding_set, keypad_keyval, modifiers,
590                                 "binding_activated", 2,
591                                 EV_TYPE_SCROLL_TYPE, scroll,
592                                 G_TYPE_BOOLEAN, horizontal);
593 }
594
595 void
596 ev_view_scroll (EvView        *view,
597                 EvScrollType   scroll,
598                 gboolean horizontal)
599 {
600         GtkAdjustment *adjustment;
601         double value, increment;
602         gboolean first_page = FALSE;
603         gboolean last_page = FALSE;
604
605         view->jump_to_find_result = FALSE;
606
607         if (view->presentation || view->sizing_mode == EV_SIZING_BEST_FIT) {
608                 switch (scroll) {
609                         case EV_SCROLL_PAGE_BACKWARD:
610                         case EV_SCROLL_STEP_BACKWARD:
611                                 ev_view_previous_page (view);
612                                 break;
613                         case EV_SCROLL_PAGE_FORWARD:
614                         case EV_SCROLL_STEP_FORWARD:
615                                 ev_view_next_page (view);
616                                 break;
617                         default:
618                                 break;
619                 }
620                 return;
621         }
622
623         /* Assign values for increment and vertical adjustment */
624         adjustment = horizontal ? view->hadjustment : view->vadjustment;
625         increment = adjustment->page_size * 0.75;
626         value = adjustment->value;
627
628         /* Assign boolean for first and last page */
629         if (view->current_page == 0)
630                 first_page = TRUE;
631         if (view->current_page == ev_page_cache_get_n_pages (view->page_cache) - 1)
632                 last_page = TRUE;
633
634         switch (scroll) {
635                 case EV_SCROLL_PAGE_BACKWARD:
636                         /* Do not jump backwards if at the first page */
637                         if (value == (adjustment->lower) && first_page) {
638                                 /* Do nothing */
639                                 /* At the top of a page, assign the upper bound limit of previous page */
640                         } else if (value == (adjustment->lower)) {
641                                 value = adjustment->upper - adjustment->page_size;
642                                 ev_view_previous_page (view);
643                                 /* Jump to the top */
644                         } else {
645                                 value = MAX (value - increment, adjustment->lower);
646                         }
647                         break;
648                 case EV_SCROLL_PAGE_FORWARD:
649                         /* Do not jump forward if at the last page */
650                         if (value == (adjustment->upper - adjustment->page_size) && last_page) {
651                                 /* Do nothing */
652                         /* At the bottom of a page, assign the lower bound limit of next page */
653                         } else if (value == (adjustment->upper - adjustment->page_size)) {
654                                 value = 0;
655                                 ev_view_next_page (view);
656                         /* Jump to the bottom */
657                         } else {
658                                 value = MIN (value + increment, adjustment->upper - adjustment->page_size);
659                         }
660                         break;
661                 case EV_SCROLL_STEP_BACKWARD:
662                         value -= adjustment->step_increment;
663                         break;
664                 case EV_SCROLL_STEP_FORWARD:
665                         value += adjustment->step_increment;
666                         break;
667                 case EV_SCROLL_STEP_DOWN:
668                         value -= adjustment->step_increment / 10;
669                         break;
670                 case EV_SCROLL_STEP_UP:
671                         value += adjustment->step_increment / 10;
672                         break;
673                 default:
674                         break;
675         }
676
677         value = CLAMP (value, adjustment->lower,
678                        adjustment->upper - adjustment->page_size);      
679
680         gtk_adjustment_set_value (adjustment, value);
681 }
682
683 #define MARGIN 5
684
685 static void
686 ensure_rectangle_is_visible (EvView *view, GdkRectangle *rect)
687 {
688         GtkWidget *widget = GTK_WIDGET (view);
689         GtkAdjustment *adjustment;
690         int value;
691
692         view->pending_scroll = SCROLL_TO_FIND_LOCATION;
693
694         adjustment = view->vadjustment;
695
696         if (rect->y < adjustment->value) {
697                 value = MAX (adjustment->lower, rect->y - MARGIN);
698                 gtk_adjustment_set_value (view->vadjustment, value);
699         } else if (rect->y + rect->height >
700                    adjustment->value + widget->allocation.height) {
701                 value = MIN (adjustment->upper, rect->y + rect->height -
702                              widget->allocation.height + MARGIN);
703                 gtk_adjustment_set_value (view->vadjustment, value);
704         }
705
706         adjustment = view->hadjustment;
707
708         if (rect->x < adjustment->value) {
709                 value = MAX (adjustment->lower, rect->x - MARGIN);
710                 gtk_adjustment_set_value (view->hadjustment, value);
711         } else if (rect->x + rect->height >
712                    adjustment->value + widget->allocation.width) {
713                 value = MIN (adjustment->upper, rect->x + rect->width -
714                              widget->allocation.width + MARGIN);
715                 gtk_adjustment_set_value (view->hadjustment, value);
716         }
717
718         gtk_widget_queue_resize (GTK_WIDGET (view));
719 }
720
721 /*** Geometry computations ***/
722
723 static void
724 compute_border (EvView *view, int width, int height, GtkBorder *border)
725 {
726         if (view->presentation) {
727                 border->left = 0;
728                 border->right = 0;
729                 border->top = 0;
730                 border->bottom = 0;
731         } else {
732                 ev_document_misc_get_page_border_size (width, height, border);
733         }
734 }
735
736 static void
737 get_page_y_offset (EvView *view, int page, double zoom, int *y_offset)
738 {
739         int max_width, offset;
740         GtkBorder border;
741
742         g_return_if_fail (y_offset != NULL);
743
744         ev_page_cache_get_max_width (view->page_cache, view->rotation, zoom, &max_width);
745
746         compute_border (view, max_width, max_width, &border);
747
748         if (view->dual_page) {
749                 ev_page_cache_get_height_to_page (view->page_cache, page,
750                                                   view->rotation, zoom, NULL, &offset);
751                 offset += ((page + ev_page_cache_get_dual_even_left (view->page_cache)) / 2 + 1) * view->spacing + ((page + ev_page_cache_get_dual_even_left (view->page_cache)) / 2 ) * (border.top + border.bottom);
752         } else {
753                 ev_page_cache_get_height_to_page (view->page_cache, page,
754                                                   view->rotation, zoom, &offset, NULL);
755                 offset += (page + 1) * view->spacing + page * (border.top + border.bottom);
756         }
757
758         *y_offset = offset;
759         return;
760 }
761
762 static gboolean
763 get_page_extents (EvView       *view,
764                   gint          page,
765                   GdkRectangle *page_area,
766                   GtkBorder    *border)
767 {
768         GtkWidget *widget;
769         int width, height;
770
771         widget = GTK_WIDGET (view);
772
773         /* Get the size of the page */
774         ev_page_cache_get_size (view->page_cache, page,
775                                 view->rotation,
776                                 view->scale,
777                                 &width, &height);
778         compute_border (view, width, height, border);
779         page_area->width = width + border->left + border->right;
780         page_area->height = height + border->top + border->bottom;
781
782         if (view->presentation) {
783                 page_area->x = (MAX (0, widget->allocation.width - width))/2;
784                 page_area->y = (MAX (0, widget->allocation.height - height))/2;
785         } else if (view->continuous) {
786                 gint max_width;
787                 gint x, y;
788
789                 ev_page_cache_get_max_width (view->page_cache, view->rotation,
790                                              view->scale, &max_width);
791                 max_width = max_width + border->left + border->right;
792                 /* Get the location of the bounding box */
793                 if (view->dual_page) {
794                         x = view->spacing + ((page % 2 == ev_page_cache_get_dual_even_left (view->page_cache)) ? 0 : 1) * (max_width + view->spacing);
795                         x = x + MAX (0, widget->allocation.width - (max_width * 2 + view->spacing * 3)) / 2;
796                         if (page % 2 == ev_page_cache_get_dual_even_left (view->page_cache))
797                                 x = x + (max_width - width - border->left - border->right);
798                 } else {
799                         x = view->spacing;
800                         x = x + MAX (0, widget->allocation.width - (width + view->spacing * 2)) / 2;
801                 }
802
803                 get_page_y_offset (view, page, view->scale, &y);
804
805                 page_area->x = x;
806                 page_area->y = y;
807         } else {
808                 gint x, y;
809                 if (view->dual_page) {
810                         gint width_2, height_2;
811                         gint max_width = width;
812                         gint max_height = height;
813                         GtkBorder overall_border;
814                         gint other_page;
815
816                         other_page = (page % 2 == ev_page_cache_get_dual_even_left (view->page_cache)) ? page + 1: page - 1;
817
818                         /* First, we get the bounding box of the two pages */
819                         if (other_page < ev_page_cache_get_n_pages (view->page_cache)
820                             && (0 <= other_page)) {
821                                 ev_page_cache_get_size (view->page_cache,
822                                                         other_page,
823                                                         view->rotation,
824                                                         view->scale,
825                                                         &width_2, &height_2);
826                                 if (width_2 > width)
827                                         max_width = width_2;
828                                 if (height_2 > height)
829                                         max_height = height_2;
830                         }
831                         compute_border (view, max_width, max_height, &overall_border);
832
833                         /* Find the offsets */
834                         x = view->spacing;
835                         y = view->spacing;
836
837                         /* Adjust for being the left or right page */
838                         if (page % 2 == ev_page_cache_get_dual_even_left (view->page_cache))
839                                 x = x + max_width - width;
840                         else
841                                 x = x + (max_width + overall_border.left + overall_border.right) + view->spacing;
842
843                         y = y + (max_height - height)/2;
844
845                         /* Adjust for extra allocation */
846                         x = x + MAX (0, widget->allocation.width -
847                                      ((max_width + overall_border.left + overall_border.right) * 2 + view->spacing * 3))/2;
848                         y = y + MAX (0, widget->allocation.height - (height + view->spacing * 2))/2;
849                 } else {
850                         x = view->spacing;
851                         y = view->spacing;
852
853                         /* Adjust for extra allocation */
854                         x = x + MAX (0, widget->allocation.width - (width + border->left + border->right + view->spacing * 2))/2;
855                         y = y + MAX (0, widget->allocation.height - (height + border->top + border->bottom +  view->spacing * 2))/2;
856                 }
857
858                 page_area->x = x;
859                 page_area->y = y;
860         }
861
862         return TRUE;
863 }
864
865 static void
866 view_point_to_doc_point (EvView *view,
867                          GdkPoint *view_point,
868                          GdkRectangle *page_area,
869                          double  *doc_point_x,
870                          double  *doc_point_y)
871 {
872         *doc_point_x = (double) (view_point->x - page_area->x) / view->scale;
873         *doc_point_y = (double) (view_point->y - page_area->y) / view->scale;
874 }
875
876 static void
877 view_rect_to_doc_rect (EvView *view,
878                        GdkRectangle *view_rect,
879                        GdkRectangle *page_area,
880                        EvRectangle  *doc_rect)
881 {
882         doc_rect->x1 = (double) (view_rect->x - page_area->x) / view->scale;
883         doc_rect->y1 = (double) (view_rect->y - page_area->y) / view->scale;
884         doc_rect->x2 = doc_rect->x1 + (double) view_rect->width / view->scale;
885         doc_rect->y2 = doc_rect->y1 + (double) view_rect->height / view->scale;
886 }
887
888 static gboolean
889 doc_point_to_view_point (EvView       *view,
890                          int           page,
891                          EvPoint      *doc_point,
892                          GdkPoint     *view_point)
893 {
894         GdkRectangle page_area;
895         GtkBorder border;
896         double x, y, view_x, view_y;
897         int width, height;
898
899         ev_page_cache_get_size (view->page_cache, page,
900                                 view->rotation,
901                                 1.0,
902                                 &width, &height);
903
904         if (view->rotation == 0) {
905                 x = doc_point->x;
906                 y = doc_point->y;
907         } else if (view->rotation == 90) {
908                 x = width - doc_point->y;
909                 y = doc_point->x;
910         } else if (view->rotation == 180) {
911                 x = width - doc_point->x;
912                 y = height - doc_point->y;
913         } else if (view->rotation == 270) {
914                 x = doc_point->y;
915                 y = height - doc_point->x;
916         } else {
917                 g_assert_not_reached ();
918         }
919
920         get_page_extents (view, page, &page_area, &border);
921
922         view_x = x * view->scale;
923         view_y = y * view->scale;
924         view_point->x = view_x + page_area.x;
925         view_point->y = view_y + page_area.y;
926
927         return (view_x > 0 && view_x <= page_area.width &&
928                 view_y > 0 && view_y <= page_area.height);
929 }
930
931 static void
932 doc_rect_to_view_rect (EvView       *view,
933                        int           page,
934                        EvRectangle  *doc_rect,
935                        GdkRectangle *view_rect)
936 {
937         GdkRectangle page_area;
938         GtkBorder border;
939         double x, y, w, h;
940         int width, height;
941
942         ev_page_cache_get_size (view->page_cache, page,
943                                 view->rotation,
944                                 1.0,
945                                 &width, &height);
946
947         if (view->rotation == 0) {
948                 x = doc_rect->x1;
949                 y = doc_rect->y1;
950                 w = doc_rect->x2 - doc_rect->x1;
951                 h = doc_rect->y2 - doc_rect->y1;
952         } else if (view->rotation == 90) {
953                 x = width - doc_rect->y2;
954                 y = doc_rect->x1;
955                 w = doc_rect->y2 - doc_rect->y1;
956                 h = doc_rect->x2 - doc_rect->x1;
957         } else if (view->rotation == 180) {
958                 x = width - doc_rect->x2;
959                 y = height - doc_rect->y2;
960                 w = doc_rect->x2 - doc_rect->x1;
961                 h = doc_rect->y2 - doc_rect->y1;
962         } else if (view->rotation == 270) {
963                 x = doc_rect->y1;
964                 y = height - doc_rect->x2;
965                 w = doc_rect->y2 - doc_rect->y1;
966                 h = doc_rect->x2 - doc_rect->x1;
967         } else {
968                 g_assert_not_reached ();
969         }
970
971         get_page_extents (view, page, &page_area, &border);
972
973         view_rect->x = x * view->scale + page_area.x;
974         view_rect->y = y * view->scale + page_area.y;
975         view_rect->width = w * view->scale;
976         view_rect->height = h * view->scale;
977 }
978
979 static void
980 find_page_at_location (EvView  *view,
981                        gdouble  x,
982                        gdouble  y,
983                        gint    *page,
984                        gint    *x_offset,
985                        gint    *y_offset)
986 {
987         int i;
988
989         if (view->document == NULL)
990                 return;
991
992         g_assert (page);
993         g_assert (x_offset);
994         g_assert (y_offset);
995
996         for (i = view->start_page; i <= view->end_page; i++) {
997                 GdkRectangle page_area;
998                 GtkBorder border;
999
1000                 if (! get_page_extents (view, i, &page_area, &border))
1001                         continue;
1002
1003                 if ((x >= page_area.x + border.left) &&
1004                     (x < page_area.x + page_area.width - border.right) &&
1005                     (y >= page_area.y + border.top) &&
1006                     (y < page_area.y + page_area.height - border.bottom)) {
1007                         *page = i;
1008                         *x_offset = x - (page_area.x + border.left);
1009                         *y_offset = y - (page_area.y + border.top);
1010                         return;
1011                 }
1012         }
1013
1014         *page = -1;
1015 }
1016
1017 static gboolean
1018 location_in_text (EvView  *view,
1019                   gdouble  x,
1020                   gdouble  y)
1021 {
1022         GdkRegion *region;
1023         gint page = -1;
1024         gint x_offset = 0, y_offset = 0;
1025
1026         find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
1027
1028         if (page == -1)
1029                 return FALSE;
1030         
1031         region = ev_pixbuf_cache_get_text_mapping (view->pixbuf_cache, page);
1032
1033         if (region)
1034                 return gdk_region_point_in (region, x_offset / view->scale, y_offset / view->scale);
1035         else
1036                 return FALSE;
1037 }
1038
1039 static int
1040 ev_view_get_width (EvView *view)
1041 {
1042         return GTK_WIDGET (view)->allocation.width;
1043 }
1044
1045 static int
1046 ev_view_get_height (EvView *view)
1047 {
1048         return GTK_WIDGET (view)->allocation.height;
1049 }
1050
1051 static gboolean
1052 location_in_selected_text (EvView  *view,
1053                            gdouble  x,
1054                            gdouble  y)
1055 {
1056         gint page = -1;
1057         gint x_offset = 0, y_offset = 0;
1058         EvViewSelection *selection;
1059         GList *l = NULL;
1060
1061         for (l = view->selection_info.selections; l != NULL; l = l->next) {
1062                 selection = (EvViewSelection *)l->data;
1063                 
1064                 find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
1065                 
1066                 if (page != selection->page)
1067                         continue;
1068                 
1069                 if (selection->covered_region &&
1070                     gdk_region_point_in (selection->covered_region, x_offset, y_offset))
1071                         return TRUE;
1072         }
1073
1074         return FALSE;
1075 }
1076
1077 static gboolean
1078 get_doc_point_from_offset (EvView *view, 
1079                            gint    page, 
1080                            gint    x_offset, 
1081                            gint    y_offset, 
1082                            gint   *x_new, 
1083                            gint   *y_new)
1084 {
1085         int width, height;
1086         double x, y;
1087
1088         ev_page_cache_get_size (view->page_cache, page,
1089                                 view->rotation,
1090                                 1.0,
1091                                 &width, &height);
1092
1093         x_offset = x_offset / view->scale;
1094         y_offset = y_offset / view->scale;
1095
1096         if (view->rotation == 0) {
1097                 x = x_offset;
1098                 y = y_offset;
1099         } else if (view->rotation == 90) {
1100                 x = y_offset;
1101                 y = width - x_offset;
1102         } else if (view->rotation == 180) {
1103                 x = width - x_offset;
1104                 y = height - y_offset;
1105         } else if (view->rotation == 270) {
1106                 x = height - y_offset; 
1107                 y = x_offset;
1108         } else {
1109                 g_assert_not_reached ();
1110         }
1111
1112         *x_new = x;
1113         *y_new = y;
1114         
1115         return TRUE;
1116 }
1117
1118 /*** Hyperref ***/
1119 static EvLink *
1120 ev_view_get_link_at_location (EvView  *view,
1121                               gdouble  x,
1122                               gdouble  y)
1123 {
1124         gint page = -1;
1125         gint x_offset = 0, y_offset = 0;
1126         gint x_new = 0, y_new = 0;
1127         GList *link_mapping;
1128
1129         if (!EV_IS_DOCUMENT_LINKS (view->document))
1130                 return NULL;
1131         
1132         x += view->scroll_x;
1133         y += view->scroll_y;
1134
1135         find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
1136
1137         if (page == -1)
1138                 return NULL;
1139
1140         
1141         if (get_doc_point_from_offset (view, page, x_offset, 
1142                                        y_offset, &x_new, &y_new) == FALSE)
1143                 return NULL;
1144
1145         link_mapping = ev_pixbuf_cache_get_link_mapping (view->pixbuf_cache, page);
1146
1147         if (link_mapping)
1148                 return ev_link_mapping_find (link_mapping, x_new, y_new);
1149         else
1150                 return NULL;
1151 }
1152
1153 static void
1154 goto_fitr_dest (EvView *view, EvLinkDest *dest)
1155 {
1156         EvPoint doc_point;
1157         double zoom;
1158
1159         zoom = zoom_for_size_best_fit (ev_link_dest_get_right (dest) - ev_link_dest_get_left (dest),
1160                                        ev_link_dest_get_bottom (dest) - ev_link_dest_get_top (dest),
1161                                        ev_view_get_width (view),
1162                                        ev_view_get_height (view), 0, 0);
1163
1164         ev_view_set_sizing_mode (view, EV_SIZING_FREE);
1165         ev_view_set_zoom (view, zoom, FALSE);
1166
1167         doc_point.x = ev_link_dest_get_left (dest);
1168         doc_point.y = ev_link_dest_get_top (dest);
1169         
1170         view->current_page = ev_link_dest_get_page (dest);
1171         view->pending_point = doc_point;
1172         view->pending_scroll = SCROLL_TO_PAGE_POSITION;
1173
1174         gtk_widget_queue_resize (GTK_WIDGET (view));
1175 }
1176
1177 static void
1178 goto_fitv_dest (EvView *view, EvLinkDest *dest)
1179 {
1180         EvPoint doc_point;
1181         int doc_width, doc_height, page;
1182         double zoom;
1183
1184         page = ev_link_dest_get_page (dest);
1185         ev_page_cache_get_size (view->page_cache, page, 0, 1.0, &doc_width, &doc_height);
1186
1187         doc_point.x = ev_link_dest_get_left (dest);
1188         doc_point.y = 0;
1189
1190         zoom = zoom_for_size_fit_height (doc_width - doc_point.x , doc_height,
1191                                          ev_view_get_width (view),
1192                                          ev_view_get_height (view), 0);
1193
1194         ev_view_set_sizing_mode (view, EV_SIZING_FREE);
1195         ev_view_set_zoom (view, zoom, FALSE);
1196
1197         view->current_page = page;
1198         view->pending_point = doc_point;
1199         view->pending_scroll = SCROLL_TO_PAGE_POSITION;
1200
1201         gtk_widget_queue_resize (GTK_WIDGET (view));
1202 }
1203
1204 static void
1205 goto_fith_dest (EvView *view, EvLinkDest *dest)
1206 {
1207         EvPoint doc_point;
1208         int doc_width, doc_height, page;
1209         double zoom;
1210
1211         page = ev_link_dest_get_page (dest);
1212         ev_page_cache_get_size (view->page_cache, page, 0, 1.0, &doc_width, &doc_height);
1213
1214         doc_point.x = 0;
1215         doc_point.y = ev_link_dest_get_top (dest);
1216
1217         zoom = zoom_for_size_fit_width (doc_width, ev_link_dest_get_top (dest),
1218                                         ev_view_get_width (view),
1219                                         ev_view_get_height (view), 0);
1220
1221         ev_view_set_sizing_mode (view, EV_SIZING_FIT_WIDTH);
1222         ev_view_set_zoom (view, zoom, FALSE);
1223
1224         view->current_page = page;
1225         view->pending_point = doc_point;
1226         view->pending_scroll = SCROLL_TO_PAGE_POSITION;
1227
1228         gtk_widget_queue_resize (GTK_WIDGET (view));
1229 }
1230
1231 static void
1232 goto_fit_dest (EvView *view, EvLinkDest *dest)
1233 {
1234         double zoom;
1235         int doc_width, doc_height;
1236         int page;
1237
1238         page = ev_link_dest_get_page (dest);
1239         ev_page_cache_get_size (view->page_cache, page, 0, 1.0, &doc_width, &doc_height);
1240
1241         zoom = zoom_for_size_best_fit (doc_width, doc_height, ev_view_get_width (view),
1242                                        ev_view_get_height (view), 0, 0);
1243
1244         ev_view_set_sizing_mode (view, EV_SIZING_BEST_FIT);
1245         ev_view_set_zoom (view, zoom, FALSE);
1246
1247         view->current_page = page;
1248         view->pending_scroll = SCROLL_TO_PAGE_POSITION;
1249
1250         gtk_widget_queue_resize (GTK_WIDGET (view));
1251 }
1252
1253 static void
1254 goto_xyz_dest (EvView *view, EvLinkDest *dest)
1255 {
1256         EvPoint doc_point;
1257         gint page;
1258         double zoom;
1259
1260         zoom = ev_link_dest_get_zoom (dest);
1261         page = ev_link_dest_get_page (dest);
1262
1263         if (zoom > 1) {
1264                 ev_view_set_sizing_mode (view, EV_SIZING_FREE);
1265                 ev_view_set_zoom (view, zoom, FALSE);
1266         }
1267
1268         doc_point.x = ev_link_dest_get_left (dest);
1269         doc_point.y = ev_link_dest_get_top (dest);
1270
1271         view->current_page = page;
1272         view->pending_point = doc_point;
1273         view->pending_scroll = SCROLL_TO_PAGE_POSITION;
1274
1275         gtk_widget_queue_resize (GTK_WIDGET (view));
1276 }
1277
1278 static void
1279 goto_dest (EvView *view, EvLinkDest *dest)
1280 {
1281         EvLinkDestType type;
1282         int page, n_pages, current_page;
1283
1284         page = ev_link_dest_get_page (dest);
1285         n_pages = ev_page_cache_get_n_pages (view->page_cache);
1286
1287         if (page < 0 || page >= n_pages)
1288                 return;
1289
1290         current_page = view->current_page;
1291         
1292         type = ev_link_dest_get_dest_type (dest);
1293
1294         switch (type) {
1295                 case EV_LINK_DEST_TYPE_PAGE:
1296                         ev_page_cache_set_current_page (view->page_cache, page);
1297                         break;
1298                 case EV_LINK_DEST_TYPE_FIT:
1299                         goto_fit_dest (view, dest);
1300                         break;
1301                 case EV_LINK_DEST_TYPE_FITH:
1302                         goto_fith_dest (view, dest);
1303                         break;
1304                 case EV_LINK_DEST_TYPE_FITV:
1305                         goto_fitv_dest (view, dest);
1306                         break;
1307                 case EV_LINK_DEST_TYPE_FITR:
1308                         goto_fitr_dest (view, dest);
1309                         break;
1310                 case EV_LINK_DEST_TYPE_XYZ:
1311                         goto_xyz_dest (view, dest);
1312                         break;
1313                 case EV_LINK_DEST_TYPE_PAGE_LABEL:
1314                         ev_page_cache_set_page_label (view->page_cache, ev_link_dest_get_page_label (dest));
1315                         break;
1316                 default:
1317                         g_assert_not_reached ();
1318         }
1319
1320         if (current_page != view->current_page)
1321                 ev_page_cache_set_current_page (view->page_cache,
1322                                                 view->current_page);
1323 }
1324
1325 static void
1326 ev_view_goto_dest (EvView *view, EvLinkDest *dest)
1327 {
1328         EvLinkDestType type;
1329
1330         type = ev_link_dest_get_dest_type (dest);
1331
1332         if (type == EV_LINK_DEST_TYPE_NAMED) {
1333                 EvLinkDest  *dest2;     
1334                 const gchar *named_dest;
1335
1336                 named_dest = ev_link_dest_get_named_dest (dest);
1337                 dest2 = ev_document_links_find_link_dest (EV_DOCUMENT_LINKS (view->document),
1338                                                           named_dest);
1339                 if (dest2) {
1340                         goto_dest (view, dest2);
1341                         g_object_unref (dest2);
1342                 }
1343
1344                 return;
1345         }
1346
1347         goto_dest (view, dest);
1348 }
1349         
1350 void
1351 ev_view_handle_link (EvView *view, EvLink *link)
1352 {
1353         EvLinkAction    *action = NULL;
1354         EvLinkActionType type;
1355
1356         action = ev_link_get_action (link);
1357         if (!action)
1358                 return;
1359
1360         type = ev_link_action_get_action_type (action);
1361
1362         switch (type) {
1363                 case EV_LINK_ACTION_TYPE_GOTO_DEST: {
1364                         EvLinkDest *dest;
1365                         
1366                         g_signal_emit (view, signals[SIGNAL_HANDLE_LINK], 0, link);
1367                 
1368                         dest = ev_link_action_get_dest (action);
1369                         ev_view_goto_dest (view, dest);
1370                 }
1371                         break;
1372                 case EV_LINK_ACTION_TYPE_GOTO_REMOTE:
1373                 case EV_LINK_ACTION_TYPE_EXTERNAL_URI:
1374                 case EV_LINK_ACTION_TYPE_LAUNCH:
1375                 case EV_LINK_ACTION_TYPE_NAMED:
1376                         g_signal_emit (view, signals[SIGNAL_EXTERNAL_LINK], 0, action);
1377                         break;
1378         }
1379 }
1380
1381 gchar *
1382 ev_view_page_label_from_dest (EvView *view, EvLinkDest *dest)
1383 {
1384         EvLinkDestType type;
1385         gchar *msg = NULL;
1386
1387         type = ev_link_dest_get_dest_type (dest);
1388
1389         switch (type) {
1390                 case EV_LINK_DEST_TYPE_NAMED: {
1391                         EvLinkDest  *dest2;
1392                         const gchar *named_dest;
1393                         
1394                         named_dest = ev_link_dest_get_named_dest (dest);
1395                         dest2 = ev_document_links_find_link_dest (EV_DOCUMENT_LINKS (view->document),
1396                                                                   named_dest);
1397                         if (dest2) {
1398                                 msg = ev_page_cache_get_page_label (view->page_cache,
1399                                                                     ev_link_dest_get_page (dest2));
1400                                 g_object_unref (dest2);
1401                         }
1402                 }
1403                         
1404                         break;
1405                 case EV_LINK_DEST_TYPE_PAGE_LABEL: {
1406                         msg = g_strdup (ev_link_dest_get_page_label (dest));
1407                 }
1408                         break;
1409                 default: 
1410                         msg = ev_page_cache_get_page_label (view->page_cache,
1411                                                             ev_link_dest_get_page (dest));
1412         }
1413         
1414         return msg;
1415 }
1416
1417 static char *
1418 tip_from_action_named (EvLinkAction *action)
1419 {
1420         const gchar *name = ev_link_action_get_name (action);
1421         
1422         if (g_ascii_strcasecmp (name, "FirstPage") == 0) {
1423                 return g_strdup (_("Go to first page"));
1424         } else if (g_ascii_strcasecmp (name, "PrevPage") == 0) {
1425                 return g_strdup (_("Go to previous page"));
1426         } else if (g_ascii_strcasecmp (name, "NextPage") == 0) {
1427                 return g_strdup (_("Go to next page"));
1428         } else if (g_ascii_strcasecmp (name, "LastPage") == 0) {
1429                 return g_strdup (_("Go to last page"));
1430         } else if (g_ascii_strcasecmp (name, "GoToPage") == 0) {
1431                 return g_strdup (_("Go to page"));
1432         } else if (g_ascii_strcasecmp (name, "Find") == 0) {
1433                 return g_strdup (_("Find"));
1434         }
1435         
1436         return NULL;
1437 }
1438
1439 static char *
1440 tip_from_link (EvView *view, EvLink *link)
1441 {
1442         EvLinkAction *action;
1443         EvLinkActionType type;
1444         char *msg = NULL;
1445         char *page_label;
1446         const char *title;
1447
1448         action = ev_link_get_action (link);
1449         title = ev_link_get_title (link);
1450         
1451         if (!action)
1452                 return title ? g_strdup (title) : NULL;
1453                 
1454         type = ev_link_action_get_action_type (action);
1455
1456         switch (type) {
1457                 case EV_LINK_ACTION_TYPE_GOTO_DEST:
1458                         page_label = ev_view_page_label_from_dest (view,
1459                                                                    ev_link_action_get_dest (action));
1460                         msg = g_strdup_printf (_("Go to page %s"), page_label);
1461                         g_free (page_label);
1462                         break;
1463                 case EV_LINK_ACTION_TYPE_GOTO_REMOTE:
1464                         if (title) {
1465                                 msg = g_strdup_printf (_("Go to %s on file “%s”"), title,
1466                                                        ev_link_action_get_filename (action));
1467                         } else {
1468                                 msg = g_strdup_printf (_("Go to file “%s”"),
1469                                                        ev_link_action_get_filename (action));
1470                         }
1471                         
1472                         break;
1473                 case EV_LINK_ACTION_TYPE_EXTERNAL_URI:
1474                         msg = g_strdup (ev_link_action_get_uri (action));
1475                         break;
1476                 case EV_LINK_ACTION_TYPE_LAUNCH:
1477                         msg = g_strdup_printf (_("Launch %s"),
1478                                                ev_link_action_get_filename (action));
1479                         break;
1480                 case EV_LINK_ACTION_TYPE_NAMED:
1481                         msg = tip_from_action_named (action);
1482                         break;
1483                 default:
1484                         if (title)
1485                                 msg = g_strdup (title);
1486                         break;
1487         }
1488         
1489         return msg;
1490 }
1491
1492 static void
1493 ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y)
1494 {
1495         EvLink *link;
1496
1497         link = ev_view_get_link_at_location (view, x, y);
1498
1499         if (view->link_tooltip == NULL) {
1500                 view->link_tooltip = ev_tooltip_new (GTK_WIDGET (view));
1501         }
1502
1503         if (view->hovered_link != link) {
1504                 view->hovered_link = link;
1505                 ev_tooltip_deactivate (EV_TOOLTIP (view->link_tooltip));
1506         }
1507
1508         if (link) {
1509                 char *msg = tip_from_link (view, link);
1510
1511                 if (msg && g_utf8_validate (msg, -1, NULL)) {
1512                         EvTooltip *tooltip = EV_TOOLTIP (view->link_tooltip);
1513
1514                         ev_tooltip_set_position (tooltip, x, y);
1515                         ev_tooltip_set_text (tooltip, msg);
1516                         ev_tooltip_activate (tooltip);
1517                 }
1518                 g_free (msg);
1519
1520                 ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK);
1521         } else if (location_in_text (view, x + view->scroll_x, y + view->scroll_y)) {
1522                 ev_view_set_cursor (view, EV_VIEW_CURSOR_IBEAM);
1523         } else if (ev_view_get_form_field_at_location (view, x, y)) {
1524                 ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK);
1525         } else {
1526                 ev_view_set_status (view, NULL);
1527                 if (view->cursor == EV_VIEW_CURSOR_LINK ||
1528                     view->cursor == EV_VIEW_CURSOR_IBEAM)
1529                         ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
1530         }
1531 }
1532
1533 /*** Images ***/
1534 static EvImage *
1535 ev_view_get_image_at_location (EvView  *view,
1536                                gdouble  x,
1537                                gdouble  y)
1538 {
1539         gint page = -1;
1540         gint x_offset = 0, y_offset = 0;
1541         gint x_new = 0, y_new = 0;
1542         GList *image_mapping;
1543
1544         if (!EV_IS_DOCUMENT_IMAGES (view->document))
1545                 return NULL;
1546
1547         x += view->scroll_x;
1548         y += view->scroll_y;
1549
1550         find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
1551
1552         if (page == -1)
1553                 return NULL;
1554
1555         if (get_doc_point_from_offset (view, page, x_offset,
1556                                        y_offset, &x_new, &y_new) == FALSE)
1557                 return NULL;
1558
1559         image_mapping = ev_pixbuf_cache_get_image_mapping (view->pixbuf_cache, page);
1560
1561         if (image_mapping)
1562                 return ev_image_mapping_find (image_mapping, x_new, y_new);
1563         else
1564                 return NULL;
1565 }
1566
1567 /*** Forms ***/
1568 static EvFormField *
1569 ev_view_get_form_field_at_location (EvView  *view,
1570                                     gdouble  x,
1571                                     gdouble  y)
1572 {
1573         gint page = -1;
1574         gint x_offset = 0, y_offset = 0;
1575         gint x_new = 0, y_new = 0;
1576         GList *forms_mapping;
1577         
1578         if (!EV_IS_DOCUMENT_FORMS (view->document))
1579                 return NULL;
1580
1581         x += view->scroll_x;
1582         y += view->scroll_y;
1583         
1584         find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
1585         
1586         if (page == -1)
1587                 return NULL;
1588
1589         if (get_doc_point_from_offset (view, page, x_offset,
1590                                        y_offset, &x_new, &y_new) == FALSE)
1591                 return NULL;
1592
1593         forms_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, page);
1594
1595         if (forms_mapping)
1596                 return ev_form_field_mapping_find (forms_mapping, x_new, y_new);
1597         else
1598                 return NULL;
1599 }
1600
1601 static gboolean
1602 ev_view_forms_remove_widgets (EvView *view)
1603 {
1604         ev_view_remove_all (view);
1605
1606         return FALSE;
1607 }
1608
1609 static void
1610 ev_view_form_field_destroy (GtkWidget *widget,
1611                             EvView    *view)
1612 {
1613         g_idle_add ((GSourceFunc)ev_view_forms_remove_widgets, view);
1614 }
1615
1616 static GtkWidget *
1617 ev_view_form_field_button_create_widget (EvView      *view,
1618                                          EvFormField *field)
1619 {
1620         EvFormFieldButton *field_button = EV_FORM_FIELD_BUTTON (field);
1621         
1622         switch (field_button->type) {
1623                 case EV_FORM_FIELD_BUTTON_PUSH:
1624                         break;
1625                 case EV_FORM_FIELD_BUTTON_CHECK:
1626                 case EV_FORM_FIELD_BUTTON_RADIO: {
1627                         gboolean state;
1628
1629                         state = ev_document_forms_form_field_button_get_state (EV_DOCUMENT_FORMS (view->document),
1630                                                                                field);
1631                         ev_document_forms_form_field_button_set_state (EV_DOCUMENT_FORMS (view->document),
1632                                                                        field, !state);
1633                         ev_pixbuf_cache_reload_page (view->pixbuf_cache,
1634                                                      field->page,
1635                                                      view->rotation,
1636                                                      view->scale);
1637                 }
1638                         break;
1639         }
1640         
1641         return NULL;
1642 }
1643
1644 static void
1645 ev_view_form_field_text_save (EvView    *view,
1646                               GtkWidget *widget)
1647 {
1648         EvFormField *field;
1649
1650         field = g_object_get_data (G_OBJECT (widget), "form-field");
1651         
1652         if (field->changed) {
1653                 EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field);
1654                 
1655                 ev_document_forms_form_field_text_set_text (EV_DOCUMENT_FORMS (view->document),
1656                                                             field, field_text->text);
1657                 field->changed = FALSE;
1658                 ev_pixbuf_cache_reload_page (view->pixbuf_cache,
1659                                              field->page,
1660                                              view->rotation,
1661                                              view->scale);
1662         }
1663 }
1664
1665 static void
1666 ev_view_form_field_text_changed (GtkWidget   *widget,
1667                                  EvFormField *field)
1668 {
1669         EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field);
1670         gchar           *text = NULL;
1671
1672         if (GTK_IS_ENTRY (widget)) {
1673                 text = g_strdup (gtk_entry_get_text (GTK_ENTRY (widget)));
1674         } else if (GTK_IS_TEXT_BUFFER (widget)) {
1675                 GtkTextIter start, end;
1676
1677                 gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (widget), &start, &end);
1678                 text = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (widget),
1679                                                  &start, &end, FALSE);
1680         }
1681
1682         if (!field_text->text ||
1683             (field_text->text && g_ascii_strcasecmp (field_text->text, text) != 0)) {
1684                 g_free (field_text->text);
1685                 field_text->text = text;
1686                 field->changed = TRUE;
1687         }
1688 }
1689
1690 static GtkWidget *
1691 ev_view_form_field_text_create_widget (EvView      *view,
1692                                        EvFormField *field)
1693 {
1694         EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field);
1695         GtkWidget       *text = NULL;
1696         gchar           *txt;
1697
1698         txt = ev_document_forms_form_field_text_get_text (EV_DOCUMENT_FORMS (view->document),
1699                                                           field);
1700
1701         switch (field_text->type) {
1702                 case EV_FORM_FIELD_TEXT_FILE_SELECT:
1703                         /* TODO */
1704                 case EV_FORM_FIELD_TEXT_NORMAL:
1705                 case EV_FORM_FIELD_TEXT_PASSWORD:
1706                         text = gtk_entry_new ();
1707                         gtk_entry_set_has_frame (GTK_ENTRY (text), FALSE);
1708                         gtk_entry_set_max_length (GTK_ENTRY (text), field_text->max_len);
1709                         gtk_entry_set_visibility (GTK_ENTRY (text),
1710                                                   !(field_text->type == EV_FORM_FIELD_TEXT_PASSWORD));
1711                         
1712                         if (txt) {
1713                                 gtk_entry_set_text (GTK_ENTRY (text), txt);
1714                                 g_free (txt);
1715                         }
1716
1717                         g_signal_connect (G_OBJECT (text), "changed",
1718                                           G_CALLBACK (ev_view_form_field_text_changed),
1719                                           field);
1720                         g_signal_connect_after (G_OBJECT (text), "activate",
1721                                                 G_CALLBACK (ev_view_form_field_destroy),
1722                                                 view);
1723                         break;
1724                 case EV_FORM_FIELD_TEXT_MULTILINE: {
1725                         GtkTextBuffer *buffer;
1726                 
1727                         text = gtk_text_view_new ();
1728                         buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text));
1729                 
1730                         if (txt) {
1731                                 gtk_text_buffer_set_text (buffer, txt, -1);
1732                                 g_free (txt);
1733                         }
1734                         
1735                         g_signal_connect (G_OBJECT (buffer), "changed",
1736                                           G_CALLBACK (ev_view_form_field_text_changed),
1737                                           field);
1738                 }
1739                         break;
1740         }                       
1741
1742         g_object_weak_ref (G_OBJECT (text),
1743                            (GWeakNotify)ev_view_form_field_text_save,
1744                            view);
1745
1746         return text;
1747 }
1748
1749 static void
1750 ev_view_form_field_choice_save (EvView    *view,
1751                                 GtkWidget *widget)
1752 {
1753         EvFormField *field;
1754
1755         field = g_object_get_data (G_OBJECT (widget), "form-field");
1756
1757         if (field->changed) {
1758                 GList             *l;
1759                 EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field);
1760
1761                 if (field_choice->is_editable) {
1762                         ev_document_forms_form_field_choice_set_text (EV_DOCUMENT_FORMS (view->document),
1763                                                                       field, field_choice->text);
1764                 }
1765                 
1766                 ev_document_forms_form_field_choice_unselect_all (EV_DOCUMENT_FORMS (view->document), field);
1767                 for (l = field_choice->selected_items; l && l->data; l = g_list_next (l)) {
1768                         ev_document_forms_form_field_choice_select_item (EV_DOCUMENT_FORMS (view->document),
1769                                                                          field,
1770                                                                          GPOINTER_TO_INT (l->data));
1771                 }
1772                 field->changed = FALSE;
1773                 ev_pixbuf_cache_reload_page (view->pixbuf_cache,
1774                                              field->page,
1775                                              view->rotation,
1776                                              view->scale);
1777         }
1778 }
1779
1780 static void
1781 ev_view_form_field_choice_changed (GtkWidget   *widget,
1782                                    EvFormField *field)
1783 {
1784         EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field);
1785         
1786         if (GTK_IS_COMBO_BOX (widget)) {
1787                 gint item;
1788                 
1789                 item = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
1790                 if (GPOINTER_TO_INT (field_choice->selected_items->data) != item) {
1791                         g_list_free (field_choice->selected_items);
1792                         field_choice->selected_items = NULL;
1793                         field_choice->selected_items = g_list_prepend (field_choice->selected_items,
1794                                                                        GINT_TO_POINTER (item));
1795                         field->changed = TRUE;
1796                 }
1797
1798                 if (GTK_IS_COMBO_BOX_ENTRY (widget)) {
1799                         gchar *text;
1800                         
1801                         text = gtk_combo_box_get_active_text (GTK_COMBO_BOX (widget));
1802                         if (!field_choice->text ||
1803                             (field_choice->text && g_ascii_strcasecmp (field_choice->text, text) != 0)) {
1804                                 g_free (field_choice->text);
1805                                 field_choice->text = text;
1806                                 field->changed = TRUE;
1807                         }
1808                 }
1809         } else if (GTK_IS_TREE_SELECTION (widget)) {
1810                 GtkTreeSelection *selection = GTK_TREE_SELECTION (widget);
1811                 GtkTreeModel     *model;
1812                 GList            *items, *l;
1813                 
1814                 items = gtk_tree_selection_get_selected_rows (selection, &model);
1815                 g_list_free (field_choice->selected_items);
1816                 field_choice->selected_items = NULL;
1817
1818                 for (l = items; l && l->data; l = g_list_next (l)) {
1819                         GtkTreeIter  iter;
1820                         GtkTreePath *path = (GtkTreePath *)l->data;
1821                         gint         item;
1822                         
1823                         gtk_tree_model_get_iter (model, &iter, path);
1824                         gtk_tree_model_get (model, &iter, 1, &item, -1);
1825
1826                         field_choice->selected_items = g_list_prepend (field_choice->selected_items,
1827                                                                        GINT_TO_POINTER (item));
1828
1829                         gtk_tree_path_free (path);
1830                 }
1831
1832                 g_list_free (items);
1833
1834                 field->changed = TRUE;
1835         }
1836 }
1837
1838 static GtkWidget *
1839 ev_view_form_field_choice_create_widget (EvView      *view,
1840                                          EvFormField *field)
1841 {
1842         EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field);
1843         GtkWidget         *choice;
1844         GtkTreeModel      *model;
1845         gint               n_items, i;
1846         gint               selected_item = 0;
1847
1848         n_items = ev_document_forms_form_field_choice_get_n_items (EV_DOCUMENT_FORMS (view->document),
1849                                                                    field);
1850         model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT));
1851         for (i = 0; i < n_items; i++) {
1852                 GtkTreeIter iter;
1853                 gchar      *item;
1854
1855                 item = ev_document_forms_form_field_choice_get_item (EV_DOCUMENT_FORMS (view->document),
1856                                                                      field, i);
1857                 if (ev_document_forms_form_field_choice_is_item_selected (
1858                             EV_DOCUMENT_FORMS (view->document), field, i)) {
1859                         selected_item = i;
1860                         /* FIXME: we need a get_selected_items function in poppler */
1861                         field_choice->selected_items = g_list_prepend (field_choice->selected_items,
1862                                                                        GINT_TO_POINTER (i));
1863                 }
1864                 
1865                 if (item) {
1866                         gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1867                         gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1868                                             0, item,
1869                                             1, i,
1870                                             -1);
1871                         g_free (item);
1872                 }
1873         }
1874
1875         if (field_choice->type == EV_FORM_FIELD_CHOICE_LIST) {
1876                 GtkCellRenderer  *renderer;
1877                 GtkWidget        *tree_view;
1878                 GtkTreeSelection *selection;
1879
1880                 tree_view = gtk_tree_view_new_with_model (model);
1881                 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
1882
1883                 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
1884                 if (field_choice->multi_select) {
1885                         gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
1886                 }
1887
1888                 /* TODO: set selected items */
1889
1890                 renderer = gtk_cell_renderer_text_new ();
1891                 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
1892                                                              0,
1893                                                              "choix", renderer,
1894                                                              "text", 0,
1895                                                              NULL);
1896
1897                 choice = gtk_scrolled_window_new (NULL, NULL);
1898                 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (choice),
1899                                                 GTK_POLICY_AUTOMATIC,
1900                                                 GTK_POLICY_AUTOMATIC);
1901                 gtk_container_add (GTK_CONTAINER (choice), tree_view);
1902                 gtk_widget_show (tree_view);
1903
1904                 g_signal_connect (G_OBJECT (selection), "changed",
1905                                   G_CALLBACK (ev_view_form_field_choice_changed),
1906                                   field);
1907                 g_signal_connect_after (G_OBJECT (selection), "changed",
1908                                         G_CALLBACK (ev_view_form_field_destroy),
1909                                         view);
1910         } else if (field_choice->is_editable) { /* ComboBoxEntry */
1911                 gchar *text;
1912                 
1913                 choice = gtk_combo_box_entry_new_with_model (model, 0);
1914                 text = ev_document_forms_form_field_choice_get_text (EV_DOCUMENT_FORMS (view->document), field);
1915                 if (text) {
1916                         gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (choice))), text);
1917                         g_free (text);
1918                 }
1919
1920                 g_signal_connect (G_OBJECT (choice), "changed",
1921                                   G_CALLBACK (ev_view_form_field_choice_changed),
1922                                   field);
1923                 g_signal_connect_after (G_OBJECT (GTK_BIN (choice)->child), "activate",
1924                                         G_CALLBACK (ev_view_form_field_destroy),
1925                                         view);
1926         } else { /* ComboBoxText */
1927                 GtkCellRenderer *renderer;
1928
1929                 choice = gtk_combo_box_new_with_model (model);
1930                 renderer = gtk_cell_renderer_text_new ();
1931                 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (choice),
1932                                             renderer, TRUE);
1933                 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (choice),
1934                                                 renderer,
1935                                                 "text", 0,
1936                                                 NULL);
1937                 gtk_combo_box_set_active (GTK_COMBO_BOX (choice), selected_item);
1938                 gtk_combo_box_popup (GTK_COMBO_BOX (choice));
1939                 
1940                 g_signal_connect (G_OBJECT (choice), "changed",
1941                                   G_CALLBACK (ev_view_form_field_choice_changed),
1942                                   field);
1943                 g_signal_connect_after (G_OBJECT (choice), "changed",
1944                                         G_CALLBACK (ev_view_form_field_destroy),
1945                                         view);
1946         }
1947
1948         g_object_unref (model);
1949
1950         g_object_weak_ref (G_OBJECT (choice),
1951                            (GWeakNotify)ev_view_form_field_choice_save,
1952                            view);
1953
1954         return choice;
1955 }
1956
1957 static void
1958 ev_view_handle_form_field (EvView      *view,
1959                            EvFormField *field,
1960                            gdouble      x,
1961                            gdouble      y)
1962 {
1963         GtkWidget   *field_widget = NULL;
1964         GList       *form_field_mapping;
1965         EvRectangle  field_area;
1966         GdkRectangle view_area;
1967
1968         if (field->is_read_only)
1969                 return;
1970         
1971         if (EV_IS_FORM_FIELD_BUTTON (field)) {
1972                 field_widget = ev_view_form_field_button_create_widget (view, field);
1973         } else if (EV_IS_FORM_FIELD_TEXT (field)) {
1974                 field_widget = ev_view_form_field_text_create_widget (view, field);
1975         } else if (EV_IS_FORM_FIELD_CHOICE (field)) {
1976                 field_widget = ev_view_form_field_choice_create_widget (view, field);
1977         } else if (EV_IS_FORM_FIELD_SIGNATURE (field)) {
1978                 /* TODO */
1979         }
1980
1981         /* Form field doesn't require a widget */
1982         if (!field_widget)
1983                 return;
1984
1985         g_object_set_data_full (G_OBJECT (field_widget), "form-field",
1986                                 g_object_ref (field),
1987                                 (GDestroyNotify)g_object_unref);
1988
1989         form_field_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, field->page);
1990         ev_form_field_mapping_get_area (form_field_mapping, field, &field_area);
1991         
1992         doc_rect_to_view_rect (view, field->page, &field_area, &view_area);
1993         view_area.x -= view->scroll_x;
1994         view_area.y -= view->scroll_y;
1995
1996         gtk_layout_put (GTK_LAYOUT (view), field_widget, view_area.x, view_area.y);
1997         gtk_widget_show (field_widget);
1998         gtk_widget_grab_focus (field_widget);
1999 }
2000
2001 /*** GtkWidget implementation ***/
2002
2003 static void
2004 ev_view_size_request_continuous_dual_page (EvView         *view,
2005                                            GtkRequisition *requisition)
2006 {
2007         int max_width;
2008         gint n_pages;
2009         GtkBorder border;
2010
2011         ev_page_cache_get_max_width (view->page_cache, view->rotation,
2012                                      view->scale, &max_width);
2013         compute_border (view, max_width, max_width, &border);
2014
2015         n_pages = ev_page_cache_get_n_pages (view->page_cache) + 1;
2016
2017         requisition->width = (max_width + border.left + border.right) * 2 + (view->spacing * 3);
2018         get_page_y_offset (view, n_pages, view->scale, &requisition->height);
2019
2020         if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
2021                 requisition->width = 1;
2022         } else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
2023                 requisition->width = 1;
2024                 /* FIXME: This could actually be set on one page docs or docs
2025                  * with a strange aspect ratio. */
2026                 /* requisition->height = 1;*/
2027         }
2028 }
2029
2030 static void
2031 ev_view_size_request_continuous (EvView         *view,
2032                                  GtkRequisition *requisition)
2033 {
2034         int max_width;
2035         int n_pages;
2036         GtkBorder border;
2037
2038
2039         ev_page_cache_get_max_width (view->page_cache, view->rotation,
2040                                      view->scale, &max_width);
2041         n_pages = ev_page_cache_get_n_pages (view->page_cache);
2042         compute_border (view, max_width, max_width, &border);
2043
2044         requisition->width = max_width + (view->spacing * 2) + border.left + border.right;
2045         get_page_y_offset (view, n_pages, view->scale, &requisition->height);
2046
2047         if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
2048                 requisition->width = 1;
2049         } else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
2050                 requisition->width = 1;
2051                 /* FIXME: This could actually be set on one page docs or docs
2052                  * with a strange aspect ratio. */
2053                 /* requisition->height = 1;*/
2054         }
2055 }
2056
2057 static void
2058 ev_view_size_request_dual_page (EvView         *view,
2059                                 GtkRequisition *requisition)
2060 {
2061         GtkBorder border;
2062         gint width, height;
2063
2064         /* Find the largest of the two. */
2065         ev_page_cache_get_size (view->page_cache,
2066                                 view->current_page,
2067                                 view->rotation,
2068                                 view->scale,
2069                                 &width, &height);
2070         if (view->current_page + 1 < ev_page_cache_get_n_pages (view->page_cache)) {
2071                 gint width_2, height_2;
2072                 ev_page_cache_get_size (view->page_cache,
2073                                         view->current_page + 1,
2074                                         view->rotation,
2075                                         view->scale,
2076                                         &width_2, &height_2);
2077                 if (width_2 > width) {
2078                         width = width_2;
2079                         height = height_2;
2080                 }
2081         }
2082         compute_border (view, width, height, &border);
2083
2084         requisition->width = ((width + border.left + border.right) * 2) +
2085                 (view->spacing * 3);
2086         requisition->height = (height + border.top + border.bottom) +
2087                 (view->spacing * 2);
2088
2089         if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
2090                 requisition->width = 1;
2091         } else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
2092                 requisition->width = 1;
2093                 requisition->height = 1;
2094         }
2095 }
2096
2097 static void
2098 ev_view_size_request_single_page (EvView         *view,
2099                                   GtkRequisition *requisition)
2100 {
2101         GtkBorder border;
2102         gint width, height;
2103
2104         ev_page_cache_get_size (view->page_cache,
2105                                 view->current_page,
2106                                 view->rotation,
2107                                 view->scale,
2108                                 &width, &height);
2109         compute_border (view, width, height, &border);
2110
2111         requisition->width = width + border.left + border.right + (2 * view->spacing);
2112         requisition->height = height + border.top + border.bottom + (2 * view->spacing);
2113
2114         if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
2115                 requisition->width = 1;
2116                 requisition->height = height + border.top + border.bottom + (2 * view->spacing);
2117         } else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
2118                 requisition->width = 1;
2119                 requisition->height = 1;
2120         }
2121 }
2122
2123 static void
2124 ev_view_size_request (GtkWidget      *widget,
2125                       GtkRequisition *requisition)
2126 {
2127         EvView *view = EV_VIEW (widget);
2128         
2129         if (view->document == NULL) {
2130                 requisition->width = 1;
2131                 requisition->height = 1;
2132                 return;
2133         }
2134
2135         if (view->presentation) {
2136                 requisition->width = 1;
2137                 requisition->height = 1;
2138                 return;
2139         }
2140
2141         if (view->continuous && view->dual_page)
2142                 ev_view_size_request_continuous_dual_page (view, requisition);
2143         else if (view->continuous)
2144                 ev_view_size_request_continuous (view, requisition);
2145         else if (view->dual_page)
2146                 ev_view_size_request_dual_page (view, requisition);
2147         else
2148                 ev_view_size_request_single_page (view, requisition);
2149 }
2150
2151 static void
2152 ev_view_size_allocate (GtkWidget      *widget,
2153                        GtkAllocation  *allocation)
2154 {
2155         EvView *view = EV_VIEW (widget);
2156         GList  *children, *l;
2157
2158         GTK_WIDGET_CLASS (ev_view_parent_class)->size_allocate (widget, allocation);
2159         
2160         if (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
2161             view->sizing_mode == EV_SIZING_BEST_FIT) {
2162
2163                 g_signal_emit (view, signals[SIGNAL_ZOOM_INVALID], 0);
2164
2165                 ev_view_size_request (widget, &widget->requisition);
2166         }
2167         
2168         view_set_adjustment_values (view, GTK_ORIENTATION_HORIZONTAL);
2169         view_set_adjustment_values (view, GTK_ORIENTATION_VERTICAL);
2170
2171         if (view->document)
2172                 view_update_range_and_current_page (view);
2173
2174         view->pending_scroll = SCROLL_TO_KEEP_POSITION;
2175         view->pending_resize = FALSE;
2176
2177         children = gtk_container_get_children (GTK_CONTAINER (widget));
2178         for (l = children; l && l->data; l = g_list_next (l)) {
2179                 EvFormField   *field;
2180                 EvRectangle    field_area;
2181                 GdkRectangle   view_area;
2182                 GList         *form_field_mapping;
2183                 GtkAllocation  child_allocation;
2184                 GtkRequisition child_requisition;
2185                 GtkWidget     *child = (GtkWidget *)l->data;
2186                 
2187                 field = g_object_get_data (G_OBJECT (child), "form-field");
2188                 if (!field)
2189                         continue;
2190
2191                 form_field_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache,
2192                                                                              field->page);
2193                 ev_form_field_mapping_get_area (form_field_mapping, field, &field_area);
2194
2195                 doc_rect_to_view_rect (view, field->page, &field_area, &view_area);
2196                 view_area.x -= view->scroll_x;
2197                 view_area.y -= view->scroll_y;
2198
2199                 gtk_widget_size_request (child, &child_requisition);
2200                 if (child_requisition.width != view_area.width ||
2201                     child_requisition.height != view_area.height)
2202                         gtk_widget_set_size_request (child, view_area.width, view_area.height);
2203
2204                 gtk_container_child_get (GTK_CONTAINER (widget),
2205                                          child,
2206                                          "x", &child_allocation.x,
2207                                          "y", &child_allocation.y,
2208                                          NULL);
2209                 if (child_allocation.x != view_area.x ||
2210                     child_allocation.y != view_area.y) {
2211                         gtk_layout_move (GTK_LAYOUT (widget), child, view_area.x, view_area.y);
2212                 }
2213         }
2214         g_list_free (children);
2215 }
2216
2217 static void
2218 ev_view_realize (GtkWidget *widget)
2219 {
2220         EvView *view = EV_VIEW (widget);
2221
2222         if (GTK_WIDGET_CLASS (ev_view_parent_class)->realize)
2223                 (* GTK_WIDGET_CLASS (ev_view_parent_class)->realize) (widget);
2224
2225         gdk_window_set_events (view->layout.bin_window,
2226                                (gdk_window_get_events (view->layout.bin_window) | 
2227                                 GDK_EXPOSURE_MASK |
2228                                 GDK_BUTTON_PRESS_MASK |
2229                                 GDK_BUTTON_RELEASE_MASK |
2230                                 GDK_SCROLL_MASK |
2231                                 GDK_KEY_PRESS_MASK |
2232                                 GDK_POINTER_MOTION_MASK |
2233                                 GDK_POINTER_MOTION_HINT_MASK |
2234                                 GDK_ENTER_NOTIFY_MASK |
2235                                 GDK_LEAVE_NOTIFY_MASK));
2236
2237         if (view->presentation)
2238                 gdk_window_set_background (view->layout.bin_window, &widget->style->black);
2239         else
2240                 gdk_window_set_background (view->layout.bin_window, &widget->style->mid [GTK_STATE_NORMAL]);
2241 }
2242
2243 static gboolean
2244 ev_view_scroll_event (GtkWidget *widget, GdkEventScroll *event)
2245 {
2246         EvView *view = EV_VIEW (widget);
2247         guint state;
2248
2249         state = event->state & gtk_accelerator_get_default_mod_mask ();
2250
2251         if (state == GDK_CONTROL_MASK && view->presentation == FALSE) {
2252                 ev_view_set_sizing_mode (view, EV_SIZING_FREE);
2253
2254                 if (event->direction == GDK_SCROLL_UP ||
2255                     event->direction == GDK_SCROLL_LEFT) {
2256                         if (ev_view_can_zoom_in (view)) {
2257                                 ev_view_zoom_in (view);
2258                         }
2259                 } else {
2260                         if (ev_view_can_zoom_out (view)) {
2261                                 ev_view_zoom_out (view);
2262                         }
2263                 }
2264
2265                 return TRUE;
2266         }
2267
2268         view->jump_to_find_result = FALSE;
2269         /* Shift+Wheel scrolls the in the perpendicular direction */
2270         if (state & GDK_SHIFT_MASK) {
2271                 if (event->direction == GDK_SCROLL_UP)
2272                         event->direction = GDK_SCROLL_LEFT;
2273                 if (event->direction == GDK_SCROLL_LEFT)
2274                         event->direction = GDK_SCROLL_UP;
2275                 if (event->direction == GDK_SCROLL_DOWN)
2276                         event->direction = GDK_SCROLL_RIGHT;
2277                 if (event->direction == GDK_SCROLL_RIGHT)
2278                         event->direction = GDK_SCROLL_DOWN;
2279
2280                 event->state &= ~GDK_SHIFT_MASK;
2281                 state &= ~GDK_SHIFT_MASK;
2282         }
2283
2284         if (state == 0 && view->presentation) {
2285                 switch (event->direction) {
2286                         case GDK_SCROLL_DOWN:
2287                         case GDK_SCROLL_RIGHT:
2288                                 ev_view_next_page (view);       
2289                                 break;
2290                         case GDK_SCROLL_UP:
2291                         case GDK_SCROLL_LEFT:
2292                                 ev_view_previous_page (view);
2293                                 break;
2294                 }
2295
2296                 return TRUE;
2297         }
2298
2299         return FALSE;
2300 }
2301
2302 static EvViewSelection *
2303 find_selection_for_page (EvView *view,
2304                          gint    page)
2305 {
2306         GList *list;
2307
2308         for (list = view->selection_info.selections; list != NULL; list = list->next) {
2309                 EvViewSelection *selection;
2310
2311                 selection = (EvViewSelection *) list->data;
2312
2313                 if (selection->page == page)
2314                         return selection;
2315         }
2316
2317         return NULL;
2318 }
2319
2320 static void
2321 draw_end_presentation_page (EvView       *view,
2322                             GdkRectangle *page_area)
2323 {
2324         PangoLayout *layout;
2325         PangoFontDescription *font_desc;
2326         gchar *markup;
2327         const gchar *text = _("End of presentation. Press Escape to exit.");
2328
2329         if (view->presentation_state != EV_PRESENTATION_END)
2330                 return;
2331
2332         layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), NULL);
2333         markup = g_strdup_printf ("<span foreground=\"white\">%s</span>", text);
2334         pango_layout_set_markup (layout, markup, -1);
2335         g_free (markup);
2336
2337         font_desc = pango_font_description_new ();
2338         pango_font_description_set_size (font_desc, 16 * PANGO_SCALE);
2339         pango_layout_set_font_description (layout, font_desc);
2340
2341         gtk_paint_layout (GTK_WIDGET (view)->style,
2342                           view->layout.bin_window,
2343                           GTK_WIDGET_STATE (view),
2344                           FALSE,
2345                           page_area,
2346                           GTK_WIDGET (view),
2347                           NULL,
2348                           page_area->x + 15,
2349                           page_area->y + 15,
2350                           layout);
2351
2352         pango_font_description_free (font_desc);
2353         g_object_unref (layout);
2354 }
2355
2356 static gboolean
2357 ev_view_expose_event (GtkWidget      *widget,
2358                       GdkEventExpose *event)
2359 {
2360         EvView *view = EV_VIEW (widget);
2361         int i;
2362
2363         if (view->presentation) {
2364                 switch (view->presentation_state) {
2365                         case EV_PRESENTATION_END: {
2366                                 GdkRectangle area = {0};
2367
2368                                 area.width = widget->allocation.width;
2369                                 area.height = widget->allocation.height;
2370                                 
2371                                 draw_end_presentation_page (view, &area);
2372                         }
2373                                 return FALSE;
2374                         case EV_PRESENTATION_BLACK:
2375                         case EV_PRESENTATION_WHITE:
2376                                 return FALSE;
2377                         case EV_PRESENTATION_NORMAL:
2378                         default:
2379                                 break;
2380                 }
2381         } else if (view->loading) {
2382                 GdkRectangle area = {0};
2383                 
2384                 area.width = widget->allocation.width;
2385                 area.height = widget->allocation.height;
2386
2387                 draw_loading_text (view,
2388                                    &area,
2389                                    &(event->area));
2390         }
2391
2392         if (view->document == NULL)
2393                 return FALSE;
2394
2395         for (i = view->start_page; i <= view->end_page; i++) {
2396                 GdkRectangle page_area;
2397                 GtkBorder border;
2398                 gboolean page_ready = TRUE;
2399
2400                 if (!get_page_extents (view, i, &page_area, &border))
2401                         continue;
2402
2403                 page_area.x -= view->scroll_x;
2404                 page_area.y -= view->scroll_y;
2405
2406                 draw_one_page (view, i, &page_area, &border, &(event->area), &page_ready);
2407
2408                 if (page_ready && EV_IS_DOCUMENT_FIND (view->document))
2409                         highlight_find_results (view, i);
2410         }
2411
2412         if (GTK_WIDGET_CLASS (ev_view_parent_class)->expose_event)
2413                 (* GTK_WIDGET_CLASS (ev_view_parent_class)->expose_event) (widget, event);
2414
2415         return FALSE;
2416 }
2417
2418 static gboolean
2419 ev_view_do_popup_menu (EvView *view,
2420                        gdouble x,
2421                        gdouble y)
2422 {
2423         EvLink  *link;
2424         EvImage *image;
2425
2426         image = ev_view_get_image_at_location (view, x, y);
2427         if (image) {
2428                 g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, image);
2429                 return TRUE;
2430         }
2431
2432         link = ev_view_get_link_at_location (view, x, y);
2433         if (link) {
2434                 g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, link);
2435                 return TRUE;
2436         }
2437
2438         g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, NULL);
2439
2440         return TRUE;
2441 }
2442
2443 static gboolean
2444 ev_view_popup_menu (GtkWidget *widget)
2445 {
2446         gint x, y;
2447         
2448         gtk_widget_get_pointer (widget, &x, &y);
2449         return ev_view_do_popup_menu (EV_VIEW (widget), x, y);
2450 }
2451
2452 static gboolean
2453 ev_view_button_press_event (GtkWidget      *widget,
2454                             GdkEventButton *event)
2455 {
2456         EvView *view = EV_VIEW (widget);
2457
2458         if (!view->document)
2459                 return FALSE;
2460         
2461         if (!GTK_WIDGET_HAS_FOCUS (widget)) {
2462                 gtk_widget_grab_focus (widget);
2463         }
2464         
2465         view->pressed_button = event->button;
2466         view->selection_info.in_drag = FALSE;
2467         
2468         switch (event->button) {
2469                 case 1: {
2470                         EvImage *image;
2471                         EvFormField *field;
2472
2473                         if (view->selection_info.selections) {
2474                                 if (location_in_selected_text (view,
2475                                                                event->x + view->scroll_x,
2476                                                                event->y + view->scroll_y)) {
2477                                         view->selection_info.in_drag = TRUE;
2478                                 } else {
2479                                         clear_selection (view);
2480                                         
2481                                         view->selection_info.start.x = event->x + view->scroll_x;
2482                                         view->selection_info.start.y = event->y + view->scroll_y;
2483                                 }
2484                                 
2485                                 gtk_widget_queue_draw (widget);
2486                         } else if (!location_in_text (view, event->x + view->scroll_x, event->y + view->scroll_y) &&
2487                                    (image = ev_view_get_image_at_location (view, event->x, event->y))) {
2488                                 if (view->image_dnd_info.image)
2489                                         g_object_unref (view->image_dnd_info.image);
2490                                 view->image_dnd_info.image = g_object_ref (image);
2491                                 view->image_dnd_info.in_drag = TRUE;
2492
2493                                 view->image_dnd_info.start.x = event->x + view->scroll_x;
2494                                 view->image_dnd_info.start.y = event->y + view->scroll_y;
2495                         } else if ((field = ev_view_get_form_field_at_location (view, event->x, event->y))) {
2496                                 ev_view_remove_all (view);
2497                                 ev_view_handle_form_field (view, field, event->x, event->y);
2498                         } else {
2499                                 ev_view_remove_all (view);
2500                                 view->selection_info.start.x = event->x + view->scroll_x;
2501                                 view->selection_info.start.y = event->y + view->scroll_y;
2502                         }
2503                 }                       
2504                         return TRUE;
2505                 case 2:
2506                         /* use root coordinates as reference point because
2507                          * scrolling changes window relative coordinates */
2508                         view->drag_info.start.x = event->x_root;
2509                         view->drag_info.start.y = event->y_root;
2510                         view->drag_info.hadj = gtk_adjustment_get_value (view->hadjustment);
2511                         view->drag_info.vadj = gtk_adjustment_get_value (view->vadjustment);
2512
2513                         ev_view_set_cursor (view, EV_VIEW_CURSOR_DRAG);
2514
2515                         return TRUE;
2516                 case 3:
2517                         return ev_view_do_popup_menu (view, event->x, event->y);
2518         }
2519         
2520         return FALSE;
2521 }
2522
2523 static void
2524 ev_view_remove_all (EvView *view)
2525 {
2526         GList *children, *child;
2527
2528         children = gtk_container_get_children (GTK_CONTAINER (view));
2529         for (child = children; child && child->data; child = g_list_next (child)) {
2530                 gtk_container_remove (GTK_CONTAINER (view),
2531                                       GTK_WIDGET (child->data));
2532         }
2533         g_list_free (children);
2534 }
2535
2536 /*** Drag and Drop ***/
2537 static void
2538 ev_view_drag_data_get (GtkWidget        *widget,
2539                        GdkDragContext   *context,
2540                        GtkSelectionData *selection_data,
2541                        guint             info,
2542                        guint             time)
2543 {
2544         EvView *view = EV_VIEW (widget);
2545
2546         switch (info) {
2547                 case TARGET_DND_TEXT:
2548                         if (view->selection_info.selections &&
2549                             ev_document_can_get_text (view->document)) {
2550                                 gchar *text;
2551
2552                                 text = get_selected_text (view);
2553                                 
2554                                 gtk_selection_data_set_text (selection_data,
2555                                                              text,
2556                                                              strlen (text));
2557                                 
2558                                 g_free (text);
2559                         }
2560                         break;
2561                 case TARGET_DND_IMAGE:
2562                         if (view->image_dnd_info.image) {
2563                                 GdkPixbuf *pixbuf;
2564
2565                                 pixbuf = ev_image_get_pixbuf (view->image_dnd_info.image);
2566                                 gtk_selection_data_set_pixbuf (selection_data, pixbuf);
2567                         }
2568                         break;
2569                 case TARGET_DND_URI:
2570                         if (view->image_dnd_info.image) {
2571                                 const gchar *tmp_uri;
2572                                 gchar      **uris;
2573
2574                                 tmp_uri = ev_image_save_tmp (view->image_dnd_info.image);
2575
2576                                 uris = g_new0 (gchar *, 2);
2577                                 uris[0] = (gchar *)tmp_uri;
2578                                 
2579                                 gtk_selection_data_set_uris (selection_data, uris);
2580
2581                                 /* g_free instead of g_strfreev since tmp_uri is const */ 
2582                                 g_free (uris);
2583                         }
2584         }
2585 }
2586
2587 static gboolean
2588 ev_view_drag_motion (GtkWidget      *widget,
2589                      GdkDragContext *context,
2590                      gint            x,
2591                      gint            y,
2592                      guint           time)
2593 {
2594         if (gtk_drag_get_source_widget (context) == widget)
2595                 gdk_drag_status (context, 0, time);
2596         else
2597                 gdk_drag_status (context, context->suggested_action, time);
2598         
2599         return TRUE;
2600 }
2601                      
2602 static void
2603 ev_view_drag_data_received (GtkWidget          *widget,
2604                             GdkDragContext     *context,
2605                             gint                x,
2606                             gint                y,
2607                             GtkSelectionData   *selection_data,
2608                             guint               info,
2609                             guint               time)
2610 {
2611         gchar  **uris;
2612         gint     i = 0;
2613         GSList  *uri_list = NULL;
2614
2615         uris = gtk_selection_data_get_uris (selection_data);
2616         if (!uris) {
2617                 gtk_drag_finish (context, FALSE, FALSE, time);
2618                 return;
2619         }
2620
2621         for (i = 0; uris[i]; i++) {
2622                 uri_list = g_slist_prepend (uri_list, (gpointer) uris[i]);
2623         }
2624         
2625         ev_application_open_uri_list (EV_APP, uri_list,
2626                                       gtk_widget_get_screen (widget),
2627                                       0);
2628         gtk_drag_finish (context, TRUE, FALSE, time);
2629         
2630         g_strfreev (uris);
2631         g_slist_free (uri_list);
2632 }
2633
2634
2635 static gboolean
2636 selection_update_idle_cb (EvView *view)
2637 {
2638         compute_selections (view, &view->selection_info.start, &view->motion);
2639         view->selection_update_id = 0;
2640         return FALSE;
2641 }
2642
2643 static gboolean
2644 selection_scroll_timeout_cb (EvView *view)
2645 {       
2646         gint x, y, shift = 0;
2647         GtkWidget *widget = GTK_WIDGET (view);
2648         
2649         gtk_widget_get_pointer (widget, &x, &y);
2650
2651         if (y > widget->allocation.height) {
2652                 shift = (y - widget->allocation.height) / 2;
2653         } else if (y < 0) {
2654                 shift = y / 2;
2655         }
2656
2657         if (shift)
2658                 gtk_adjustment_set_value (view->vadjustment,
2659                                           CLAMP (view->vadjustment->value + shift,
2660                                           view->vadjustment->lower,
2661                                           view->vadjustment->upper -
2662                                           view->vadjustment->page_size));       
2663
2664         if (x > widget->allocation.width) {
2665                 shift = (x - widget->allocation.width) / 2;
2666         } else if (x < 0) {
2667                 shift = x / 2;
2668         }
2669
2670         if (shift)
2671                 gtk_adjustment_set_value (view->hadjustment,
2672                                           CLAMP (view->hadjustment->value + shift,
2673                                           view->hadjustment->lower,
2674                                           view->hadjustment->upper -
2675                                           view->hadjustment->page_size));       
2676
2677         return TRUE;
2678 }
2679
2680 static gboolean
2681 ev_view_motion_notify_event (GtkWidget      *widget,
2682                              GdkEventMotion *event)
2683 {
2684         EvView *view = EV_VIEW (widget);
2685         gint x, y;
2686
2687         if (!view->document)
2688                 return FALSE;
2689                 
2690         if (event->is_hint || event->window != view->layout.bin_window) {
2691             gtk_widget_get_pointer (widget, &x, &y);
2692         } else {
2693             x = event->x;
2694             y = event->y;
2695         }
2696
2697         if (view->selection_info.in_drag) {
2698                 if (gtk_drag_check_threshold (widget,
2699                                               view->selection_info.start.x,
2700                                               view->selection_info.start.y,
2701                                               x, y)) {
2702                         GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
2703
2704                         gtk_target_list_add_text_targets (target_list, TARGET_DND_TEXT);
2705
2706                         gtk_drag_begin (widget, target_list,
2707                                         GDK_ACTION_COPY,
2708                                         1, (GdkEvent *)event);
2709
2710                         view->selection_info.in_drag = FALSE;
2711
2712                         gtk_target_list_unref (target_list);
2713
2714                         return TRUE;
2715                 }
2716         } else if (view->image_dnd_info.in_drag) {
2717                 if (gtk_drag_check_threshold (widget,
2718                                               view->selection_info.start.x,
2719                                               view->selection_info.start.y,
2720                                               x, y)) {
2721                         GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
2722
2723                         gtk_target_list_add_uri_targets (target_list, TARGET_DND_URI);
2724                         gtk_target_list_add_image_targets (target_list, TARGET_DND_IMAGE, TRUE);
2725
2726                         gtk_drag_begin (widget, target_list,
2727                                         GDK_ACTION_COPY,
2728                                         1, (GdkEvent *)event);
2729
2730                         view->image_dnd_info.in_drag = FALSE;
2731
2732                         gtk_target_list_unref (target_list);
2733
2734                         return TRUE;
2735                 }
2736         }
2737         
2738         /* For the Evince 0.4.x release, we limit selection to un-rotated
2739          * documents only.
2740          */
2741         if (view->pressed_button == 1 && view->rotation == 0) {
2742
2743                 /* Schedule timeout to scroll during selection and additionally 
2744                  * scroll once to allow arbitrary speed. */
2745                 if (!view->selection_scroll_id)
2746                     view->selection_scroll_id = g_timeout_add (SCROLL_TIME, (GSourceFunc)selection_scroll_timeout_cb, view);
2747                 else 
2748                     selection_scroll_timeout_cb (view);
2749
2750                 view->selection_info.in_selection = TRUE;
2751                 view->motion.x = x + view->scroll_x;
2752                 view->motion.y = y + view->scroll_y;
2753
2754                 /* Queue an idle to handle the motion.  We do this because      
2755                  * handling any selection events in the motion could be slower  
2756                  * than new motion events reach us.  We always put it in the    
2757                  * idle to make sure we catch up and don't visibly lag the      
2758                  * mouse. */
2759                 if (!view->selection_update_id)
2760                         view->selection_update_id = g_idle_add ((GSourceFunc)selection_update_idle_cb, view);
2761
2762                 return TRUE;
2763         } else if (view->pressed_button == 2) {
2764                 if (!view->drag_info.in_drag) {
2765                         gboolean start;
2766
2767                         start = gtk_drag_check_threshold (widget,
2768                                                           view->drag_info.start.x,
2769                                                           view->drag_info.start.y,
2770                                                           event->x_root,
2771                                                           event->y_root);
2772                         view->drag_info.in_drag = start;
2773                 }
2774
2775                 if (view->drag_info.in_drag) {
2776                         int dx, dy;
2777                         gdouble dhadj_value, dvadj_value;
2778
2779                         dx = event->x_root - view->drag_info.start.x;
2780                         dy = event->y_root - view->drag_info.start.y;
2781
2782                         dhadj_value = view->hadjustment->page_size *
2783                                       (gdouble)dx / widget->allocation.width;
2784                         dvadj_value = view->vadjustment->page_size *
2785                                       (gdouble)dy / widget->allocation.height;
2786
2787                         /* clamp scrolling to visible area */
2788                         gtk_adjustment_set_value (view->hadjustment,
2789                                                   MIN(view->drag_info.hadj - dhadj_value,
2790                                                       view->hadjustment->upper -
2791                                                       view->hadjustment->page_size));
2792                         gtk_adjustment_set_value (view->vadjustment,
2793                                                   MIN(view->drag_info.vadj - dvadj_value,
2794                                                       view->vadjustment->upper -
2795                                                       view->vadjustment->page_size));
2796
2797                         return TRUE;
2798                 }
2799         } else if (view->pressed_button <= 0) {
2800                 ev_view_handle_cursor_over_xy (view, x, y);
2801                 return TRUE;
2802         }
2803
2804         return FALSE;
2805 }
2806
2807 static gboolean
2808 ev_view_button_release_event (GtkWidget      *widget,
2809                               GdkEventButton *event)
2810 {
2811         EvView *view = EV_VIEW (widget);
2812         EvLink *link;
2813
2814         if (view->pressed_button == 2) {
2815                 ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
2816         }
2817
2818         if (view->document && view->pressed_button != 3) {
2819                 link = ev_view_get_link_at_location (view, event->x, event->y);
2820         } else {
2821                 link = NULL;
2822         }
2823
2824         view->pressed_button = -1;
2825         view->drag_info.in_drag = FALSE;
2826         view->image_dnd_info.in_drag = FALSE;
2827
2828         if (view->selection_scroll_id) {
2829             g_source_remove (view->selection_scroll_id);
2830             view->selection_scroll_id = 0;
2831         }
2832         if (view->selection_update_id) {
2833             g_source_remove (view->selection_update_id);
2834             view->selection_update_id = 0;
2835         }
2836
2837         if (view->selection_info.selections) {
2838                 ev_view_update_primary_selection (view);
2839                 
2840                 if (view->selection_info.in_drag) {
2841                         clear_selection (view);
2842                         gtk_widget_queue_draw (widget);
2843                 }
2844                 
2845                 view->selection_info.in_drag = FALSE;
2846         } else if (link) {
2847                 if (event->button == 2) {
2848                         EvLinkAction    *action;
2849                         EvLinkActionType type;
2850
2851                         action = ev_link_get_action (link);
2852                         if (!action)
2853                                 return FALSE;
2854
2855                         type = ev_link_action_get_action_type (action);
2856                         if (type == EV_LINK_ACTION_TYPE_GOTO_DEST) {
2857                                 g_signal_emit (view,
2858                                                signals[SIGNAL_EXTERNAL_LINK],
2859                                                0, action);
2860                         }
2861                 } else {
2862                         ev_view_handle_link (view, link);
2863                 }
2864         } else if (view->presentation) {
2865                 switch (event->button) {
2866                         case 1:
2867                                 ev_view_next_page (view);       
2868                                 return TRUE;
2869                         case 3:
2870                                 ev_view_previous_page (view);   
2871                                 return TRUE;
2872                 }
2873         }
2874  
2875         return FALSE;
2876 }
2877
2878 /* Goto Window */
2879 /* Cut and paste from gtkwindow.c */
2880 static void
2881 send_focus_change (GtkWidget *widget,
2882                    gboolean   in)
2883 {
2884         GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
2885
2886         g_object_ref (widget);
2887
2888         if (in)
2889                 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
2890         else
2891                 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
2892
2893         fevent->focus_change.type = GDK_FOCUS_CHANGE;
2894         fevent->focus_change.window = g_object_ref (widget->window);
2895         fevent->focus_change.in = in;
2896
2897         gtk_widget_event (widget, fevent);
2898
2899         g_object_notify (G_OBJECT (widget), "has-focus");
2900
2901         g_object_unref (widget);
2902         gdk_event_free (fevent);
2903 }
2904
2905 static void
2906 ev_view_goto_window_hide (EvView *view)
2907 {
2908         /* send focus-in event */
2909         send_focus_change (view->goto_entry, FALSE);
2910         gtk_widget_hide (view->goto_window);
2911         gtk_entry_set_text (GTK_ENTRY (view->goto_entry), "");
2912 }
2913
2914 static gboolean
2915 ev_view_goto_window_delete_event (GtkWidget   *widget,
2916                                   GdkEventAny *event,
2917                                   EvView      *view)
2918 {
2919         ev_view_goto_window_hide (view);
2920
2921         return TRUE;
2922 }
2923
2924 static gboolean
2925 key_is_numeric (guint keyval)
2926 {
2927         return ((keyval >= GDK_0 && keyval <= GDK_9) ||
2928                 (keyval >= GDK_KP_0 && keyval <= GDK_KP_9));
2929 }
2930
2931 static gboolean
2932 ev_view_goto_window_key_press_event (GtkWidget   *widget,
2933                                      GdkEventKey *event,
2934                                      EvView      *view)
2935 {
2936         switch (event->keyval) {
2937                 case GDK_Escape:
2938                 case GDK_Tab:
2939                 case GDK_KP_Tab:
2940                 case GDK_ISO_Left_Tab:
2941                         ev_view_goto_window_hide (view);
2942                         return TRUE;
2943                 case GDK_Return:
2944                 case GDK_KP_Enter:
2945                 case GDK_ISO_Enter:
2946                 case GDK_BackSpace:
2947                 case GDK_Delete:
2948                         return FALSE;
2949                 default:
2950                         if (!key_is_numeric (event->keyval))
2951                                 return TRUE;
2952         }
2953
2954         return FALSE;
2955 }
2956
2957 static gboolean
2958 ev_view_goto_window_button_press_event (GtkWidget      *widget,
2959                                         GdkEventButton *event,
2960                                         EvView         *view)
2961 {
2962         ev_view_goto_window_hide (view);
2963
2964         return TRUE;
2965 }
2966
2967 static void
2968 ev_view_goto_entry_activate (GtkEntry *entry,
2969                              EvView   *view)
2970 {
2971         const gchar *text;
2972         gint         page;
2973
2974         text = gtk_entry_get_text (entry);
2975         page = atoi (text) - 1;
2976         
2977         ev_view_goto_window_hide (view);
2978
2979         if (page >= 0 &&
2980             page < ev_page_cache_get_n_pages (view->page_cache))
2981                 ev_page_cache_set_current_page (view->page_cache, page);
2982 }
2983
2984 static void
2985 ev_view_goto_window_create (EvView *view)
2986 {
2987         GtkWidget *frame, *hbox, *toplevel, *label;
2988
2989         toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view));
2990         
2991         if (view->goto_window) {
2992                 if (GTK_WINDOW (toplevel)->group)
2993                         gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
2994                                                      GTK_WINDOW (view->goto_window));
2995                 else if (GTK_WINDOW (view->goto_window)->group)
2996                         gtk_window_group_remove_window (GTK_WINDOW (view->goto_window)->group,
2997                                                         GTK_WINDOW (view->goto_window));
2998                 return;
2999         }
3000
3001         view->goto_window = gtk_window_new (GTK_WINDOW_POPUP);
3002
3003         if (GTK_WINDOW (toplevel)->group)
3004                 gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
3005                                              GTK_WINDOW (view->goto_window));
3006         
3007         gtk_window_set_modal (GTK_WINDOW (view->goto_window), TRUE);
3008
3009         g_signal_connect (view->goto_window, "delete_event",
3010                           G_CALLBACK (ev_view_goto_window_delete_event),
3011                           view);
3012         g_signal_connect (view->goto_window, "key_press_event",
3013                           G_CALLBACK (ev_view_goto_window_key_press_event),
3014                           view);
3015         g_signal_connect (view->goto_window, "button_press_event",
3016                           G_CALLBACK (ev_view_goto_window_button_press_event),
3017                           view);
3018
3019         frame = gtk_frame_new (NULL);
3020         gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
3021         gtk_container_add (GTK_CONTAINER (view->goto_window), frame);
3022         gtk_widget_show (frame);
3023
3024         hbox = gtk_hbox_new (FALSE, 0);
3025         gtk_container_set_border_width (GTK_CONTAINER (hbox), 3);
3026         gtk_container_add (GTK_CONTAINER (frame), hbox);
3027         gtk_widget_show (hbox);
3028
3029         label = gtk_label_new(_("Jump to page:"));
3030         gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 3);
3031         gtk_widget_show (label);
3032         gtk_widget_realize (label);
3033
3034         view->goto_entry = gtk_entry_new ();
3035         g_signal_connect (view->goto_entry, "activate",
3036                           G_CALLBACK (ev_view_goto_entry_activate),
3037                           view);
3038         gtk_box_pack_start_defaults (GTK_BOX (hbox), view->goto_entry);
3039         gtk_widget_show (view->goto_entry);
3040         gtk_widget_realize (view->goto_entry);
3041 }
3042
3043 static void
3044 ev_view_goto_entry_grab_focus (EvView *view)
3045 {
3046         GtkWidgetClass *entry_parent_class;
3047         
3048         entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (view->goto_entry));
3049         (entry_parent_class->grab_focus) (view->goto_entry);
3050
3051         send_focus_change (view->goto_entry, TRUE);
3052 }
3053
3054 static void
3055 ev_view_goto_window_send_key_event (EvView   *view,
3056                                     GdkEvent *event)
3057 {
3058         GdkEventKey *new_event;
3059         GdkScreen   *screen;
3060
3061         /* Move goto window off screen */
3062         screen = gtk_widget_get_screen (GTK_WIDGET (view));
3063         gtk_window_move (GTK_WINDOW (view->goto_window),
3064                          gdk_screen_get_width (screen) + 1,
3065                          gdk_screen_get_height (screen) + 1);
3066         gtk_widget_show (view->goto_window);
3067
3068         new_event = (GdkEventKey *) gdk_event_copy (event);
3069         g_object_unref (new_event->window);
3070         new_event->window = g_object_ref (view->goto_window->window);
3071         gtk_widget_realize (view->goto_window);
3072
3073         gtk_widget_event (view->goto_window, (GdkEvent *)new_event);
3074         gdk_event_free ((GdkEvent *)new_event);
3075         gtk_widget_hide (view->goto_window);
3076 }
3077
3078 static gboolean
3079 ev_view_key_press_event (GtkWidget   *widget,
3080                          GdkEventKey *event)
3081 {
3082         EvView *view = EV_VIEW (widget);
3083         EvPresentationState current;
3084
3085         if (!view->document)
3086                 return FALSE;
3087         
3088         if (!view->presentation ||
3089             view->presentation_state == EV_PRESENTATION_END)
3090                 return gtk_bindings_activate_event (GTK_OBJECT (widget), event);
3091
3092
3093         current = view->presentation_state;
3094
3095         switch (event->keyval) {
3096                 case GDK_b:
3097                 case GDK_B:
3098                         view->presentation_state =
3099                                 (view->presentation_state == EV_PRESENTATION_BLACK) ?
3100                                 EV_PRESENTATION_NORMAL : EV_PRESENTATION_BLACK;
3101                         break;
3102                 case GDK_w:
3103                 case GDK_W:
3104                         view->presentation_state =
3105                                 (view->presentation_state == EV_PRESENTATION_WHITE) ?
3106                                 EV_PRESENTATION_NORMAL : EV_PRESENTATION_WHITE;
3107                         break;
3108                 default:
3109                         if (view->presentation_state == EV_PRESENTATION_BLACK ||
3110                             view->presentation_state == EV_PRESENTATION_WHITE) {
3111                                 view->presentation_state = EV_PRESENTATION_NORMAL;
3112                         }
3113         }
3114
3115         if (current == view->presentation_state) {
3116                 if (ev_page_cache_get_n_pages (view->page_cache) > 1 &&
3117                     key_is_numeric (event->keyval)) {
3118                         gint x, y;
3119                         
3120                         ev_view_goto_window_create (view);
3121                         ev_view_goto_window_send_key_event (view, (GdkEvent *)event);
3122                         gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
3123                         gtk_window_move (GTK_WINDOW (view->goto_window), x, y);
3124                         gtk_widget_show (view->goto_window);
3125                         ev_view_goto_entry_grab_focus (view);
3126                         
3127                         return TRUE;
3128                 }
3129                 
3130                 return gtk_bindings_activate_event (GTK_OBJECT (widget), event);
3131         }
3132
3133         switch (view->presentation_state) {
3134                 case EV_PRESENTATION_NORMAL:
3135                 case EV_PRESENTATION_BLACK:
3136                         gdk_window_set_background (view->layout.bin_window,
3137                                                    &widget->style->black);
3138                         break;
3139                 case EV_PRESENTATION_WHITE:
3140                         gdk_window_set_background (view->layout.bin_window,
3141                                                    &widget->style->white);
3142                         break;
3143                 default:
3144                         return gtk_bindings_activate_event (GTK_OBJECT (widget), event);
3145         }
3146
3147         gtk_widget_queue_draw (widget);
3148         return TRUE;
3149 }
3150
3151 static gint
3152 ev_view_focus_in (GtkWidget     *widget,
3153                   GdkEventFocus *event)
3154 {
3155         if (EV_VIEW (widget)->pixbuf_cache)
3156                 ev_pixbuf_cache_style_changed (EV_VIEW (widget)->pixbuf_cache);
3157         gtk_widget_queue_draw (widget);
3158
3159         return FALSE;
3160 }
3161
3162 static gint
3163 ev_view_focus_out (GtkWidget     *widget,
3164                      GdkEventFocus *event)
3165 {
3166         if (EV_VIEW (widget)->goto_window)
3167                 ev_view_goto_window_hide (EV_VIEW (widget));
3168         
3169         if (EV_VIEW (widget)->pixbuf_cache)
3170                 ev_pixbuf_cache_style_changed (EV_VIEW (widget)->pixbuf_cache);
3171         gtk_widget_queue_draw (widget);
3172
3173         return FALSE;
3174 }
3175
3176 static gboolean
3177 ev_view_leave_notify_event (GtkWidget *widget, GdkEventCrossing   *event)
3178 {
3179         EvView *view = EV_VIEW (widget);
3180     
3181         ev_view_set_status (view, NULL);
3182
3183         if (view->cursor == EV_VIEW_CURSOR_LINK ||
3184             view->cursor == EV_VIEW_CURSOR_IBEAM)
3185                 ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
3186
3187         if (view->link_tooltip) {
3188                 view->hovered_link = NULL;
3189                 ev_tooltip_deactivate (EV_TOOLTIP (view->link_tooltip));
3190         }
3191
3192         return FALSE;
3193 }
3194
3195 static gboolean
3196 ev_view_enter_notify_event (GtkWidget *widget, GdkEventCrossing   *event)
3197 {
3198         EvView *view = EV_VIEW (widget);
3199
3200         ev_view_handle_cursor_over_xy (view, event->x, event->y);
3201     
3202         return FALSE;
3203 }
3204
3205 static void
3206 ev_view_style_set (GtkWidget *widget,
3207                    GtkStyle  *old_style)
3208 {
3209         if (EV_VIEW (widget)->pixbuf_cache)
3210                 ev_pixbuf_cache_style_changed (EV_VIEW (widget)->pixbuf_cache);
3211
3212         GTK_WIDGET_CLASS (ev_view_parent_class)->style_set (widget, old_style);
3213 }
3214
3215 /*** Drawing ***/
3216
3217 static guint32
3218 ev_gdk_color_to_rgb (const GdkColor *color)
3219 {
3220   guint32 result;
3221   result = (0xff0000 | (color->red & 0xff00));
3222   result <<= 8;
3223   result |= ((color->green & 0xff00) | (color->blue >> 8));
3224   return result;
3225 }
3226
3227 static void
3228 draw_rubberband (GtkWidget *widget, GdkWindow *window,
3229                  const GdkRectangle *rect, guchar alpha)
3230 {
3231         GdkGC *gc;
3232         GdkPixbuf *pixbuf;
3233         GdkColor *fill_color_gdk;
3234         guint fill_color;
3235
3236         fill_color_gdk = gdk_color_copy (&GTK_WIDGET (widget)->style->base[GTK_STATE_SELECTED]);
3237         fill_color = ev_gdk_color_to_rgb (fill_color_gdk) << 8 | alpha;
3238
3239         pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
3240                                  rect->width, rect->height);
3241         gdk_pixbuf_fill (pixbuf, fill_color);
3242
3243         gdk_draw_pixbuf (window, NULL, pixbuf,
3244                          0, 0,
3245                          rect->x - EV_VIEW (widget)->scroll_x, rect->y - EV_VIEW (widget)->scroll_y,
3246                          rect->width, rect->height,
3247                          GDK_RGB_DITHER_NONE,
3248                          0, 0);
3249
3250         g_object_unref (pixbuf);
3251
3252         gc = gdk_gc_new (window);
3253         gdk_gc_set_rgb_fg_color (gc, fill_color_gdk);
3254         gdk_draw_rectangle (window, gc, FALSE,
3255                             rect->x - EV_VIEW (widget)->scroll_x, rect->y - EV_VIEW (widget)->scroll_y,
3256                             rect->width - 1,
3257                             rect->height - 1);
3258         g_object_unref (gc);
3259
3260         gdk_color_free (fill_color_gdk);
3261 }
3262
3263
3264 static void
3265 highlight_find_results (EvView *view, int page)
3266 {
3267         EvDocumentFind *find;
3268         int i, results = 0;
3269
3270         find = EV_DOCUMENT_FIND (view->document);
3271
3272         results = ev_document_find_get_n_results (find, page);
3273
3274         for (i = 0; i < results; i++) {
3275                 EvRectangle rectangle;
3276                 GdkRectangle view_rectangle;
3277                 guchar alpha;
3278
3279                 if (i == view->find_result && page == view->current_page) {
3280                         alpha = 0x90;
3281                 } else {
3282                         alpha = 0x20;
3283                 }
3284
3285                 ev_document_find_get_result (find, page, i, &rectangle);
3286                 doc_rect_to_view_rect (view, page, &rectangle, &view_rectangle);
3287                 draw_rubberband (GTK_WIDGET (view), view->layout.bin_window,
3288                                  &view_rectangle, alpha);
3289         }
3290 }
3291
3292 static void
3293 draw_loading_text (EvView       *view,
3294                    GdkRectangle *page_area,
3295                    GdkRectangle *expose_area)
3296 {
3297         cairo_t *cr;
3298         gint     width, height;
3299
3300         /* Don't annoy users with loading messages during presentations.
3301          * FIXME: Temporary "workaround" for
3302          * http://bugzilla.gnome.org/show_bug.cgi?id=320352 */
3303         if (view->presentation)
3304                 return;
3305
3306         if (!view->loading_text) {
3307                 const gchar *loading_text = _("Loading...");
3308                 PangoLayout *layout;
3309                 PangoFontDescription *font_desc;
3310                 PangoRectangle logical_rect;
3311                 gint target_width;
3312                 gdouble real_scale;
3313
3314                 ev_document_fc_mutex_lock ();
3315
3316                 layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), loading_text);
3317                 
3318                 font_desc = pango_font_description_new ();
3319                 
3320                 /* We set the font to be 10 points, get the size, and scale appropriately */
3321                 pango_font_description_set_size (font_desc, 10 * PANGO_SCALE);
3322                 pango_layout_set_font_description (layout, font_desc);
3323                 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
3324
3325                 target_width = MAX (page_area->width / 2, 1);
3326                 real_scale = ((double)target_width / (double) logical_rect.width) * (PANGO_SCALE * 10);
3327                 pango_font_description_set_size (font_desc, (int)real_scale);
3328                 pango_layout_set_font_description (layout, font_desc);
3329                 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
3330
3331                 view->loading_text = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
3332                                                                  logical_rect.width,
3333                                                                  logical_rect.height);
3334                 cr = cairo_create (view->loading_text);
3335                 cairo_set_source_rgb (cr,
3336                                       155 / (double)255,
3337                                       155 / (double)255,
3338                                       155 / (double)255);
3339                 pango_cairo_show_layout (cr, layout);
3340                 cairo_destroy (cr);
3341
3342                 pango_font_description_free (font_desc);
3343                 g_object_unref (layout);
3344
3345                 ev_document_fc_mutex_unlock ();
3346         }
3347
3348         width = (page_area->width - cairo_image_surface_get_width (view->loading_text)) / 2;
3349         height = (page_area->height - cairo_image_surface_get_height (view->loading_text)) / 2;
3350         
3351         cr = gdk_cairo_create (view->layout.bin_window);
3352         cairo_translate (cr,
3353                          page_area->x + width,
3354                          page_area->y + height);
3355         cairo_set_source_surface (cr, view->loading_text, 0, 0);
3356         cairo_paint (cr);
3357         cairo_destroy (cr);
3358 }
3359
3360 static void
3361 draw_one_page (EvView       *view,
3362                gint          page,
3363                GdkRectangle *page_area,
3364                GtkBorder    *border,
3365                GdkRectangle *expose_area,
3366                gboolean     *page_ready)
3367 {
3368         GdkRectangle overlap;
3369         GdkRectangle real_page_area;
3370
3371         g_assert (view->document);
3372
3373         if (! gdk_rectangle_intersect (page_area, expose_area, &overlap))
3374                 return;
3375
3376         /* Render the document itself */
3377         real_page_area = *page_area;
3378
3379         real_page_area.x += border->left;
3380         real_page_area.y += border->top;
3381         real_page_area.width -= (border->left + border->right);
3382         real_page_area.height -= (border->top + border->bottom);
3383         *page_ready = TRUE;
3384
3385         if (!view->presentation) {
3386                 gint current_page;
3387                 
3388                 current_page = ev_page_cache_get_current_page (view->page_cache);
3389                 ev_document_misc_paint_one_page (view->layout.bin_window,
3390                                                  GTK_WIDGET (view),
3391                                                  page_area, border, 
3392                                                  page == current_page);
3393         }
3394
3395         if (gdk_rectangle_intersect (&real_page_area, expose_area, &overlap)) {
3396                 gint             width, height;
3397                 gint             page_width, page_height;
3398                 cairo_surface_t *page_surface = NULL;
3399                 gint             selection_width, selection_height;
3400                 cairo_surface_t *selection_surface = NULL;
3401                 cairo_t         *cr = NULL;
3402
3403                 page_surface = ev_pixbuf_cache_get_surface (view->pixbuf_cache, page);
3404
3405                 if (!page_surface) {
3406                         draw_loading_text (view,
3407                                            &real_page_area,
3408                                            expose_area);
3409                         *page_ready = FALSE;
3410
3411                         return;
3412                 }
3413
3414                 ev_page_cache_get_size (view->page_cache,
3415                                         page, view->rotation,
3416                                         view->scale,
3417                                         &width, &height);
3418
3419                 cr = gdk_cairo_create (view->layout.bin_window);
3420                 
3421                 cairo_save (cr);
3422                 
3423                 page_width = cairo_image_surface_get_width (page_surface);
3424                 page_height = cairo_image_surface_get_height (page_surface);
3425                 
3426                 cairo_rectangle (cr, overlap.x, overlap.y, overlap.width, overlap.height);
3427                 cairo_clip (cr);
3428                 
3429                 cairo_translate (cr, overlap.x, overlap.y);
3430                 
3431                 if (width != page_width || height != page_height) {
3432                         cairo_pattern_set_filter (cairo_get_source (cr),
3433                                                   CAIRO_FILTER_FAST);
3434                         cairo_scale (cr,
3435                                      (gdouble)width / page_width,
3436                                      (gdouble)height / page_height);
3437                 }
3438
3439                 cairo_surface_set_device_offset (page_surface,
3440                                                  overlap.x - real_page_area.x,
3441                                                  overlap.y - real_page_area.y);
3442
3443                 cairo_set_source_surface (cr, page_surface, 0, 0);
3444                 cairo_paint (cr);
3445
3446                 cairo_restore (cr);
3447                 
3448                 /* Get the selection pixbuf iff we have something to draw */
3449                 if (find_selection_for_page (view, page) &&
3450                     view->selection_mode == EV_VIEW_SELECTION_TEXT) {
3451                         selection_surface =
3452                                 ev_pixbuf_cache_get_selection_surface (view->pixbuf_cache,
3453                                                                        page,
3454                                                                        view->scale,
3455                                                                        NULL);
3456                 }
3457
3458                 if (!selection_surface) {
3459                         cairo_destroy (cr);
3460                         return;
3461                 }
3462
3463                 selection_width = cairo_image_surface_get_width (selection_surface);
3464                 selection_height = cairo_image_surface_get_height (selection_surface);
3465
3466                 cairo_rectangle (cr, overlap.x, overlap.y, overlap.width, overlap.height);
3467                 cairo_clip (cr);
3468                 
3469                 cairo_translate (cr, overlap.x, overlap.y);
3470
3471                 if (width != selection_width || height != selection_height) {
3472                         cairo_pattern_set_filter (cairo_get_source (cr),
3473                                                   CAIRO_FILTER_FAST);
3474                         cairo_scale (cr,
3475                                      (gdouble)width / selection_width,
3476                                      (gdouble)height / selection_height);
3477                 }
3478
3479                 cairo_surface_set_device_offset (selection_surface,
3480                                                  overlap.x - real_page_area.x,
3481                                                  overlap.y - real_page_area.y);
3482
3483                 cairo_set_source_surface (cr, selection_surface, 0, 0);
3484                 cairo_paint (cr);
3485                 cairo_destroy (cr);
3486         }
3487 }
3488
3489 /*** GObject functions ***/
3490
3491 static void
3492 ev_view_finalize (GObject *object)
3493 {
3494         EvView *view = EV_VIEW (object);
3495
3496         g_free (view->status);
3497         g_free (view->find_status);
3498
3499         clear_selection (view);
3500
3501         if (view->image_dnd_info.image)
3502                 g_object_unref (view->image_dnd_info.image);
3503         view->image_dnd_info.image = NULL;
3504
3505         G_OBJECT_CLASS (ev_view_parent_class)->finalize (object);
3506 }
3507
3508 static void
3509 ev_view_destroy (GtkObject *object)
3510 {
3511         EvView *view = EV_VIEW (object);
3512
3513         if (view->document) {
3514                 g_object_unref (view->document);
3515                 view->document = NULL;
3516         }
3517
3518         if (view->pixbuf_cache) {
3519                 g_object_unref (view->pixbuf_cache);
3520                 view->pixbuf_cache = NULL;
3521         }
3522
3523         if (view->link_tooltip) {
3524                 gtk_widget_destroy (view->link_tooltip);
3525                 view->link_tooltip = NULL;
3526         }
3527
3528         if (view->goto_window) {
3529                 gtk_widget_destroy (view->goto_window);
3530                 view->goto_window = NULL;
3531                 view->goto_entry = NULL;
3532         }
3533
3534         if (view->selection_scroll_id) {
3535             g_source_remove (view->selection_scroll_id);
3536             view->selection_scroll_id = 0;
3537         }
3538
3539         if (view->selection_update_id) {
3540             g_source_remove (view->selection_update_id);
3541             view->selection_update_id = 0;
3542         }
3543
3544         if (view->loading_text) {
3545                 cairo_surface_destroy (view->loading_text);
3546                 view->loading_text = NULL;
3547         }
3548
3549         ev_view_presentation_transition_stop (view);
3550
3551         ev_view_set_scroll_adjustments (GTK_LAYOUT (view), NULL, NULL);
3552
3553         GTK_OBJECT_CLASS (ev_view_parent_class)->destroy (object);
3554 }
3555
3556 static void
3557 ev_view_set_property (GObject      *object,
3558                       guint         prop_id,
3559                       const GValue *value,
3560                       GParamSpec   *pspec)
3561 {
3562         EvView *view = EV_VIEW (object);
3563
3564         switch (prop_id) {
3565                 case PROP_CONTINUOUS:
3566                         ev_view_set_continuous (view, g_value_get_boolean (value));
3567                         break;
3568                 case PROP_DUAL_PAGE:
3569                         ev_view_set_dual_page (view, g_value_get_boolean (value));
3570                         break;
3571                 case PROP_FULLSCREEN:
3572                         ev_view_set_fullscreen (view, g_value_get_boolean (value));
3573                         break;
3574                 case PROP_PRESENTATION:
3575                         ev_view_set_presentation (view, g_value_get_boolean (value));
3576                         break;
3577                 case PROP_SIZING_MODE:
3578                         ev_view_set_sizing_mode (view, g_value_get_enum (value));
3579                         break;
3580                 case PROP_ZOOM:
3581                         ev_view_set_zoom (view, g_value_get_double (value), FALSE);
3582                         break;
3583                 case PROP_ROTATION:
3584                         ev_view_set_rotation (view, g_value_get_int (value));
3585                         break;
3586                 default:
3587                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3588         }
3589 }
3590
3591 static AtkObject *
3592 ev_view_get_accessible (GtkWidget *widget)
3593 {
3594         static gboolean first_time = TRUE;
3595
3596         if (first_time) {
3597                 AtkObjectFactory *factory;
3598                 AtkRegistry *registry;
3599                 GType derived_type; 
3600                 GType derived_atk_type; 
3601
3602                 /*
3603                  * Figure out whether accessibility is enabled by looking at the
3604                  * type of the accessible object which would be created for
3605                  * the parent type of EvView.
3606                  */
3607                 derived_type = g_type_parent (EV_TYPE_VIEW);
3608
3609                 registry = atk_get_default_registry ();
3610                 factory = atk_registry_get_factory (registry,
3611                                                     derived_type);
3612                 derived_atk_type = atk_object_factory_get_accessible_type (factory);
3613                 if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE)) 
3614                         atk_registry_set_factory_type (registry, 
3615                                                        EV_TYPE_VIEW,
3616                                                        ev_view_accessible_factory_get_type ());
3617                 first_time = FALSE;
3618         } 
3619         return GTK_WIDGET_CLASS (ev_view_parent_class)->get_accessible (widget);
3620 }
3621
3622 static void
3623 ev_view_get_property (GObject *object,
3624                       guint prop_id,
3625                       GValue *value,
3626                       GParamSpec *pspec)
3627 {
3628         EvView *view = EV_VIEW (object);
3629
3630         switch (prop_id) {
3631                 case PROP_STATUS:
3632                         g_value_set_string (value, view->status);
3633                         break;
3634                 case PROP_FIND_STATUS:
3635                         g_value_set_string (value, view->status);
3636                         break;
3637                 case PROP_CONTINUOUS:
3638                         g_value_set_boolean (value, view->continuous);
3639                         break;
3640                 case PROP_DUAL_PAGE:
3641                         g_value_set_boolean (value, view->dual_page);
3642                         break;
3643                 case PROP_FULLSCREEN:
3644                         g_value_set_boolean (value, view->fullscreen);
3645                         break;
3646                 case PROP_PRESENTATION:
3647                         g_value_set_boolean (value, view->presentation);
3648                         break;
3649                 case PROP_SIZING_MODE:
3650                         g_value_set_enum (value, view->sizing_mode);
3651                         break;
3652                 case PROP_ZOOM:
3653                         g_value_set_double (value, view->scale);
3654                         break;
3655                 case PROP_ROTATION:
3656                         g_value_set_int (value, view->rotation);
3657                         break;
3658                 case PROP_HAS_SELECTION:
3659                         g_value_set_boolean (value,
3660                                              view->selection_info.selections != NULL);
3661                         break;
3662                 default:
3663                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3664         }
3665 }
3666
3667 static void
3668 ev_view_class_init (EvViewClass *class)
3669 {
3670         GObjectClass *object_class = G_OBJECT_CLASS (class);
3671         GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (class);
3672         GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
3673         GtkLayoutClass *layout_class = GTK_LAYOUT_CLASS (class);
3674         GtkBindingSet *binding_set;
3675
3676         object_class->finalize = ev_view_finalize;
3677         object_class->set_property = ev_view_set_property;
3678         object_class->get_property = ev_view_get_property;
3679
3680         widget_class->expose_event = ev_view_expose_event;
3681         widget_class->button_press_event = ev_view_button_press_event;
3682         widget_class->motion_notify_event = ev_view_motion_notify_event;
3683         widget_class->button_release_event = ev_view_button_release_event;
3684         widget_class->key_press_event = ev_view_key_press_event;
3685         widget_class->focus_in_event = ev_view_focus_in;
3686         widget_class->focus_out_event = ev_view_focus_out;
3687         widget_class->get_accessible = ev_view_get_accessible;
3688         widget_class->size_request = ev_view_size_request;
3689         widget_class->size_allocate = ev_view_size_allocate;
3690         widget_class->realize = ev_view_realize;
3691         widget_class->scroll_event = ev_view_scroll_event;
3692         widget_class->enter_notify_event = ev_view_enter_notify_event;
3693         widget_class->leave_notify_event = ev_view_leave_notify_event;
3694         widget_class->style_set = ev_view_style_set;
3695         widget_class->drag_data_get = ev_view_drag_data_get;
3696         widget_class->drag_motion = ev_view_drag_motion;
3697         widget_class->drag_data_received = ev_view_drag_data_received;
3698         widget_class->popup_menu = ev_view_popup_menu;
3699
3700         gtk_object_class->destroy = ev_view_destroy;
3701
3702         layout_class->set_scroll_adjustments = ev_view_set_scroll_adjustments;
3703         
3704         class->binding_activated = ev_view_scroll;
3705
3706         signals[SIGNAL_BINDING_ACTIVATED] = g_signal_new ("binding_activated",
3707                          G_TYPE_FROM_CLASS (object_class),
3708                          G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
3709                          G_STRUCT_OFFSET (EvViewClass, binding_activated),
3710                          NULL, NULL,
3711                          ev_marshal_VOID__ENUM_BOOLEAN,
3712                          G_TYPE_NONE, 2,
3713                          GTK_TYPE_SCROLL_TYPE,
3714                          G_TYPE_BOOLEAN);
3715
3716         signals[SIGNAL_ZOOM_INVALID] = g_signal_new ("zoom-invalid",
3717                          G_TYPE_FROM_CLASS (object_class),
3718                          G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
3719                          G_STRUCT_OFFSET (EvViewClass, zoom_invalid),
3720                          NULL, NULL,
3721                          ev_marshal_VOID__VOID,
3722                          G_TYPE_NONE, 0, G_TYPE_NONE);
3723         signals[SIGNAL_HANDLE_LINK] = g_signal_new ("handle-link",
3724                          G_TYPE_FROM_CLASS (object_class),
3725                          G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
3726                          G_STRUCT_OFFSET (EvViewClass, handle_link),
3727                          NULL, NULL,
3728                          g_cclosure_marshal_VOID__OBJECT,
3729                          G_TYPE_NONE, 1,
3730                          G_TYPE_OBJECT);
3731         signals[SIGNAL_EXTERNAL_LINK] = g_signal_new ("external-link",
3732                          G_TYPE_FROM_CLASS (object_class),
3733                          G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
3734                          G_STRUCT_OFFSET (EvViewClass, external_link),
3735                          NULL, NULL,
3736                          g_cclosure_marshal_VOID__OBJECT,
3737                          G_TYPE_NONE, 1,
3738                          G_TYPE_OBJECT);
3739         signals[SIGNAL_POPUP_MENU] = g_signal_new ("popup",
3740                          G_TYPE_FROM_CLASS (object_class),
3741                          G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
3742                          G_STRUCT_OFFSET (EvViewClass, popup_menu),
3743                          NULL, NULL,
3744                          g_cclosure_marshal_VOID__OBJECT,
3745                          G_TYPE_NONE, 1,
3746                          G_TYPE_OBJECT);
3747
3748         g_object_class_install_property (object_class,
3749                                          PROP_STATUS,
3750                                          g_param_spec_string ("status",
3751                                                               "Status Message",
3752                                                               "The status message",
3753                                                               NULL,
3754                                                               G_PARAM_READABLE));
3755
3756         g_object_class_install_property (object_class,
3757                                          PROP_FIND_STATUS,
3758                                          g_param_spec_string ("find-status",
3759                                                               "Find Status Message",
3760                                                               "The find status message",
3761                                                               NULL,
3762                                                               G_PARAM_READABLE));
3763
3764         g_object_class_install_property (object_class,
3765                                          PROP_CONTINUOUS,
3766                                          g_param_spec_boolean ("continuous",
3767                                                                "Continuous",
3768                                                                "Continuous scrolling mode",
3769                                                                TRUE,
3770                                                                G_PARAM_READWRITE));
3771
3772         g_object_class_install_property (object_class,
3773                                          PROP_DUAL_PAGE,
3774                                          g_param_spec_boolean ("dual-page",
3775                                                                "Dual Page",
3776                                                                "Two pages visible at once",
3777                                                                FALSE,
3778                                                                G_PARAM_READWRITE));
3779         g_object_class_install_property (object_class,
3780                                          PROP_FULLSCREEN,
3781                                          g_param_spec_boolean ("fullscreen",
3782                                                                "Full Screen",
3783                                                                "Draw page in a fullscreen fashion",
3784                                                                FALSE,
3785                                                                G_PARAM_READWRITE));
3786         g_object_class_install_property (object_class,
3787                                          PROP_PRESENTATION,
3788                                          g_param_spec_boolean ("presentation",
3789                                                                "Presentation",
3790                                                                "Draw page in presentation mode",
3791                                                                TRUE,
3792                                                                G_PARAM_READWRITE));
3793
3794         g_object_class_install_property (object_class,
3795                                          PROP_SIZING_MODE,
3796                                          g_param_spec_enum ("sizing-mode",
3797                                                             "Sizing Mode",
3798                                                             "Sizing Mode",
3799                                                             EV_TYPE_SIZING_MODE,
3800                                                             EV_SIZING_FIT_WIDTH,
3801                                                             G_PARAM_READWRITE));
3802
3803         g_object_class_install_property (object_class,
3804                                          PROP_ZOOM,
3805                                          g_param_spec_double ("zoom",
3806                                                               "Zoom factor",
3807                                                               "Zoom factor",
3808                                                               0,
3809                                                               G_MAXDOUBLE,
3810                                                               1.0,
3811                                                               G_PARAM_READWRITE));
3812         g_object_class_install_property (object_class,
3813                                          PROP_ROTATION,
3814                                          g_param_spec_double ("rotation",
3815                                                               "Rotation",
3816                                                               "Rotation",
3817                                                               0,
3818                                                               360,
3819                                                               0,
3820                                                               G_PARAM_READWRITE));
3821         g_object_class_install_property (object_class,
3822                                          PROP_HAS_SELECTION,
3823                                          g_param_spec_boolean ("has-selection",
3824                                                                "Has selection",
3825                                                                "The view has selections",
3826                                                                FALSE,
3827                                                                G_PARAM_READABLE));
3828
3829         binding_set = gtk_binding_set_by_class (class);
3830
3831         add_scroll_binding_keypad (binding_set, GDK_Left,  0, EV_SCROLL_STEP_BACKWARD, TRUE);
3832         add_scroll_binding_keypad (binding_set, GDK_Right, 0, EV_SCROLL_STEP_FORWARD,  TRUE);
3833         add_scroll_binding_keypad (binding_set, GDK_Left,  GDK_MOD1_MASK, EV_SCROLL_STEP_DOWN, TRUE);
3834         add_scroll_binding_keypad (binding_set, GDK_Right, GDK_MOD1_MASK, EV_SCROLL_STEP_UP,  TRUE);
3835         add_scroll_binding_keypad (binding_set, GDK_Up,    0, EV_SCROLL_STEP_BACKWARD, FALSE);
3836         add_scroll_binding_keypad (binding_set, GDK_Down,  0, EV_SCROLL_STEP_FORWARD,  FALSE);
3837         add_scroll_binding_keypad (binding_set, GDK_Up,    GDK_MOD1_MASK, EV_SCROLL_STEP_DOWN, FALSE);
3838         add_scroll_binding_keypad (binding_set, GDK_Down,  GDK_MOD1_MASK, EV_SCROLL_STEP_UP,  FALSE);
3839 }
3840
3841 static void
3842 ev_view_init (EvView *view)
3843 {
3844         GTK_WIDGET_SET_FLAGS (view, GTK_CAN_FOCUS);
3845
3846         view->spacing = 5;
3847         view->scale = 1.0;
3848         view->current_page = 0;
3849         view->pressed_button = -1;
3850         view->cursor = EV_VIEW_CURSOR_NORMAL;
3851         view->drag_info.in_drag = FALSE;
3852         view->selection_info.selections = NULL;
3853         view->selection_info.in_selection = FALSE;
3854         view->selection_info.in_drag = FALSE;
3855         view->selection_mode = EV_VIEW_SELECTION_TEXT;
3856         view->continuous = TRUE;
3857         view->dual_page = FALSE;
3858         view->presentation = FALSE;
3859         view->presentation_state = EV_PRESENTATION_NORMAL;
3860         view->fullscreen = FALSE;
3861         view->sizing_mode = EV_SIZING_FIT_WIDTH;
3862         view->pending_scroll = SCROLL_TO_KEEP_POSITION;
3863         view->jump_to_find_result = TRUE;
3864
3865         gtk_layout_set_hadjustment (GTK_LAYOUT (view), NULL);
3866         gtk_layout_set_vadjustment (GTK_LAYOUT (view), NULL);
3867
3868         gtk_drag_dest_set (GTK_WIDGET (view),
3869                            GTK_DEST_DEFAULT_ALL,
3870                            view_drop_targets,
3871                            G_N_ELEMENTS (view_drop_targets),
3872                            GDK_ACTION_COPY);
3873 }
3874
3875 /*** Callbacks ***/
3876
3877 static void
3878 find_changed_cb (EvDocument *document, int page, EvView *view)
3879 {
3880         double percent;
3881         int n_pages;
3882
3883         percent = ev_document_find_get_progress
3884                         (EV_DOCUMENT_FIND (view->document)); 
3885         n_pages = ev_page_cache_get_n_pages (view->page_cache);
3886         
3887         if (view->jump_to_find_result == TRUE) {
3888                 jump_to_find_page (view, EV_VIEW_FIND_NEXT, 0);
3889                 jump_to_find_result (view);
3890         }
3891         update_find_status_message (view, percent * n_pages >= n_pages - 1 );
3892         if (view->current_page == page)
3893                 gtk_widget_queue_draw (GTK_WIDGET (view));
3894 }
3895
3896 static void
3897 job_finished_cb (EvPixbufCache *pixbuf_cache,
3898                  EvView        *view)
3899 {
3900         gtk_widget_queue_draw (GTK_WIDGET (view));
3901 }
3902
3903 static void
3904 page_changed_cb (EvPageCache *page_cache,
3905                  int          new_page,
3906                  EvView      *view)
3907 {
3908         if (view->current_page != new_page) {
3909                 gint x, y;
3910                 
3911                 view->current_page = new_page;
3912                 view->pending_scroll = SCROLL_TO_PAGE_POSITION;
3913
3914                 if (view->presentation)
3915                         ev_view_presentation_transition_start (view);
3916                 
3917                 gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
3918                 ev_view_handle_cursor_over_xy (view, x, y);
3919                 
3920                 gtk_widget_queue_resize (GTK_WIDGET (view));
3921         } else {
3922                 gtk_widget_queue_draw (GTK_WIDGET (view));
3923         }
3924
3925         if (EV_IS_DOCUMENT_FIND (view->document)) {
3926                 view->find_result = 0;
3927                 update_find_status_message (view, TRUE);
3928         }
3929 }
3930
3931 static void
3932 on_adjustment_value_changed (GtkAdjustment *adjustment,
3933                              EvView        *view)
3934 {
3935         int dx = 0, dy = 0;
3936         gint x, y;
3937         GList *children, *l;
3938
3939         if (! GTK_WIDGET_REALIZED (view))
3940                 return;
3941
3942         if (view->hadjustment) {
3943                 dx = view->scroll_x - (int) view->hadjustment->value;
3944                 view->scroll_x = (int) view->hadjustment->value;
3945         } else {
3946                 view->scroll_x = 0;
3947         }
3948
3949         if (view->vadjustment) {
3950                 dy = view->scroll_y - (int) view->vadjustment->value;
3951                 view->scroll_y = (int) view->vadjustment->value;
3952         } else {
3953                 view->scroll_y = 0;
3954         }
3955
3956         children = gtk_container_get_children (GTK_CONTAINER (view));
3957         for (l = children; l && l->data; l = g_list_next (l)) {
3958                 gint       child_x, child_y;
3959                 GtkWidget *child = (GtkWidget *)l->data;
3960                 
3961                 gtk_container_child_get (GTK_CONTAINER (view),
3962                                          child,
3963                                          "x", &child_x,
3964                                          "y", &child_y,
3965                                          NULL);
3966                 gtk_layout_move (GTK_LAYOUT (view), child, child_x + dx, child_y + dy);
3967         }
3968         g_list_free (children);
3969         
3970         if (view->pending_resize)
3971                 gtk_widget_queue_draw (GTK_WIDGET (view));
3972         else
3973                 gdk_window_scroll (view->layout.bin_window, dx, dy);
3974                 
3975         gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
3976         ev_view_handle_cursor_over_xy (view, x, y);
3977
3978         if (view->document)
3979                 view_update_range_and_current_page (view);
3980 }
3981
3982 GtkWidget*
3983 ev_view_new (void)
3984 {
3985         GtkWidget *view;
3986
3987         view = g_object_new (EV_TYPE_VIEW, NULL);
3988
3989         return view;
3990 }
3991
3992 static void
3993 setup_caches (EvView *view)
3994 {
3995         view->page_cache = ev_page_cache_get (view->document);
3996         g_signal_connect (view->page_cache, "page-changed", G_CALLBACK (page_changed_cb), view);
3997         view->pixbuf_cache = ev_pixbuf_cache_new (GTK_WIDGET (view), view->document);
3998         g_signal_connect (view->pixbuf_cache, "job-finished", G_CALLBACK (job_finished_cb), view);
3999         page_changed_cb (view->page_cache,
4000                          ev_page_cache_get_current_page (view->page_cache),
4001                          view);
4002 }
4003
4004 static void
4005 clear_caches (EvView *view)
4006 {
4007         if (view->pixbuf_cache) {
4008                 g_object_unref (view->pixbuf_cache);
4009                 view->pixbuf_cache = NULL;
4010         }
4011
4012         if (view->page_cache) {
4013                 view->page_cache = NULL;
4014         }
4015 }
4016
4017 void
4018 ev_view_set_loading (EvView       *view,
4019                      gboolean      loading)
4020 {
4021         view->loading = loading;
4022         gtk_widget_queue_draw (GTK_WIDGET (view));
4023 }
4024
4025 void
4026 ev_view_set_document (EvView     *view,
4027                       EvDocument *document)
4028 {
4029         g_return_if_fail (EV_IS_VIEW (view));
4030
4031         view->loading = FALSE;
4032         
4033         if (document != view->document) {
4034                 clear_caches (view);
4035
4036                 if (view->document) {
4037                         g_signal_handlers_disconnect_by_func (view->document,
4038                                                               find_changed_cb,
4039                                                               view);
4040                         g_object_unref (view->document);
4041                         view->page_cache = NULL;
4042
4043                 }
4044
4045                 view->document = document;
4046                 view->find_result = 0;
4047
4048                 if (view->document) {
4049                         g_object_ref (view->document);
4050                         if (EV_IS_DOCUMENT_FIND (view->document)) {
4051                                 g_signal_connect (view->document,
4052                                                   "find_changed",
4053                                                   G_CALLBACK (find_changed_cb),
4054                                                   view);
4055                         }
4056
4057                         setup_caches (view);
4058                 }
4059
4060                 gtk_widget_queue_resize (GTK_WIDGET (view));
4061         }
4062 }
4063
4064 /*** Zoom and sizing mode ***/
4065
4066 #define EPSILON 0.0000001
4067 void
4068 ev_view_set_zoom (EvView   *view,
4069                   double    factor,
4070                   gboolean  relative)
4071 {
4072         double scale;
4073
4074         if (relative)
4075                 scale = view->scale * factor;
4076         else
4077                 scale = factor;
4078
4079         scale = CLAMP (scale, view->min_scale, view->max_scale);
4080
4081         if (ABS (view->scale - scale) < EPSILON)
4082                 return;
4083
4084         if (view->loading_text) {
4085                 cairo_surface_destroy (view->loading_text);
4086                 view->loading_text = NULL;
4087         }
4088
4089         view->scale = scale;
4090         view->pending_resize = TRUE;
4091
4092         gtk_widget_queue_resize (GTK_WIDGET (view));
4093
4094         g_object_notify (G_OBJECT (view), "zoom");
4095 }
4096
4097 double
4098 ev_view_get_zoom (EvView *view)
4099 {
4100         return view->scale;
4101 }
4102
4103 void
4104 ev_view_set_screen_dpi (EvView  *view,
4105                         gdouble  dpi)
4106 {
4107         g_return_if_fail (EV_IS_VIEW (view));
4108         g_return_if_fail (dpi > 0);
4109
4110         view->dpi = dpi;
4111         view->min_scale = MIN_SCALE * dpi / 72.0;
4112         view->max_scale = MAX_SCALE * dpi / 72.0;
4113 }
4114
4115 gboolean
4116 ev_view_get_continuous (EvView *view)
4117 {
4118         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
4119
4120         return view->continuous;
4121 }
4122
4123 void
4124 ev_view_set_continuous (EvView   *view,
4125                         gboolean  continuous)
4126 {
4127         g_return_if_fail (EV_IS_VIEW (view));
4128
4129         continuous = continuous != FALSE;
4130
4131         if (view->continuous != continuous) {
4132                 view->continuous = continuous;
4133                 view->pending_scroll = SCROLL_TO_PAGE_POSITION;
4134                 gtk_widget_queue_resize (GTK_WIDGET (view));
4135         }
4136
4137         g_object_notify (G_OBJECT (view), "continuous");
4138 }
4139
4140 gboolean
4141 ev_view_get_dual_page (EvView *view)
4142 {
4143         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
4144
4145         return view->dual_page;
4146 }
4147
4148 void
4149 ev_view_set_dual_page (EvView   *view,
4150                        gboolean  dual_page)
4151 {
4152         g_return_if_fail (EV_IS_VIEW (view));
4153
4154         dual_page = dual_page != FALSE;
4155
4156         if (view->dual_page == dual_page)
4157                 return;
4158
4159         view->pending_scroll = SCROLL_TO_PAGE_POSITION;
4160         view->dual_page = dual_page;
4161         /* FIXME: if we're keeping the pixbuf cache around, we should extend the
4162          * preload_cache_size to be 2 if dual_page is set.
4163          */
4164         gtk_widget_queue_resize (GTK_WIDGET (view));
4165
4166         g_object_notify (G_OBJECT (view), "dual-page");
4167 }
4168
4169 void
4170 ev_view_set_fullscreen (EvView   *view,
4171                          gboolean  fullscreen)
4172 {
4173         g_return_if_fail (EV_IS_VIEW (view));
4174
4175         fullscreen = fullscreen != FALSE;
4176
4177         if (view->fullscreen == fullscreen) 
4178                 return;
4179                 
4180         view->fullscreen = fullscreen;
4181         gtk_widget_queue_resize (GTK_WIDGET (view));
4182         
4183         g_object_notify (G_OBJECT (view), "fullscreen");
4184 }
4185
4186 gboolean
4187 ev_view_get_fullscreen (EvView *view)
4188 {
4189         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
4190
4191         return view->fullscreen;
4192 }
4193
4194 void
4195 ev_view_set_presentation (EvView   *view,
4196                           gboolean  presentation)
4197 {
4198         g_return_if_fail (EV_IS_VIEW (view));
4199
4200         presentation = presentation != FALSE;
4201
4202         if (view->presentation == presentation)
4203                 return;
4204
4205         if (!presentation)
4206                 view->presentation_state = EV_PRESENTATION_NORMAL;
4207         
4208         view->presentation = presentation;
4209         view->pending_scroll = SCROLL_TO_PAGE_POSITION;
4210         
4211         if (presentation) {
4212                 view->sizing_mode_saved = view->sizing_mode;
4213                 view->scale_saved = view->scale;
4214                 ev_view_set_sizing_mode (view, EV_SIZING_BEST_FIT);
4215         } else {
4216                 ev_view_set_sizing_mode (view, view->sizing_mode_saved);
4217                 ev_view_set_zoom (view, view->scale_saved, FALSE);
4218         }
4219         
4220         gtk_widget_queue_resize (GTK_WIDGET (view));
4221
4222         if (presentation)
4223                 ev_view_presentation_transition_start (view);
4224         else
4225                 ev_view_presentation_transition_stop (view);
4226
4227         if (GTK_WIDGET_REALIZED (view)) {
4228                 if (view->presentation)
4229                         gdk_window_set_background (view->layout.bin_window,
4230                                                    &GTK_WIDGET (view)->style->black);
4231                 else
4232                         gdk_window_set_background (view->layout.bin_window,
4233                                                    &GTK_WIDGET (view)->style->mid [GTK_STATE_NORMAL]);
4234         }
4235
4236         g_object_notify (G_OBJECT (view), "presentation");
4237 }
4238
4239 gboolean
4240 ev_view_get_presentation (EvView *view)
4241 {
4242         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
4243
4244         return view->presentation;
4245 }
4246
4247 static gboolean
4248 transition_next_page (EvView *view)
4249 {
4250         ev_view_next_page (view);
4251
4252         return FALSE;
4253 }
4254
4255 static void
4256 ev_view_presentation_transition_stop (EvView *view)
4257 {
4258         if (view->trans_timeout_id > 0)
4259                 g_source_remove (view->trans_timeout_id);
4260         view->trans_timeout_id = 0;
4261 }
4262
4263 static void
4264 ev_view_presentation_transition_start (EvView *view)
4265 {
4266         gdouble duration;
4267         
4268         if (!EV_IS_DOCUMENT_TRANSITION (view->document))
4269                 return;
4270
4271         ev_view_presentation_transition_stop (view);
4272
4273         duration = ev_document_transition_get_page_duration (EV_DOCUMENT_TRANSITION (view->document),
4274                                                              view->current_page);
4275         if (duration > 0)
4276                 view->trans_timeout_id = g_timeout_add (duration * 1000,
4277                                                         (GSourceFunc) transition_next_page,
4278                                                         view);
4279 }
4280
4281 void
4282 ev_view_set_sizing_mode (EvView       *view,
4283                          EvSizingMode  sizing_mode)
4284 {
4285         g_return_if_fail (EV_IS_VIEW (view));
4286
4287         if (view->sizing_mode == sizing_mode)
4288                 return;
4289
4290         view->sizing_mode = sizing_mode;
4291         gtk_widget_queue_resize (GTK_WIDGET (view));
4292
4293         g_object_notify (G_OBJECT (view), "sizing-mode");
4294 }
4295
4296 EvSizingMode
4297 ev_view_get_sizing_mode (EvView *view)
4298 {
4299         g_return_val_if_fail (EV_IS_VIEW (view), EV_SIZING_FREE);
4300
4301         return view->sizing_mode;
4302 }
4303
4304 gboolean
4305 ev_view_can_zoom_in (EvView *view)
4306 {
4307         return view->scale * ZOOM_IN_FACTOR <= view->max_scale;
4308 }
4309
4310 gboolean
4311 ev_view_can_zoom_out (EvView *view)
4312 {
4313         return view->scale * ZOOM_OUT_FACTOR >= view->min_scale;
4314 }
4315
4316 void
4317 ev_view_zoom_in (EvView *view)
4318 {
4319         g_return_if_fail (view->sizing_mode == EV_SIZING_FREE);
4320
4321         if (view->presentation)
4322                 return;
4323         
4324         view->pending_scroll = SCROLL_TO_CENTER;
4325         ev_view_set_zoom (view, ZOOM_IN_FACTOR, TRUE);
4326 }
4327
4328 void
4329 ev_view_zoom_out (EvView *view)
4330 {
4331         g_return_if_fail (view->sizing_mode == EV_SIZING_FREE);
4332
4333         if (view->presentation)
4334                 return;
4335         
4336         view->pending_scroll = SCROLL_TO_CENTER;
4337         ev_view_set_zoom (view, ZOOM_OUT_FACTOR, TRUE);
4338 }
4339
4340 void
4341 ev_view_rotate_right (EvView *view)
4342 {
4343         int rotation = view->rotation + 90;
4344
4345         if (rotation >= 360) {
4346                 rotation -= 360;
4347         }
4348
4349         ev_view_set_rotation (view, rotation);
4350 }
4351
4352 void
4353 ev_view_rotate_left (EvView *view)
4354 {
4355         int rotation = view->rotation - 90;
4356
4357         if (rotation < 0) {
4358                 rotation += 360;
4359         }
4360
4361         ev_view_set_rotation (view, rotation);
4362 }
4363
4364 void
4365 ev_view_set_rotation (EvView *view, int rotation)
4366 {
4367         view->rotation = rotation;
4368
4369         if (view->pixbuf_cache) {
4370                 ev_pixbuf_cache_clear (view->pixbuf_cache);
4371                 gtk_widget_queue_resize (GTK_WIDGET (view));
4372         }
4373
4374         if (rotation != 0)
4375                 clear_selection (view);
4376
4377         g_object_notify (G_OBJECT (view), "rotation");
4378 }
4379
4380 int
4381 ev_view_get_rotation (EvView *view)
4382 {
4383         return view->rotation;
4384 }
4385
4386 static double
4387 zoom_for_size_fit_width (int doc_width,
4388                          int doc_height,
4389                          int target_width,
4390                          int target_height,
4391                          int vsb_width)
4392 {
4393         double scale;
4394
4395         scale = (double)target_width / doc_width;
4396
4397         if (doc_height * scale > target_height)
4398                 scale = (double) (target_width - vsb_width) / doc_width;
4399
4400         return scale;
4401 }
4402
4403 static double
4404 zoom_for_size_fit_height (int doc_width,
4405                           int doc_height,
4406                           int target_width,
4407                           int target_height,
4408                           int vsb_height)
4409 {
4410         double scale;
4411
4412         scale = (double)target_height / doc_height;
4413
4414         if (doc_width * scale > target_width)
4415                 scale = (double) (target_height - vsb_height) / doc_height;
4416
4417         return scale;
4418 }
4419
4420 static double
4421 zoom_for_size_best_fit (int doc_width,
4422                         int doc_height,
4423                         int target_width,
4424                         int target_height,
4425                         int vsb_width,
4426                         int hsb_width)
4427 {
4428         double w_scale;
4429         double h_scale;
4430
4431         w_scale = (double)target_width / doc_width;
4432         h_scale = (double)target_height / doc_height;
4433
4434         if (doc_height * w_scale > target_height)
4435                 w_scale = (double) (target_width - vsb_width) / doc_width;
4436         if (doc_width * h_scale > target_width)
4437                 h_scale = (double) (target_height - hsb_width) / doc_height;
4438
4439         return MIN (w_scale, h_scale);
4440 }
4441
4442
4443 static void
4444 ev_view_zoom_for_size_presentation (EvView *view,
4445                                     int     width,
4446                                     int     height)
4447 {
4448         int doc_width, doc_height;
4449         gdouble scale;
4450
4451         ev_page_cache_get_size (view->page_cache,
4452                                 view->current_page,
4453                                 view->rotation,
4454                                 1.0,
4455                                 &doc_width,
4456                                 &doc_height);
4457         scale = zoom_for_size_best_fit (doc_width, doc_height, width, height, 0, 0);
4458         ev_view_set_zoom (view, scale, FALSE);
4459 }
4460
4461 static void
4462 ev_view_zoom_for_size_continuous_and_dual_page (EvView *view,
4463                            int     width,
4464                            int     height,
4465                            int     vsb_width,
4466                            int     hsb_height)
4467 {
4468         int doc_width, doc_height;
4469         GtkBorder border;
4470         gdouble scale;
4471
4472         ev_page_cache_get_max_width (view->page_cache,
4473                                      view->rotation,
4474                                      1.0,
4475                                      &doc_width);
4476         ev_page_cache_get_max_height (view->page_cache,
4477                                       view->rotation,
4478                                       1.0,
4479                                       &doc_height);
4480         compute_border (view, doc_width, doc_height, &border);
4481
4482         doc_width = doc_width * 2;
4483         width -= (2 * (border.left + border.right) + 3 * view->spacing);
4484         height -= (border.top + border.bottom + 2 * view->spacing - 1);
4485
4486         /* FIXME: We really need to calculate the overall height here, not the
4487          * page height.  We assume there's always a vertical scrollbar for
4488          * now.  We need to fix this. */
4489         if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
4490                 scale = zoom_for_size_fit_width (doc_width, doc_height, width - vsb_width, height, 0);
4491         else if (view->sizing_mode == EV_SIZING_BEST_FIT)
4492                 scale = zoom_for_size_best_fit (doc_width, doc_height, width - vsb_width, height, 0, hsb_height);
4493         else
4494                 g_assert_not_reached ();
4495
4496         ev_view_set_zoom (view, scale, FALSE);
4497 }
4498
4499 static void
4500 ev_view_zoom_for_size_continuous (EvView *view,
4501                                   int     width,
4502                                   int     height,
4503                                   int     vsb_width,
4504                                   int     hsb_height)
4505 {
4506         int doc_width, doc_height;
4507         GtkBorder border;
4508         gdouble scale;
4509
4510         ev_page_cache_get_max_width (view->page_cache,
4511                                      view->rotation,
4512                                      1.0,
4513                                      &doc_width);
4514         ev_page_cache_get_max_height (view->page_cache,
4515                                       view->rotation,
4516                                       1.0,
4517                                       &doc_height);
4518         compute_border (view, doc_width, doc_height, &border);
4519
4520         width -= (border.left + border.right + 2 * view->spacing);
4521         height -= (border.top + border.bottom + 2 * view->spacing - 1);
4522
4523         /* FIXME: We really need to calculate the overall height here, not the
4524          * page height.  We assume there's always a vertical scrollbar for
4525          * now.  We need to fix this. */
4526         if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
4527                 scale = zoom_for_size_fit_width (doc_width, doc_height, width - vsb_width, height, 0);
4528         else if (view->sizing_mode == EV_SIZING_BEST_FIT)
4529                 scale = zoom_for_size_best_fit (doc_width, doc_height, width - vsb_width, height, 0, hsb_height);
4530         else
4531                 g_assert_not_reached ();
4532
4533         ev_view_set_zoom (view, scale, FALSE);
4534 }
4535
4536 static void
4537 ev_view_zoom_for_size_dual_page (EvView *view,
4538                                  int     width,
4539                                  int     height,
4540                                  int     vsb_width,
4541                                  int     hsb_height)
4542 {
4543         GtkBorder border;
4544         gint doc_width, doc_height;
4545         gdouble scale;
4546         gint other_page;
4547
4548         other_page = view->current_page ^ 1;
4549
4550         /* Find the largest of the two. */
4551         ev_page_cache_get_size (view->page_cache,
4552                                 view->current_page,
4553                                 view->rotation,
4554                                 1.0,
4555                                 &doc_width, &doc_height);
4556
4557         if (other_page < ev_page_cache_get_n_pages (view->page_cache)) {
4558                 gint width_2, height_2;
4559                 ev_page_cache_get_size (view->page_cache,
4560                                         other_page,
4561                                         view->rotation,
4562                                         1.0,
4563                                         &width_2, &height_2);
4564                 if (width_2 > doc_width)
4565                         doc_width = width_2;
4566                 if (height_2 > doc_height)
4567                         doc_height = height_2;
4568         }
4569         compute_border (view, doc_width, doc_height, &border);
4570
4571         doc_width = doc_width * 2;
4572         width -= ((border.left + border.right)* 2 + 3 * view->spacing);
4573         height -= (border.top + border.bottom + 2 * view->spacing);
4574
4575         if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
4576                 scale = zoom_for_size_fit_width (doc_width, doc_height, width, height, vsb_width);
4577         else if (view->sizing_mode == EV_SIZING_BEST_FIT)
4578                 scale = zoom_for_size_best_fit (doc_width, doc_height, width, height, vsb_width, hsb_height);
4579         else
4580                 g_assert_not_reached ();
4581
4582         ev_view_set_zoom (view, scale, FALSE);
4583 }
4584
4585 static void
4586 ev_view_zoom_for_size_single_page (EvView *view,
4587                                    int     width,
4588                                    int     height,
4589                                    int     vsb_width,
4590                                    int     hsb_height)
4591 {
4592         int doc_width, doc_height;
4593         GtkBorder border;
4594         gdouble scale;
4595
4596         ev_page_cache_get_size (view->page_cache,
4597                                 view->current_page,
4598                                 view->rotation,
4599                                 1.0,
4600                                 &doc_width,
4601                                 &doc_height);
4602         /* Get an approximate border */
4603         compute_border (view, width, height, &border);
4604
4605         width -= (border.left + border.right + 2 * view->spacing);
4606         height -= (border.top + border.bottom + 2 * view->spacing);
4607
4608         if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
4609                 scale = zoom_for_size_fit_width (doc_width, doc_height, width, height, vsb_width);
4610         else if (view->sizing_mode == EV_SIZING_BEST_FIT)
4611                 scale = zoom_for_size_best_fit (doc_width, doc_height, width, height, vsb_width, hsb_height);
4612         else
4613                 g_assert_not_reached ();
4614
4615         ev_view_set_zoom (view, scale, FALSE);
4616 }
4617
4618 void
4619 ev_view_set_zoom_for_size (EvView *view,
4620                            int     width,
4621                            int     height,
4622                            int     vsb_width,
4623                            int     hsb_height)
4624 {
4625         g_return_if_fail (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
4626                           view->sizing_mode == EV_SIZING_BEST_FIT);
4627         g_return_if_fail (width >= 0);
4628         g_return_if_fail (height >= 0);
4629
4630         if (view->document == NULL)
4631                 return;
4632
4633         if (view->presentation)
4634                 ev_view_zoom_for_size_presentation (view, width, height);
4635         else if (view->continuous && view->dual_page)
4636                 ev_view_zoom_for_size_continuous_and_dual_page (view, width, height, vsb_width, hsb_height);
4637         else if (view->continuous)
4638                 ev_view_zoom_for_size_continuous (view, width, height, vsb_width, hsb_height);
4639         else if (view->dual_page)
4640                 ev_view_zoom_for_size_dual_page (view, width, height, vsb_width, hsb_height);
4641         else
4642                 ev_view_zoom_for_size_single_page (view, width, height, vsb_width, hsb_height);
4643 }
4644
4645 /*** Status text messages ***/
4646
4647 const char *
4648 ev_view_get_status (EvView *view)
4649 {
4650         g_return_val_if_fail (EV_IS_VIEW (view), NULL);
4651
4652         return view->status;
4653 }
4654
4655 static void
4656 ev_view_set_status (EvView *view, const char *message)
4657 {
4658         g_return_if_fail (EV_IS_VIEW (view));
4659
4660         if (message != view->status) {
4661                 g_free (view->status);
4662                 view->status = g_strdup (message);
4663                 g_object_notify (G_OBJECT (view), "status");
4664         }
4665 }
4666
4667 static void
4668 update_find_status_message (EvView *view, gboolean this_page)
4669 {
4670         char *message;
4671
4672         if (this_page) {
4673                 int results;
4674
4675                 results = ev_document_find_get_n_results
4676                                 (EV_DOCUMENT_FIND (view->document),
4677                                  view->current_page);
4678                 /* TRANS: Sometimes this could be better translated as
4679                    "%d hit(s) on this page".  Therefore this string
4680                    contains plural cases. */
4681                 message = g_strdup_printf (ngettext ("%d found on this page",
4682                                                      "%d found on this page",
4683                                                      results),
4684                                            results);
4685         } else {
4686                 double percent;
4687
4688                 percent = ev_document_find_get_progress
4689                                 (EV_DOCUMENT_FIND (view->document));
4690                 message = g_strdup_printf (_("%3d%% remaining to search"),
4691                                            (int) ((1.0 - percent) * 100));
4692                 
4693         }
4694         ev_view_set_find_status (view, message);
4695         g_free (message);
4696 }
4697
4698 const char *
4699 ev_view_get_find_status (EvView *view)
4700 {
4701         g_return_val_if_fail (EV_IS_VIEW (view), NULL);
4702
4703         return view->find_status;
4704 }
4705
4706 static void
4707 ev_view_set_find_status (EvView *view, const char *message)
4708 {
4709         g_return_if_fail (EV_IS_VIEW (view));
4710
4711         g_free (view->find_status);
4712         view->find_status = g_strdup (message);
4713         g_object_notify (G_OBJECT (view), "find-status");
4714 }
4715
4716 /*** Find ***/
4717
4718 static void
4719 jump_to_find_result (EvView *view)
4720 {
4721         EvDocumentFind *find = EV_DOCUMENT_FIND (view->document);
4722         EvRectangle rect;
4723         GdkRectangle view_rect;
4724         int n_results;
4725         int page = view->current_page;
4726
4727         n_results = ev_document_find_get_n_results (find, page);
4728
4729         if (n_results > 0  && view->find_result < n_results) {
4730                 ev_document_find_get_result
4731                         (find, page, view->find_result, &rect);
4732
4733                 doc_rect_to_view_rect (view, page, &rect, &view_rect);
4734                 ensure_rectangle_is_visible (view, &view_rect);
4735         }
4736 }
4737
4738 /**
4739  * jump_to_find_page
4740  * @view: #EvView instance
4741  * @direction: Direction to look
4742  * @shift: Shift from current page
4743  *
4744  * Jumps to the first page that has occurences of searched word.
4745  * Uses a direction where to look and a shift from current page. 
4746  *
4747  */
4748 static void
4749 jump_to_find_page (EvView *view, EvViewFindDirection direction, gint shift)
4750 {
4751         int n_pages, i;
4752
4753         n_pages = ev_page_cache_get_n_pages (view->page_cache);
4754
4755         for (i = 0; i < n_pages; i++) {
4756                 int has_results;
4757                 int page;
4758                 
4759                 if (direction == EV_VIEW_FIND_NEXT)
4760                         page = view->current_page + i;
4761                 else
4762                         page = view->current_page - i;          
4763                 page += shift;
4764                 
4765                 if (page >= n_pages) {
4766                         page = page - n_pages;
4767                 }
4768                 if (page < 0) 
4769                         page = page + n_pages;
4770                 
4771                 has_results = ev_document_find_page_has_results
4772                                 (EV_DOCUMENT_FIND (view->document), page);
4773                 if (has_results == -1) {
4774                         break;
4775                 } else if (has_results == 1) {
4776                         ev_page_cache_set_current_page (view->page_cache, page);
4777                         break;
4778                 }
4779         }
4780 }
4781
4782 gboolean
4783 ev_view_can_find_next (EvView *view)
4784 {
4785         if (EV_IS_DOCUMENT_FIND (view->document)) {
4786                 EvDocumentFind *find = EV_DOCUMENT_FIND (view->document);
4787                 int i, n_pages;
4788
4789                 n_pages = ev_page_cache_get_n_pages (view->page_cache);
4790                 for (i = 0; i < n_pages; i++) {
4791                         if (ev_document_find_get_n_results (find, i) > 0) {
4792                                 return TRUE;
4793                         }
4794                 }
4795         }
4796
4797         return FALSE;
4798 }
4799
4800 void
4801 ev_view_find_next (EvView *view)
4802 {
4803         int n_results, n_pages;
4804         EvDocumentFind *find = EV_DOCUMENT_FIND (view->document);
4805
4806         n_results = ev_document_find_get_n_results (find, view->current_page);
4807
4808         n_pages = ev_page_cache_get_n_pages (view->page_cache);
4809
4810         view->find_result++;
4811
4812         if (view->find_result >= n_results) {
4813
4814                 view->find_result = 0;
4815                 jump_to_find_page (view, EV_VIEW_FIND_NEXT, 1);
4816                 jump_to_find_result (view);
4817         } else {
4818                 jump_to_find_result (view);
4819                 gtk_widget_queue_draw (GTK_WIDGET (view));
4820         }
4821 }
4822
4823 gboolean
4824 ev_view_can_find_previous (EvView *view)
4825 {
4826         if (EV_IS_DOCUMENT_FIND (view->document)) {
4827                 EvDocumentFind *find = EV_DOCUMENT_FIND (view->document);
4828                 int i, n_pages;
4829
4830                 n_pages = ev_page_cache_get_n_pages (view->page_cache);
4831                 for (i = n_pages - 1; i >= 0; i--) {
4832                         if (ev_document_find_get_n_results (find, i) > 0) {
4833                                 return TRUE;
4834                         }
4835                 }
4836         }
4837
4838         return FALSE;
4839 }
4840 void
4841 ev_view_find_previous (EvView *view)
4842 {
4843         int n_results, n_pages;
4844         EvDocumentFind *find = EV_DOCUMENT_FIND (view->document);
4845         EvPageCache *page_cache;
4846
4847         page_cache = ev_page_cache_get (view->document);
4848
4849         n_results = ev_document_find_get_n_results (find, view->current_page);
4850
4851         n_pages = ev_page_cache_get_n_pages (page_cache);
4852
4853         view->find_result--;
4854
4855         if (view->find_result < 0) {
4856
4857                 jump_to_find_page (view, EV_VIEW_FIND_PREV, -1);
4858                 view->find_result = ev_document_find_get_n_results (find, view->current_page) - 1;
4859                 jump_to_find_result (view);
4860         } else {
4861                 jump_to_find_result (view);
4862                 gtk_widget_queue_draw (GTK_WIDGET (view));
4863         }
4864 }
4865
4866 void ev_view_search_changed (EvView *view)
4867 {
4868         /* search string has changed, focus on new search result */
4869         view->jump_to_find_result = TRUE;
4870 }
4871
4872 /*** Selections ***/
4873
4874 /* compute_new_selection_rect/text calculates the area currently selected by
4875  * view_rect.  each handles a different mode;
4876  */
4877 static GList *
4878 compute_new_selection_rect (EvView       *view,
4879                             GdkPoint     *start,
4880                             GdkPoint     *stop)
4881 {
4882         GdkRectangle view_rect;
4883         int n_pages, i;
4884         GList *list = NULL;
4885
4886         g_assert (view->selection_mode == EV_VIEW_SELECTION_RECTANGLE);
4887         
4888         view_rect.x = MIN (start->x, stop->x);
4889         view_rect.y = MIN (start->y, stop->y);
4890         view_rect.width = MAX (start->x, stop->x) - view_rect.x;
4891         view_rect.width = MAX (start->y, stop->y) - view_rect.y;
4892
4893         n_pages = ev_page_cache_get_n_pages (view->page_cache);
4894
4895         for (i = 0; i < n_pages; i++) {
4896                 GdkRectangle page_area;
4897                 GtkBorder border;
4898                 
4899                 if (get_page_extents (view, i, &page_area, &border)) {
4900                         GdkRectangle overlap;
4901
4902                         if (gdk_rectangle_intersect (&page_area, &view_rect, &overlap)) {
4903                                 EvViewSelection *selection;
4904
4905                                 selection = g_new0 (EvViewSelection, 1);
4906                                 selection->page = i;
4907                                 view_rect_to_doc_rect (view, &overlap, &page_area,
4908                                                        &(selection->rect));
4909
4910                                 list = g_list_append (list, selection);
4911                         }
4912                 }
4913         }
4914
4915         return list;
4916 }
4917
4918 static gboolean
4919 gdk_rectangle_point_in (GdkRectangle *rectangle,
4920                         GdkPoint     *point)
4921 {
4922         return rectangle->x <= point->x &&
4923                 rectangle->y <= point->y &&
4924                 point->x < rectangle->x + rectangle->width &&
4925                 point->y < rectangle->y + rectangle->height;
4926 }
4927
4928 static GList *
4929 compute_new_selection_text (EvView   *view,
4930                             GdkPoint *start,
4931                             GdkPoint *stop)
4932 {
4933         int n_pages, i, first, last;
4934         GList *list = NULL;
4935         EvViewSelection *selection;
4936         gint width, height;
4937         int start_page, end_page;
4938
4939         g_assert (view->selection_mode == EV_VIEW_SELECTION_TEXT);
4940
4941         n_pages = ev_page_cache_get_n_pages (view->page_cache);
4942
4943         /* First figure out the range of pages the selection
4944          * affects. */
4945         first = n_pages;
4946         last = 0;
4947         if (view->continuous) {
4948                 start_page = 0;
4949                 end_page = n_pages;
4950         } else if (view->dual_page) {
4951                 start_page = view->start_page;
4952                 end_page = view->end_page + 1;
4953         } else {
4954                 start_page = view->current_page;
4955                 end_page = view->current_page + 1;
4956         }
4957
4958         for (i = start_page; i < end_page; i++) {
4959                 GdkRectangle page_area;
4960                 GtkBorder border;
4961                 
4962                 get_page_extents (view, i, &page_area, &border);
4963                 if (gdk_rectangle_point_in (&page_area, start) || 
4964                     gdk_rectangle_point_in (&page_area, stop)) {
4965                         if (first == n_pages)
4966                                 first = i;
4967                         last = i;
4968                 }
4969
4970         }
4971
4972         /* Now create a list of EvViewSelection's for the affected
4973          * pages.  This could be an empty list, a list of just one
4974          * page or a number of pages.*/
4975         for (i = first; i < last + 1; i++) {
4976                 GdkRectangle page_area;
4977                 GtkBorder border;
4978                 GdkPoint *point;
4979
4980                 ev_page_cache_get_size (view->page_cache, i,
4981                                         view->rotation,
4982                                         1.0, &width, &height);
4983
4984                 selection = g_new0 (EvViewSelection, 1);
4985                 selection->page = i;
4986                 selection->rect.x1 = selection->rect.y1 = 0;
4987                 selection->rect.x2 = width;
4988                 selection->rect.y2 = height;
4989
4990                 get_page_extents (view, i, &page_area, &border);
4991
4992                 if (gdk_rectangle_point_in (&page_area, start))
4993                         point = start;
4994                 else
4995                         point = stop;
4996
4997                 if (i == first)
4998                         view_point_to_doc_point (view, point, &page_area,
4999                                                  &selection->rect.x1,
5000                                                  &selection->rect.y1);
5001
5002                 /* If the selection is contained within just one page,
5003                  * make sure we don't write 'start' into both points
5004                  * in selection->rect. */
5005                 if (first == last)
5006                         point = stop;
5007
5008                 if (i == last)
5009                         view_point_to_doc_point (view, point, &page_area,
5010                                                  &selection->rect.x2,
5011                                                  &selection->rect.y2);
5012
5013                 list = g_list_append (list, selection);
5014         }
5015
5016         return list;
5017 }
5018
5019 /* This function takes the newly calculated list, and figures out which regions
5020  * have changed.  It then queues a redraw approporiately.
5021  */
5022 static void
5023 merge_selection_region (EvView *view,
5024                         GList  *new_list)
5025 {
5026         GList *old_list;
5027         GList *new_list_ptr, *old_list_ptr;
5028
5029         /* Update the selection */
5030         old_list = ev_pixbuf_cache_get_selection_list (view->pixbuf_cache);
5031         g_list_foreach (view->selection_info.selections, (GFunc)selection_free, NULL);
5032         view->selection_info.selections = new_list;
5033         ev_pixbuf_cache_set_selection_list (view->pixbuf_cache, new_list);
5034         g_object_notify (G_OBJECT (view), "has-selection");
5035
5036         new_list_ptr = new_list;
5037         old_list_ptr = old_list;
5038
5039         while (new_list_ptr || old_list_ptr) {
5040                 EvViewSelection *old_sel, *new_sel;
5041                 int cur_page;
5042                 GdkRegion *region = NULL;
5043
5044                 new_sel = (new_list_ptr) ? (new_list_ptr->data) : NULL;
5045                 old_sel = (old_list_ptr) ? (old_list_ptr->data) : NULL;
5046
5047                 /* Assume that the lists are in order, and we run through them
5048                  * comparing them, one page at a time.  We come out with the
5049                  * first page we see. */
5050                 if (new_sel && old_sel) {
5051                         if (new_sel->page < old_sel->page) {
5052                                 new_list_ptr = new_list_ptr->next;
5053                                 old_sel = NULL;
5054                         } else if (new_sel->page > old_sel->page) {
5055                                 old_list_ptr = old_list_ptr->next;
5056                                 new_sel = NULL;
5057                         } else {
5058                                 new_list_ptr = new_list_ptr->next;
5059                                 old_list_ptr = old_list_ptr->next;
5060                         }
5061                 } else if (new_sel) {
5062                         new_list_ptr = new_list_ptr->next;
5063                 } else if (old_sel) {
5064                         old_list_ptr = old_list_ptr->next;
5065                 }
5066
5067                 g_assert (new_sel || old_sel);
5068
5069                 /* is the page we're looking at on the screen?*/
5070                 cur_page = new_sel ? new_sel->page : old_sel->page;
5071                 if (cur_page < view->start_page || cur_page > view->end_page)
5072                         continue;
5073
5074                 /* seed the cache with a new page.  We are going to need the new
5075                  * region too. */
5076                 if (new_sel) {
5077                         GdkRegion *tmp_region = NULL;
5078
5079                         ev_pixbuf_cache_get_selection_surface (view->pixbuf_cache,
5080                                                                cur_page,
5081                                                                view->scale,
5082                                                                &tmp_region);
5083
5084                         if (tmp_region) {
5085                                 new_sel->covered_region = gdk_region_copy (tmp_region);
5086                         }
5087                 }
5088
5089                 /* Now we figure out what needs redrawing */
5090                 if (old_sel && new_sel) {
5091                         if (old_sel->covered_region && new_sel->covered_region) {
5092                                 /* We only want to redraw the areas that have
5093                                  * changed, so we xor the old and new regions
5094                                  * and redraw if it's different */
5095                                 region = gdk_region_copy (old_sel->covered_region);
5096                                 gdk_region_xor (region, new_sel->covered_region);
5097                                 if (gdk_region_empty (region)) {
5098                                         gdk_region_destroy (region);
5099                                         region = NULL;
5100                                 }
5101                         } else if (old_sel->covered_region) {
5102                                 region = gdk_region_copy (old_sel->covered_region);
5103                         } else if (new_sel->covered_region) {
5104                                 region = gdk_region_copy (new_sel->covered_region);
5105                         }
5106                 } else if (old_sel && !new_sel) {
5107                         if (old_sel->covered_region && !gdk_region_empty (old_sel->covered_region)) {
5108                                 region = gdk_region_copy (old_sel->covered_region);
5109                         }
5110                 } else if (!old_sel && new_sel) {
5111                         if (new_sel->covered_region && !gdk_region_empty (new_sel->covered_region)) {
5112                                 region = gdk_region_copy (new_sel->covered_region);
5113                         }
5114                 } else {
5115                         g_assert_not_reached ();
5116                 }
5117
5118                 /* Redraw the damaged region! */
5119                 if (region) {
5120                         GdkRectangle page_area;
5121                         GtkBorder border;
5122
5123                         /* I don't know why but the region is smaller
5124                          * than expected. This hack fixes it, I guess
5125                          * 10 pixels more won't hurt
5126                          */
5127                         gdk_region_shrink (region, -5, -5);
5128
5129                         get_page_extents (view, cur_page, &page_area, &border);
5130                         gdk_region_offset (region,
5131                                            page_area.x + border.left - view->scroll_x,
5132                                            page_area.y + border.top - view->scroll_y);
5133                         gdk_window_invalidate_region (view->layout.bin_window, region, TRUE);
5134                         gdk_region_destroy (region);
5135                 }
5136         }
5137
5138         /* Free the old list, now that we're done with it. */
5139         g_list_foreach (old_list, (GFunc) selection_free, NULL);
5140 }
5141
5142 static void
5143 compute_selections (EvView   *view,
5144                     GdkPoint *start,
5145                     GdkPoint *stop)
5146 {
5147         GList *list;
5148
5149         if (view->selection_mode == EV_VIEW_SELECTION_RECTANGLE)
5150                 list = compute_new_selection_rect (view, start, stop);
5151         else
5152                 list = compute_new_selection_text (view, start, stop);
5153         merge_selection_region (view, list);
5154 }
5155
5156 /* Free's the selection.  It's up to the caller to queue redraws if needed.
5157  */
5158 static void
5159 selection_free (EvViewSelection *selection)
5160 {
5161         if (selection->covered_region)
5162                 gdk_region_destroy (selection->covered_region);
5163         g_free (selection);
5164 }
5165
5166 static void
5167 clear_selection (EvView *view)
5168 {
5169         g_list_foreach (view->selection_info.selections, (GFunc)selection_free, NULL);
5170         view->selection_info.selections = NULL;
5171         view->selection_info.in_selection = FALSE;
5172         if (view->pixbuf_cache)
5173                 ev_pixbuf_cache_set_selection_list (view->pixbuf_cache, NULL);
5174         g_object_notify (G_OBJECT (view), "has-selection");
5175 }
5176
5177
5178 void
5179 ev_view_select_all (EvView *view)
5180 {
5181         int n_pages, i;
5182
5183         /* Disable selection on rotated pages for the 0.4.0 series */
5184         if (view->rotation != 0)
5185                 return;
5186
5187         clear_selection (view);
5188
5189         n_pages = ev_page_cache_get_n_pages (view->page_cache);
5190         for (i = 0; i < n_pages; i++) {
5191                 int width, height;
5192                 EvViewSelection *selection;
5193
5194                 ev_page_cache_get_size (view->page_cache,
5195                                         i,
5196                                         view->rotation,
5197                                         1.0, &width, &height);
5198
5199                 selection = g_new0 (EvViewSelection, 1);
5200                 selection->page = i;
5201                 selection->rect.x1 = selection->rect.y1 = 0;
5202                 selection->rect.x2 = width;
5203                 selection->rect.y2 = height;
5204
5205                 view->selection_info.selections = g_list_append (view->selection_info.selections, selection);
5206         }
5207
5208         ev_pixbuf_cache_set_selection_list (view->pixbuf_cache, view->selection_info.selections);
5209         g_object_notify (G_OBJECT (view), "has-selection");
5210         gtk_widget_queue_draw (GTK_WIDGET (view));
5211 }
5212
5213 gboolean
5214 ev_view_get_has_selection (EvView *view)
5215 {
5216         return view->selection_info.selections != NULL;
5217 }
5218
5219 static char *
5220 get_selected_text (EvView *ev_view)
5221 {
5222         GString *text;
5223         GList *l;
5224         gchar *normalized_text;
5225
5226         text = g_string_new (NULL);
5227
5228         ev_document_doc_mutex_lock ();
5229
5230         for (l = ev_view->selection_info.selections; l != NULL; l = l->next) {
5231                 EvViewSelection *selection = (EvViewSelection *)l->data;
5232                 char *tmp;
5233
5234                 tmp = ev_document_get_text (ev_view->document,
5235                                             selection->page,
5236                                             &selection->rect);
5237                 g_string_append (text, tmp);
5238                 g_free (tmp);
5239         }
5240
5241         ev_document_doc_mutex_unlock ();
5242
5243         normalized_text = g_utf8_normalize (text->str, text->len, G_NORMALIZE_NFKC);
5244         g_string_free (text, TRUE);
5245         return normalized_text;
5246 }
5247
5248 void
5249 ev_view_copy (EvView *ev_view)
5250 {
5251         GtkClipboard *clipboard;
5252         char *text;
5253
5254         if (!ev_document_can_get_text (ev_view->document)) {
5255                 return;
5256         }
5257
5258         text = get_selected_text (ev_view);
5259         clipboard = gtk_widget_get_clipboard (GTK_WIDGET (ev_view),
5260                                               GDK_SELECTION_CLIPBOARD);
5261         gtk_clipboard_set_text (clipboard, text, -1);
5262         g_free (text);
5263 }
5264
5265 static void
5266 ev_view_primary_get_cb (GtkClipboard     *clipboard,
5267                         GtkSelectionData *selection_data,
5268                         guint             info,
5269                         gpointer          data)
5270 {
5271         EvView *ev_view = EV_VIEW (data);
5272         char *text;
5273
5274         if (!ev_document_can_get_text (ev_view->document)) {
5275                 return;
5276         }
5277
5278         text = get_selected_text (ev_view);
5279         if (text) {
5280                 gtk_selection_data_set_text (selection_data, text, -1);
5281                 g_free (text);
5282         }
5283 }
5284
5285 static void
5286 ev_view_primary_clear_cb (GtkClipboard *clipboard,
5287                           gpointer      data)
5288 {
5289         EvView *view = EV_VIEW (data);
5290
5291         clear_selection (view);
5292 }
5293
5294 static void
5295 ev_view_update_primary_selection (EvView *ev_view)
5296 {
5297         GtkClipboard *clipboard;
5298
5299         clipboard = gtk_widget_get_clipboard (GTK_WIDGET (ev_view),
5300                                               GDK_SELECTION_PRIMARY);
5301
5302         if (ev_view->selection_info.selections) {
5303                 if (!gtk_clipboard_set_with_owner (clipboard,
5304                                                    clipboard_targets,
5305                                                    G_N_ELEMENTS (clipboard_targets),
5306                                                    ev_view_primary_get_cb,
5307                                                    ev_view_primary_clear_cb,
5308                                                    G_OBJECT (ev_view)))
5309                         ev_view_primary_clear_cb (clipboard, ev_view);
5310         } else {
5311                 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (ev_view))
5312                         gtk_clipboard_clear (clipboard);
5313         }
5314 }
5315
5316 /*** Cursor operations ***/
5317
5318 static GdkCursor *
5319 ev_view_create_invisible_cursor(void)
5320 {
5321        GdkBitmap *empty;
5322        GdkColor black = { 0, 0, 0, 0 };
5323        static char bits[] = { 0x00 };
5324
5325        empty = gdk_bitmap_create_from_data (NULL, bits, 1, 1);
5326
5327        return gdk_cursor_new_from_pixmap (empty, empty, &black, &black, 0, 0);
5328 }
5329
5330 static void
5331 ev_view_set_cursor (EvView *view, EvViewCursor new_cursor)
5332 {
5333         GdkCursor *cursor = NULL;
5334         GdkDisplay *display;
5335         GtkWidget *widget;
5336
5337         if (view->cursor == new_cursor) {
5338                 return;
5339         }
5340
5341         widget = gtk_widget_get_toplevel (GTK_WIDGET (view));
5342         display = gtk_widget_get_display (widget);
5343         view->cursor = new_cursor;
5344
5345         switch (new_cursor) {
5346                 case EV_VIEW_CURSOR_NORMAL:
5347                         gdk_window_set_cursor (view->layout.bin_window, NULL);
5348                         break;
5349                 case EV_VIEW_CURSOR_IBEAM:
5350                         cursor = gdk_cursor_new_for_display (display, GDK_XTERM);
5351                         break;
5352                 case EV_VIEW_CURSOR_LINK:
5353                         cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
5354                         break;
5355                 case EV_VIEW_CURSOR_WAIT:
5356                         cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
5357                         break;
5358                 case EV_VIEW_CURSOR_HIDDEN:
5359                         cursor = ev_view_create_invisible_cursor ();
5360                         break;
5361                 case EV_VIEW_CURSOR_DRAG:
5362                         cursor = gdk_cursor_new_for_display (display, GDK_FLEUR);
5363                         break;
5364         }
5365
5366         if (cursor) {
5367                 gdk_window_set_cursor (view->layout.bin_window, cursor);
5368                 gdk_cursor_unref (cursor);
5369                 gdk_flush();
5370         }
5371 }
5372
5373 void
5374 ev_view_hide_cursor (EvView *view)
5375 {
5376        ev_view_set_cursor (view, EV_VIEW_CURSOR_HIDDEN);
5377 }
5378
5379 void
5380 ev_view_show_cursor (EvView *view)
5381 {
5382        ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
5383 }
5384
5385 static void
5386 ev_view_reset_presentation_state (EvView *view)
5387 {
5388         if (!view->presentation ||
5389             view->presentation_state == EV_PRESENTATION_NORMAL)
5390                 return;
5391
5392         view->presentation_state = EV_PRESENTATION_NORMAL;
5393         gdk_window_set_background (view->layout.bin_window,
5394                                    &GTK_WIDGET (view)->style->black);
5395         gtk_widget_queue_draw (GTK_WIDGET (view));
5396 }
5397
5398 gboolean
5399 ev_view_next_page (EvView *view)
5400 {
5401         int page, n_pages;
5402
5403         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
5404         
5405         if (!view->page_cache)
5406                 return FALSE;
5407
5408         if (view->presentation &&
5409             (view->presentation_state == EV_PRESENTATION_BLACK ||
5410              view->presentation_state == EV_PRESENTATION_WHITE)) {
5411                 ev_view_reset_presentation_state (view);
5412                 return FALSE; 
5413         }       
5414
5415         ev_view_presentation_transition_stop (view);
5416         ev_view_reset_presentation_state (view);
5417         
5418         page = ev_page_cache_get_current_page (view->page_cache);
5419         n_pages = ev_page_cache_get_n_pages (view->page_cache);
5420
5421         if (view->dual_page && !view->presentation)
5422                 page = page + 2; 
5423         else 
5424                 page = page + 1;
5425
5426         if (page < n_pages) {
5427                 ev_page_cache_set_current_page (view->page_cache, page);
5428                 return TRUE;
5429         } else if (view->presentation && page == n_pages) {
5430                 view->presentation_state = EV_PRESENTATION_END;
5431                 gtk_widget_queue_draw (GTK_WIDGET (view));
5432                 return TRUE;
5433         } else if (view->dual_page && page == n_pages) {
5434                 ev_page_cache_set_current_page (view->page_cache, page - 1);
5435                 return TRUE;
5436         } else {
5437                 return FALSE;
5438         }
5439 }
5440
5441 gboolean
5442 ev_view_previous_page (EvView *view)
5443 {
5444         int page;
5445
5446         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
5447
5448         if (!view->page_cache)
5449                 return FALSE;
5450
5451         if (view->presentation &&
5452             view->presentation_state == EV_PRESENTATION_END) {
5453                 ev_view_reset_presentation_state (view);
5454                 return TRUE;
5455         }
5456         
5457         if (view->presentation && 
5458             (view->presentation_state == EV_PRESENTATION_BLACK ||
5459              view->presentation_state == EV_PRESENTATION_WHITE)) {
5460                 ev_view_reset_presentation_state (view);
5461                 return FALSE; 
5462         }       
5463
5464         ev_view_reset_presentation_state (view);
5465
5466         page = ev_page_cache_get_current_page (view->page_cache);
5467
5468         if (view->dual_page && !view->presentation)
5469                 page = page - 2; 
5470         else 
5471                 page = page - 1;
5472
5473         if (page >= 0) {
5474                 ev_page_cache_set_current_page (view->page_cache, page);
5475                 return TRUE;
5476         } else if (ev_view_get_dual_page (view) && page == -1) {
5477                 ev_page_cache_set_current_page (view->page_cache, 0);
5478                 return TRUE;
5479         } else {        
5480                 return FALSE;
5481         }
5482 }
5483
5484 /*** Enum description for usage in signal ***/
5485
5486 GType
5487 ev_sizing_mode_get_type (void)
5488 {
5489   static GType etype = 0;
5490   if (etype == 0) {
5491     static const GEnumValue values[] = {
5492       { EV_SIZING_FIT_WIDTH, "EV_SIZING_FIT_WIDTH", "fit-width" },
5493       { EV_SIZING_BEST_FIT, "EV_SIZING_BEST_FIT", "best-fit" },
5494       { EV_SIZING_FREE, "EV_SIZING_FREE", "free" },
5495       { 0, NULL, NULL }
5496     };
5497     etype = g_enum_register_static ("EvSizingMode", values);
5498   }
5499   return etype;
5500 }
5501
5502 GType
5503 ev_scroll_type_get_type (void)
5504 {
5505   static GType etype = 0;
5506   if (etype == 0) {
5507     static const GEnumValue values[] = {
5508       { EV_SCROLL_PAGE_FORWARD, "EV_SCROLL_PAGE_FORWARD", "scroll-page-forward" },
5509       { EV_SCROLL_PAGE_BACKWARD, "EV_SCROLL_PAGE_BACKWARD", "scroll-page-backward" },
5510       { EV_SCROLL_STEP_FORWARD, "EV_SCROLL_STEP_FORWARD", "scroll-step-forward" },
5511       { EV_SCROLL_STEP_FORWARD, "EV_SCROLL_STEP_FORWARD", "scroll-step-forward" },
5512       { EV_SCROLL_STEP_UP, "EV_SCROLL_STEP_UP", "scroll-step-up" },
5513       { EV_SCROLL_STEP_DOWN, "EV_SCROLL_STEP_DOWN", "scroll-step-down" },
5514       { 0, NULL, NULL }
5515     };
5516     etype = g_enum_register_static ("EvScrollType", values);
5517   }
5518   return etype;
5519 }