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