]> www.fi.muni.cz Git - evince.git/blob - shell/ev-view.c
1659302e21daab775fc88eb19a4b56fcfc475b00
[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 "config.h"
22
23 #include <stdlib.h>
24 #include <math.h>
25 #include <string.h>
26
27 #include <glib/gi18n.h>
28 #include <gtk/gtk.h>
29 #include <gdk/gdkkeysyms.h>
30
31 #include "ev-application.h"
32 #include "ev-document-forms.h"
33 #include "ev-document-images.h"
34 #include "ev-document-links.h"
35 #include "ev-document-misc.h"
36 #include "ev-document-transition.h"
37 #include "ev-marshal.h"
38 #include "ev-page-cache.h"
39 #include "ev-pixbuf-cache.h"
40 #include "ev-transition-animation.h"
41 #include "ev-utils.h"
42 #include "ev-view.h"
43 #include "ev-view-private.h"
44
45 #if !GTK_CHECK_VERSION (2, 11, 7)
46 #include "ev-tooltip.h"
47 #endif
48
49 #define EV_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_VIEW, EvViewClass))
50 #define EV_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_VIEW))
51 #define EV_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_VIEW, EvViewClass))
52
53 enum {
54         PROP_0,
55         PROP_CONTINUOUS,
56         PROP_DUAL_PAGE,
57         PROP_FULLSCREEN,
58         PROP_PRESENTATION,
59         PROP_SIZING_MODE,
60         PROP_ZOOM,
61         PROP_ROTATION,
62         PROP_HAS_SELECTION,
63 };
64
65 enum {
66         SIGNAL_BINDING_ACTIVATED,
67         SIGNAL_ZOOM_INVALID,
68         SIGNAL_HANDLE_LINK,
69         SIGNAL_EXTERNAL_LINK,
70         SIGNAL_POPUP_MENU,
71         N_SIGNALS,
72 };
73
74 enum {
75         TARGET_DND_URI,
76         TARGET_DND_TEXT,
77         TARGET_DND_IMAGE
78 };
79
80 enum {
81         TARGET_STRING,
82         TARGET_TEXT,
83         TARGET_COMPOUND_TEXT,
84         TARGET_UTF8_STRING,
85         TARGET_TEXT_BUFFER_CONTENTS
86 };
87
88 static const GtkTargetEntry clipboard_targets[] = {
89         { "STRING", 0, TARGET_STRING },
90         { "TEXT",   0, TARGET_TEXT },
91         { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
92         { "UTF8_STRING", 0, TARGET_UTF8_STRING },
93 };
94
95 static const GtkTargetEntry view_drop_targets[] = {
96         { "text/uri-list", 0, 0 }
97 };
98
99 static guint signals[N_SIGNALS];
100
101 typedef enum {
102         EV_VIEW_FIND_NEXT,
103         EV_VIEW_FIND_PREV
104 } EvViewFindDirection;
105
106 #define ZOOM_IN_FACTOR  1.2
107 #define ZOOM_OUT_FACTOR (1.0/ZOOM_IN_FACTOR)
108
109 #define MIN_SCALE 0.05409
110 #define MAX_SCALE 4.0
111
112 #define SCROLL_TIME 150
113
114 /*** Scrolling ***/
115 static void       scroll_to_current_page                     (EvView *view,
116                                                               GtkOrientation orientation);
117 static void       ev_view_set_scroll_adjustments             (GtkLayout          *layout,
118                                                               GtkAdjustment      *hadjustment,
119                                                               GtkAdjustment      *vadjustment);
120 static void       view_update_range_and_current_page         (EvView             *view);
121 static void       set_scroll_adjustment                      (EvView             *view,
122                                                               GtkOrientation      orientation,
123                                                               GtkAdjustment      *adjustment);
124 static void       add_scroll_binding_keypad                  (GtkBindingSet      *binding_set,
125                                                               guint               keyval,
126                                                               GdkModifierType modifiers,
127                                                               GtkScrollType       scroll,
128                                                               gboolean            horizontal);
129 static void       ensure_rectangle_is_visible                (EvView             *view,
130                                                               GdkRectangle       *rect);
131
132 /*** Geometry computations ***/
133 static void       compute_border                             (EvView             *view,
134                                                               int                 width,
135                                                               int                 height,
136                                                               GtkBorder          *border);
137 static void       get_page_y_offset                          (EvView *view,
138                                                               int page,
139                                                               double zoom,
140                                                               int *y_offset);
141 static gboolean   get_page_extents                           (EvView             *view,
142                                                               gint                page,
143                                                               GdkRectangle       *page_area,
144                                                               GtkBorder          *border);
145 static void       view_rect_to_doc_rect                      (EvView             *view,
146                                                               GdkRectangle       *view_rect,
147                                                               GdkRectangle       *page_area,
148                                                               EvRectangle        *doc_rect);
149 static void       doc_rect_to_view_rect                      (EvView             *view,
150                                                               int                 page,
151                                                               EvRectangle        *doc_rect,
152                                                               GdkRectangle       *view_rect);
153 static void       find_page_at_location                      (EvView             *view,
154                                                               gdouble             x,
155                                                               gdouble             y,
156                                                               gint               *page,
157                                                               gint               *x_offset,
158                                                               gint               *y_offset);
159 static gboolean  doc_point_to_view_point                     (EvView             *view,
160                                                               int                 page,
161                                                               EvPoint            *doc_point,
162                                                               GdkPoint           *view_point);
163 /*** Hyperrefs ***/
164 static EvLink *   ev_view_get_link_at_location               (EvView             *view,
165                                                               gdouble             x,
166                                                               gdouble             y);
167 static char*      tip_from_link                              (EvView             *view,
168                                                               EvLink             *link);
169 /*** Forms ***/
170 static EvFormField *ev_view_get_form_field_at_location       (EvView             *view,
171                                                                gdouble            x,
172                                                                gdouble            y);
173
174 /*** GtkWidget implementation ***/
175 static void       ev_view_size_request_continuous_dual_page  (EvView             *view,
176                                                               GtkRequisition     *requisition);
177 static void       ev_view_size_request_continuous            (EvView             *view,
178                                                               GtkRequisition     *requisition);
179 static void       ev_view_size_request_dual_page             (EvView             *view,
180                                                               GtkRequisition     *requisition);
181 static void       ev_view_size_request_single_page           (EvView             *view,
182                                                               GtkRequisition     *requisition);
183 static void       ev_view_size_request                       (GtkWidget          *widget,
184                                                               GtkRequisition     *requisition);
185 static void       ev_view_size_allocate                      (GtkWidget          *widget,
186                                                               GtkAllocation      *allocation);
187 static void       ev_view_realize                            (GtkWidget          *widget);
188 static gboolean   ev_view_scroll_event                       (GtkWidget          *widget,
189                                                               GdkEventScroll     *event);
190 static gboolean   ev_view_expose_event                       (GtkWidget          *widget,
191                                                               GdkEventExpose     *event);
192 static gboolean   ev_view_popup_menu                         (GtkWidget          *widget);
193 static gboolean   ev_view_button_press_event                 (GtkWidget          *widget,
194                                                               GdkEventButton     *event);
195 static gboolean   ev_view_motion_notify_event                (GtkWidget          *widget,
196                                                               GdkEventMotion     *event);
197 static gboolean   ev_view_button_release_event               (GtkWidget          *widget,
198                                                               GdkEventButton     *event);
199 static gboolean   ev_view_enter_notify_event                 (GtkWidget          *widget,
200                                                               GdkEventCrossing   *event);
201 static gboolean   ev_view_leave_notify_event                 (GtkWidget          *widget,
202                                                               GdkEventCrossing   *event);
203 static void       ev_view_style_set                          (GtkWidget          *widget,
204                                                               GtkStyle           *old_style);
205 static void       ev_view_remove_all                         (EvView             *view);
206
207 static AtkObject *ev_view_get_accessible                     (GtkWidget *widget);
208
209 /*** Drawing ***/
210 static guint32    ev_gdk_color_to_rgb                        (const GdkColor     *color);
211 static void       draw_rubberband                            (GtkWidget          *widget,
212                                                               GdkWindow          *window,
213                                                               const GdkRectangle *rect,
214                                                               guchar              alpha);
215 static void       highlight_find_results                     (EvView             *view,
216                                                               int                 page);
217 static void       draw_one_page                              (EvView             *view,
218                                                               gint                page,
219                                                               cairo_t            *cr,
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       job_finished_cb                            (EvPixbufCache      *pixbuf_cache,
230                                                               GdkRegion          *region,
231                                                               EvView             *view);
232 static void       page_changed_cb                            (EvPageCache        *page_cache,
233                                                               int                 new_page,
234                                                               EvView             *view);
235 static void       on_adjustment_value_changed                (GtkAdjustment      *adjustment,
236                                                               EvView             *view);
237
238 /*** GObject ***/
239 static void       ev_view_finalize                           (GObject            *object);
240 static void       ev_view_destroy                            (GtkObject          *object);
241 static void       ev_view_set_property                       (GObject            *object,
242                                                               guint               prop_id,
243                                                               const GValue       *value,
244                                                               GParamSpec         *pspec);
245 static void       ev_view_get_property                       (GObject            *object,
246                                                               guint               prop_id,
247                                                               GValue             *value,
248                                                               GParamSpec         *pspec);
249 static void       ev_view_class_init                         (EvViewClass        *class);
250 static void       ev_view_init                               (EvView             *view);
251
252 /*** Zoom and sizing ***/
253 static double   zoom_for_size_fit_width                      (int doc_width,
254                                                               int doc_height,
255                                                               int target_width,
256                                                               int target_height,
257                                                               int vsb_width);
258 static double   zoom_for_size_fit_height                     (int doc_width,
259                                                               int doc_height,
260                                                               int target_width,
261                                                               int target_height,
262                                                               int vsb_height);
263 static double   zoom_for_size_best_fit                       (int doc_width,
264                                                               int doc_height,
265                                                               int target_width,
266                                                               int target_height,
267                                                               int vsb_width,
268                                                               int hsb_width);
269 static void     ev_view_zoom_for_size_presentation           (EvView *view,
270                                                               int     width,
271                                                               int     height);
272 static void     ev_view_zoom_for_size_continuous_and_dual_page (EvView *view,
273                                                                 int     width,
274                                                                 int     height,
275                                                                 int     vsb_width,
276                                                                 int     hsb_height);
277 static void     ev_view_zoom_for_size_continuous               (EvView *view,
278                                                                 int     width,
279                                                                 int     height,
280                                                                 int     vsb_width,
281                                                                 int     hsb_height);
282 static void     ev_view_zoom_for_size_dual_page                (EvView *view,
283                                                                 int     width,
284                                                                 int     height,
285                                                                 int     vsb_width,
286                                                                 int     hsb_height);
287 static void     ev_view_zoom_for_size_single_page              (EvView *view,
288                                                                 int     width,
289                                                                 int     height,
290                                                                 int     vsb_width,
291                                                                 int     hsb_height);
292 /*** Cursors ***/
293 static GdkCursor* ev_view_create_invisible_cursor            (void);
294 static void       ev_view_set_cursor                         (EvView             *view,
295                                                               EvViewCursor        new_cursor);
296 static void       ev_view_handle_cursor_over_xy              (EvView *view,
297                                                               gint x,
298                                                               gint y);
299
300 /*** Find ***/
301 static gint         ev_view_find_get_n_results               (EvView             *view,
302                                                               gint                page);
303 static EvRectangle *ev_view_find_get_result                  (EvView             *view,
304                                                               gint                page,
305                                                               gint                result);
306 static void       jump_to_find_result                        (EvView             *view);
307 static void       jump_to_find_page                          (EvView             *view, 
308                                                               EvViewFindDirection direction,
309                                                               gint                shift);
310
311 /*** Selection ***/
312 static void       compute_selections                         (EvView             *view,
313                                                               EvSelectionStyle    style,
314                                                               GdkPoint           *start,
315                                                               GdkPoint           *stop);
316 static void       clear_selection                            (EvView             *view);
317 static void       clear_link_selected                        (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 && view->current_page <= view->end_page) {
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                            GtkScrollType   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                                 GTK_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                                 GTK_TYPE_SCROLL_TYPE, scroll,
589                                 G_TYPE_BOOLEAN, horizontal);
590 }
591
592 void
593 ev_view_scroll (EvView        *view,
594                 GtkScrollType  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 GTK_SCROLL_PAGE_BACKWARD:
607                         case GTK_SCROLL_STEP_BACKWARD:
608                                 ev_view_previous_page (view);
609                                 break;
610                         case GTK_SCROLL_PAGE_FORWARD:
611                         case GTK_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 GTK_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 GTK_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 GTK_SCROLL_STEP_BACKWARD:
659                         value -= adjustment->step_increment;
660                         break;
661                 case GTK_SCROLL_STEP_FORWARD:
662                         value += adjustment->step_increment;
663                         break;
664                 case GTK_SCROLL_STEP_DOWN:
665                         value -= adjustment->step_increment / 10;
666                         break;
667                 case GTK_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         gdouble zoom, left, top;
1155         gboolean change_left, change_top;
1156
1157         left = ev_link_dest_get_left (dest, &change_left);
1158         top = ev_link_dest_get_top (dest, &change_top);
1159
1160         zoom = zoom_for_size_best_fit (ev_link_dest_get_right (dest) - left,
1161                                        ev_link_dest_get_bottom (dest) - top,
1162                                        ev_view_get_width (view),
1163                                        ev_view_get_height (view), 0, 0);
1164
1165         ev_view_set_sizing_mode (view, EV_SIZING_FREE);
1166         ev_view_set_zoom (view, zoom, FALSE);
1167
1168         doc_point.x = change_left ? left : 0;
1169         doc_point.y = change_top ? top : 0;
1170         
1171         view->current_page = ev_link_dest_get_page (dest);
1172         if (change_left || change_top)
1173                 view->pending_point = doc_point;
1174         view->pending_scroll = SCROLL_TO_PAGE_POSITION;
1175
1176         gtk_widget_queue_resize (GTK_WIDGET (view));
1177 }
1178
1179 static void
1180 goto_fitv_dest (EvView *view, EvLinkDest *dest)
1181 {
1182         EvPoint doc_point;
1183         int doc_width, doc_height, page;
1184         double zoom, left;
1185         gboolean change_left;
1186
1187         page = ev_link_dest_get_page (dest);
1188         ev_page_cache_get_size (view->page_cache, page, 0, 1.0, &doc_width, &doc_height);
1189
1190         left = ev_link_dest_get_left (dest, &change_left);
1191         doc_point.x = change_left ? left : 0;
1192         doc_point.y = 0;
1193
1194         zoom = zoom_for_size_fit_height (doc_width - doc_point.x , doc_height,
1195                                          ev_view_get_width (view),
1196                                          ev_view_get_height (view), 0);
1197
1198         ev_view_set_sizing_mode (view, EV_SIZING_FREE);
1199         ev_view_set_zoom (view, zoom, FALSE);
1200
1201         view->current_page = page;
1202         if (change_left)
1203                 view->pending_point = doc_point;
1204         view->pending_scroll = SCROLL_TO_PAGE_POSITION;
1205
1206         gtk_widget_queue_resize (GTK_WIDGET (view));
1207 }
1208
1209 static void
1210 goto_fith_dest (EvView *view, EvLinkDest *dest)
1211 {
1212         EvPoint doc_point;
1213         int doc_width, doc_height, page;
1214         gdouble zoom, top;
1215         gboolean change_top;
1216
1217         page = ev_link_dest_get_page (dest);
1218         ev_page_cache_get_size (view->page_cache, page, 0, 1.0, &doc_width, &doc_height);
1219
1220         top = ev_link_dest_get_top (dest, &change_top);
1221
1222         doc_point.x = 0;
1223         doc_point.y = change_top ? top : 0;
1224
1225         zoom = zoom_for_size_fit_width (doc_width, top,
1226                                         ev_view_get_width (view),
1227                                         ev_view_get_height (view), 0);
1228
1229         ev_view_set_sizing_mode (view, EV_SIZING_FIT_WIDTH);
1230         ev_view_set_zoom (view, zoom, FALSE);
1231
1232         view->current_page = page;
1233         if (change_top)
1234                 view->pending_point = doc_point;
1235         view->pending_scroll = SCROLL_TO_PAGE_POSITION;
1236
1237         gtk_widget_queue_resize (GTK_WIDGET (view));
1238 }
1239
1240 static void
1241 goto_fit_dest (EvView *view, EvLinkDest *dest)
1242 {
1243         double zoom;
1244         int doc_width, doc_height;
1245         int page;
1246
1247         page = ev_link_dest_get_page (dest);
1248         ev_page_cache_get_size (view->page_cache, page, 0, 1.0, &doc_width, &doc_height);
1249
1250         zoom = zoom_for_size_best_fit (doc_width, doc_height, ev_view_get_width (view),
1251                                        ev_view_get_height (view), 0, 0);
1252
1253         ev_view_set_sizing_mode (view, EV_SIZING_BEST_FIT);
1254         ev_view_set_zoom (view, zoom, FALSE);
1255
1256         view->current_page = page;
1257         view->pending_scroll = SCROLL_TO_PAGE_POSITION;
1258
1259         gtk_widget_queue_resize (GTK_WIDGET (view));
1260 }
1261
1262 static void
1263 goto_xyz_dest (EvView *view, EvLinkDest *dest)
1264 {
1265         EvPoint doc_point;
1266         gint page;
1267         gdouble zoom, left, top;
1268         gboolean change_zoom, change_left, change_top; 
1269
1270         zoom = ev_link_dest_get_zoom (dest, &change_zoom);
1271         page = ev_link_dest_get_page (dest);
1272
1273         if (change_zoom && zoom > 1) {
1274                 ev_view_set_sizing_mode (view, EV_SIZING_FREE);
1275                 ev_view_set_zoom (view, zoom, FALSE);
1276         }
1277
1278         left = ev_link_dest_get_left (dest, &change_left);
1279         top = ev_link_dest_get_top (dest, &change_top);
1280
1281         doc_point.x = change_left ? left : 0;
1282         doc_point.y = change_top ? top : 0;
1283
1284         view->current_page = page;
1285         if (change_left || change_top)
1286                 view->pending_point = doc_point;
1287         view->pending_scroll = SCROLL_TO_PAGE_POSITION;
1288
1289         gtk_widget_queue_resize (GTK_WIDGET (view));
1290 }
1291
1292 static void
1293 goto_dest (EvView *view, EvLinkDest *dest)
1294 {
1295         EvLinkDestType type;
1296         int page, n_pages, current_page;
1297
1298         page = ev_link_dest_get_page (dest);
1299         n_pages = ev_page_cache_get_n_pages (view->page_cache);
1300
1301         if (page < 0 || page >= n_pages)
1302                 return;
1303
1304         current_page = view->current_page;
1305         
1306         type = ev_link_dest_get_dest_type (dest);
1307
1308         switch (type) {
1309                 case EV_LINK_DEST_TYPE_PAGE:
1310                         ev_page_cache_set_current_page (view->page_cache, page);
1311                         break;
1312                 case EV_LINK_DEST_TYPE_FIT:
1313                         goto_fit_dest (view, dest);
1314                         break;
1315                 case EV_LINK_DEST_TYPE_FITH:
1316                         goto_fith_dest (view, dest);
1317                         break;
1318                 case EV_LINK_DEST_TYPE_FITV:
1319                         goto_fitv_dest (view, dest);
1320                         break;
1321                 case EV_LINK_DEST_TYPE_FITR:
1322                         goto_fitr_dest (view, dest);
1323                         break;
1324                 case EV_LINK_DEST_TYPE_XYZ:
1325                         goto_xyz_dest (view, dest);
1326                         break;
1327                 case EV_LINK_DEST_TYPE_PAGE_LABEL:
1328                         ev_page_cache_set_page_label (view->page_cache, ev_link_dest_get_page_label (dest));
1329                         break;
1330                 default:
1331                         g_assert_not_reached ();
1332         }
1333
1334         if (current_page != view->current_page)
1335                 ev_page_cache_set_current_page (view->page_cache,
1336                                                 view->current_page);
1337 }
1338
1339 static void
1340 ev_view_goto_dest (EvView *view, EvLinkDest *dest)
1341 {
1342         EvLinkDestType type;
1343
1344         type = ev_link_dest_get_dest_type (dest);
1345
1346         if (type == EV_LINK_DEST_TYPE_NAMED) {
1347                 EvLinkDest  *dest2;     
1348                 const gchar *named_dest;
1349
1350                 named_dest = ev_link_dest_get_named_dest (dest);
1351                 dest2 = ev_document_links_find_link_dest (EV_DOCUMENT_LINKS (view->document),
1352                                                           named_dest);
1353                 if (dest2) {
1354                         goto_dest (view, dest2);
1355                         g_object_unref (dest2);
1356                 }
1357
1358                 return;
1359         }
1360
1361         goto_dest (view, dest);
1362 }
1363         
1364 void
1365 ev_view_handle_link (EvView *view, EvLink *link)
1366 {
1367         EvLinkAction    *action = NULL;
1368         EvLinkActionType type;
1369
1370         action = ev_link_get_action (link);
1371         if (!action)
1372                 return;
1373
1374         type = ev_link_action_get_action_type (action);
1375
1376         switch (type) {
1377                 case EV_LINK_ACTION_TYPE_GOTO_DEST: {
1378                         EvLinkDest *dest;
1379                         
1380                         g_signal_emit (view, signals[SIGNAL_HANDLE_LINK], 0, link);
1381                 
1382                         dest = ev_link_action_get_dest (action);
1383                         ev_view_goto_dest (view, dest);
1384                 }
1385                         break;
1386                 case EV_LINK_ACTION_TYPE_GOTO_REMOTE:
1387                 case EV_LINK_ACTION_TYPE_EXTERNAL_URI:
1388                 case EV_LINK_ACTION_TYPE_LAUNCH:
1389                 case EV_LINK_ACTION_TYPE_NAMED:
1390                         g_signal_emit (view, signals[SIGNAL_EXTERNAL_LINK], 0, action);
1391                         break;
1392         }
1393 }
1394
1395 gchar *
1396 ev_view_page_label_from_dest (EvView *view, EvLinkDest *dest)
1397 {
1398         EvLinkDestType type;
1399         gchar *msg = NULL;
1400
1401         type = ev_link_dest_get_dest_type (dest);
1402
1403         switch (type) {
1404                 case EV_LINK_DEST_TYPE_NAMED: {
1405                         EvLinkDest  *dest2;
1406                         const gchar *named_dest;
1407                         
1408                         named_dest = ev_link_dest_get_named_dest (dest);
1409                         dest2 = ev_document_links_find_link_dest (EV_DOCUMENT_LINKS (view->document),
1410                                                                   named_dest);
1411                         if (dest2) {
1412                                 msg = ev_page_cache_get_page_label (view->page_cache,
1413                                                                     ev_link_dest_get_page (dest2));
1414                                 g_object_unref (dest2);
1415                         }
1416                 }
1417                         
1418                         break;
1419                 case EV_LINK_DEST_TYPE_PAGE_LABEL: {
1420                         msg = g_strdup (ev_link_dest_get_page_label (dest));
1421                 }
1422                         break;
1423                 default: 
1424                         msg = ev_page_cache_get_page_label (view->page_cache,
1425                                                             ev_link_dest_get_page (dest));
1426         }
1427         
1428         return msg;
1429 }
1430
1431 static char *
1432 tip_from_action_named (EvLinkAction *action)
1433 {
1434         const gchar *name = ev_link_action_get_name (action);
1435         
1436         if (g_ascii_strcasecmp (name, "FirstPage") == 0) {
1437                 return g_strdup (_("Go to first page"));
1438         } else if (g_ascii_strcasecmp (name, "PrevPage") == 0) {
1439                 return g_strdup (_("Go to previous page"));
1440         } else if (g_ascii_strcasecmp (name, "NextPage") == 0) {
1441                 return g_strdup (_("Go to next page"));
1442         } else if (g_ascii_strcasecmp (name, "LastPage") == 0) {
1443                 return g_strdup (_("Go to last page"));
1444         } else if (g_ascii_strcasecmp (name, "GoToPage") == 0) {
1445                 return g_strdup (_("Go to page"));
1446         } else if (g_ascii_strcasecmp (name, "Find") == 0) {
1447                 return g_strdup (_("Find"));
1448         }
1449         
1450         return NULL;
1451 }
1452
1453 static char *
1454 tip_from_link (EvView *view, EvLink *link)
1455 {
1456         EvLinkAction *action;
1457         EvLinkActionType type;
1458         char *msg = NULL;
1459         char *page_label;
1460         const char *title;
1461
1462         action = ev_link_get_action (link);
1463         title = ev_link_get_title (link);
1464         
1465         if (!action)
1466                 return title ? g_strdup (title) : NULL;
1467                 
1468         type = ev_link_action_get_action_type (action);
1469
1470         switch (type) {
1471                 case EV_LINK_ACTION_TYPE_GOTO_DEST:
1472                         page_label = ev_view_page_label_from_dest (view,
1473                                                                    ev_link_action_get_dest (action));
1474                         if (page_label) {
1475                                 msg = g_strdup_printf (_("Go to page %s"), page_label);
1476                                 g_free (page_label);
1477                         }
1478                         break;
1479                 case EV_LINK_ACTION_TYPE_GOTO_REMOTE:
1480                         if (title) {
1481                                 msg = g_strdup_printf (_("Go to %s on file “%s”"), title,
1482                                                        ev_link_action_get_filename (action));
1483                         } else {
1484                                 msg = g_strdup_printf (_("Go to file “%s”"),
1485                                                        ev_link_action_get_filename (action));
1486                         }
1487                         break;
1488                 case EV_LINK_ACTION_TYPE_EXTERNAL_URI:
1489                         msg = g_strdup (ev_link_action_get_uri (action));
1490                         break;
1491                 case EV_LINK_ACTION_TYPE_LAUNCH:
1492                         msg = g_strdup_printf (_("Launch %s"),
1493                                                ev_link_action_get_filename (action));
1494                         break;
1495                 case EV_LINK_ACTION_TYPE_NAMED:
1496                         msg = tip_from_action_named (action);
1497                         break;
1498                 default:
1499                         if (title)
1500                                 msg = g_strdup (title);
1501                         break;
1502         }
1503         
1504         return msg;
1505 }
1506
1507 static void
1508 ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y)
1509 {
1510         EvLink      *link;
1511         EvFormField *field;
1512
1513         if (view->cursor == EV_VIEW_CURSOR_HIDDEN)
1514                 return;
1515
1516         if (view->drag_info.in_drag) {
1517                 if (view->cursor != EV_VIEW_CURSOR_DRAG)
1518                         ev_view_set_cursor (view, EV_VIEW_CURSOR_DRAG);
1519                 return;
1520         }
1521
1522         if (view->scroll_info.autoscrolling) {
1523                 if (view->cursor != EV_VIEW_CURSOR_AUTOSCROLL)
1524                         ev_view_set_cursor (view, EV_VIEW_CURSOR_AUTOSCROLL);
1525                 return;
1526         }
1527         
1528         link = ev_view_get_link_at_location (view, x, y);
1529         
1530 #if !GTK_CHECK_VERSION (2, 11, 7)
1531         if (view->link_tooltip == NULL) {
1532                 view->link_tooltip = ev_tooltip_new (GTK_WIDGET (view));
1533         }
1534
1535         if (view->hovered_link != link) {
1536                 view->hovered_link = link;
1537                 ev_tooltip_deactivate (EV_TOOLTIP (view->link_tooltip));
1538         }
1539 #endif
1540
1541         if (link) {
1542 #if GTK_CHECK_VERSION (2, 11, 7)
1543                 g_object_set (view, "has-tooltip", TRUE, NULL);
1544 #else
1545                 char *msg = tip_from_link (view, link);
1546
1547                 if (msg && g_utf8_validate (msg, -1, NULL)) {
1548                         EvTooltip *tooltip = EV_TOOLTIP (view->link_tooltip);
1549
1550                         ev_tooltip_set_position (tooltip, x, y);
1551                         ev_tooltip_set_text (tooltip, msg);
1552                         ev_tooltip_activate (tooltip);
1553                 }
1554                 g_free (msg);
1555 #endif
1556                 ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK);
1557         } else if ((field = ev_view_get_form_field_at_location (view, x, y))) {
1558                 if (field->is_read_only) {
1559                         if (view->cursor == EV_VIEW_CURSOR_LINK ||
1560                             view->cursor == EV_VIEW_CURSOR_IBEAM ||
1561                             view->cursor == EV_VIEW_CURSOR_DRAG)
1562                                 ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
1563                 } else if (EV_IS_FORM_FIELD_TEXT (field)) {
1564                         ev_view_set_cursor (view, EV_VIEW_CURSOR_IBEAM);
1565                 } else {
1566                         ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK);
1567                 }
1568         } else if (location_in_text (view, x + view->scroll_x, y + view->scroll_y)) {
1569                 ev_view_set_cursor (view, EV_VIEW_CURSOR_IBEAM);
1570         } else {
1571                 if (view->cursor == EV_VIEW_CURSOR_LINK ||
1572                     view->cursor == EV_VIEW_CURSOR_IBEAM ||
1573                     view->cursor == EV_VIEW_CURSOR_DRAG ||
1574                     view->cursor == EV_VIEW_CURSOR_AUTOSCROLL)
1575                         ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
1576         }
1577 }
1578
1579 /*** Images ***/
1580 static EvImage *
1581 ev_view_get_image_at_location (EvView  *view,
1582                                gdouble  x,
1583                                gdouble  y)
1584 {
1585         gint page = -1;
1586         gint x_offset = 0, y_offset = 0;
1587         gint x_new = 0, y_new = 0;
1588         GList *image_mapping;
1589
1590         if (!EV_IS_DOCUMENT_IMAGES (view->document))
1591                 return NULL;
1592
1593         x += view->scroll_x;
1594         y += view->scroll_y;
1595
1596         find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
1597
1598         if (page == -1)
1599                 return NULL;
1600
1601         if (get_doc_point_from_offset (view, page, x_offset,
1602                                        y_offset, &x_new, &y_new) == FALSE)
1603                 return NULL;
1604
1605         image_mapping = ev_pixbuf_cache_get_image_mapping (view->pixbuf_cache, page);
1606
1607         if (image_mapping)
1608                 return ev_image_mapping_find (image_mapping, x_new, y_new);
1609         else
1610                 return NULL;
1611 }
1612
1613 /*** Forms ***/
1614 static EvFormField *
1615 ev_view_get_form_field_at_location (EvView  *view,
1616                                     gdouble  x,
1617                                     gdouble  y)
1618 {
1619         gint page = -1;
1620         gint x_offset = 0, y_offset = 0;
1621         gint x_new = 0, y_new = 0;
1622         GList *forms_mapping;
1623         
1624         if (!EV_IS_DOCUMENT_FORMS (view->document))
1625                 return NULL;
1626
1627         x += view->scroll_x;
1628         y += view->scroll_y;
1629         
1630         find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
1631         
1632         if (page == -1)
1633                 return NULL;
1634
1635         if (get_doc_point_from_offset (view, page, x_offset,
1636                                        y_offset, &x_new, &y_new) == FALSE)
1637                 return NULL;
1638
1639         forms_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, page);
1640
1641         if (forms_mapping)
1642                 return ev_form_field_mapping_find (forms_mapping, x_new, y_new);
1643         else
1644                 return NULL;
1645 }
1646
1647 static GdkRegion *
1648 ev_view_form_field_get_region (EvView      *view,
1649                                EvFormField *field)
1650 {
1651         EvRectangle  field_area;
1652         GdkRectangle view_area;
1653         GList       *forms_mapping;
1654
1655         forms_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache,
1656                                                                 field->page->index);
1657         ev_form_field_mapping_get_area (forms_mapping, field, &field_area);
1658         doc_rect_to_view_rect (view, field->page->index, &field_area, &view_area);
1659         view_area.x -= view->scroll_x;
1660         view_area.y -= view->scroll_y;
1661
1662         return gdk_region_rectangle (&view_area);
1663 }
1664
1665 static gboolean
1666 ev_view_forms_remove_widgets (EvView *view)
1667 {
1668         ev_view_remove_all (view);
1669
1670         return FALSE;
1671 }
1672
1673 static void
1674 ev_view_form_field_destroy (GtkWidget *widget,
1675                             EvView    *view)
1676 {
1677         g_idle_add ((GSourceFunc)ev_view_forms_remove_widgets, view);
1678 }
1679
1680 static GtkWidget *
1681 ev_view_form_field_button_create_widget (EvView      *view,
1682                                          EvFormField *field)
1683 {
1684         EvFormFieldButton *field_button = EV_FORM_FIELD_BUTTON (field);
1685         GdkRegion         *field_region = NULL;
1686         
1687         switch (field_button->type) {
1688                 case EV_FORM_FIELD_BUTTON_PUSH:
1689                         return NULL;
1690                 case EV_FORM_FIELD_BUTTON_CHECK:
1691                 case EV_FORM_FIELD_BUTTON_RADIO: {
1692                         gboolean  state;
1693                         GList    *forms_mapping, *l;
1694
1695                         state = ev_document_forms_form_field_button_get_state (EV_DOCUMENT_FORMS (view->document),
1696                                                                                field);
1697
1698                         /* FIXME: it actually depends on NoToggleToOff flags */
1699                         if (field_button->type == EV_FORM_FIELD_BUTTON_RADIO &&
1700                             state && field_button->state)
1701                                 return NULL;
1702                         
1703                         field_region = ev_view_form_field_get_region (view, field);
1704
1705                         /* For radio buttons and checkbox buttons that are in a set
1706                          * we need to update also the region for the current selected item
1707                          */
1708                         forms_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache,
1709                                                                                 field->page->index);
1710                         for (l = forms_mapping; l; l = g_list_next (l)) {
1711                                 EvFormField *button = ((EvFormFieldMapping *)(l->data))->field;
1712                                 GdkRegion   *button_region;
1713
1714                                 if (button->id == field->id)
1715                                         continue;
1716
1717                                 /* FIXME: only buttons in the same group should be updated */
1718                                 if (!EV_IS_FORM_FIELD_BUTTON (button) ||
1719                                     EV_FORM_FIELD_BUTTON (button)->type != field_button->type ||
1720                                     EV_FORM_FIELD_BUTTON (button)->state != TRUE)
1721                                         continue;
1722
1723                                 button_region = ev_view_form_field_get_region (view, button);
1724                                 gdk_region_union (field_region, button_region);
1725                                 gdk_region_destroy (button_region);
1726                         }
1727                         
1728                         ev_document_forms_form_field_button_set_state (EV_DOCUMENT_FORMS (view->document),
1729                                                                        field, !state);
1730                         field_button->state = !state;
1731                 }
1732                         break;
1733         }
1734
1735         ev_pixbuf_cache_reload_page (view->pixbuf_cache,
1736                                      field_region,
1737                                      field->page->index,
1738                                      view->rotation,
1739                                      view->scale);
1740         gdk_region_destroy (field_region);
1741         
1742         return NULL;
1743 }
1744
1745 static void
1746 ev_view_form_field_text_save (EvView    *view,
1747                               GtkWidget *widget)
1748 {
1749         EvFormField *field;
1750
1751         if (!view->document)
1752                 return;
1753         
1754         field = g_object_get_data (G_OBJECT (widget), "form-field");
1755         
1756         if (field->changed) {
1757                 EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field);
1758                 GdkRegion       *field_region;
1759
1760                 field_region = ev_view_form_field_get_region (view, field);
1761                 
1762                 ev_document_forms_form_field_text_set_text (EV_DOCUMENT_FORMS (view->document),
1763                                                             field, field_text->text);
1764                 field->changed = FALSE;
1765                 ev_pixbuf_cache_reload_page (view->pixbuf_cache,
1766                                              field_region,
1767                                              field->page->index,
1768                                              view->rotation,
1769                                              view->scale);
1770                 gdk_region_destroy (field_region);
1771         }
1772 }
1773
1774 static void
1775 ev_view_form_field_text_changed (GtkWidget   *widget,
1776                                  EvFormField *field)
1777 {
1778         EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field);
1779         gchar           *text = NULL;
1780
1781         if (GTK_IS_ENTRY (widget)) {
1782                 text = g_strdup (gtk_entry_get_text (GTK_ENTRY (widget)));
1783         } else if (GTK_IS_TEXT_BUFFER (widget)) {
1784                 GtkTextIter start, end;
1785
1786                 gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (widget), &start, &end);
1787                 text = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (widget),
1788                                                  &start, &end, FALSE);
1789         }
1790
1791         if (!field_text->text ||
1792             (field_text->text && g_ascii_strcasecmp (field_text->text, text) != 0)) {
1793                 g_free (field_text->text);
1794                 field_text->text = text;
1795                 field->changed = TRUE;
1796         }
1797 }
1798
1799 static GtkWidget *
1800 ev_view_form_field_text_create_widget (EvView      *view,
1801                                        EvFormField *field)
1802 {
1803         EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field);
1804         GtkWidget       *text = NULL;
1805         gchar           *txt;
1806
1807         txt = ev_document_forms_form_field_text_get_text (EV_DOCUMENT_FORMS (view->document),
1808                                                           field);
1809
1810         switch (field_text->type) {
1811                 case EV_FORM_FIELD_TEXT_FILE_SELECT:
1812                         /* TODO */
1813                 case EV_FORM_FIELD_TEXT_NORMAL:
1814                         text = gtk_entry_new ();
1815                         gtk_entry_set_has_frame (GTK_ENTRY (text), FALSE);
1816                         gtk_entry_set_max_length (GTK_ENTRY (text), field_text->max_len);
1817                         gtk_entry_set_visibility (GTK_ENTRY (text), !field_text->is_password);
1818                         
1819                         if (txt) {
1820                                 gtk_entry_set_text (GTK_ENTRY (text), txt);
1821                                 g_free (txt);
1822                         }
1823
1824                         g_signal_connect (G_OBJECT (text), "changed",
1825                                           G_CALLBACK (ev_view_form_field_text_changed),
1826                                           field);
1827                         g_signal_connect_after (G_OBJECT (text), "activate",
1828                                                 G_CALLBACK (ev_view_form_field_destroy),
1829                                                 view);
1830                         break;
1831                 case EV_FORM_FIELD_TEXT_MULTILINE: {
1832                         GtkTextBuffer *buffer;
1833                 
1834                         text = gtk_text_view_new ();
1835                         buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text));
1836                         
1837                         if (txt) {
1838                                 gtk_text_buffer_set_text (buffer, txt, -1);
1839                                 g_free (txt);
1840                         }
1841                         
1842                         g_signal_connect (G_OBJECT (buffer), "changed",
1843                                           G_CALLBACK (ev_view_form_field_text_changed),
1844                                           field);
1845                 }
1846                         break;
1847         }                       
1848
1849         g_object_weak_ref (G_OBJECT (text),
1850                            (GWeakNotify)ev_view_form_field_text_save,
1851                            view);
1852
1853         return text;
1854 }
1855
1856 static void
1857 ev_view_form_field_choice_save (EvView    *view,
1858                                 GtkWidget *widget)
1859 {
1860         EvFormField *field;
1861
1862         if (!view->document)
1863                 return;
1864         
1865         field = g_object_get_data (G_OBJECT (widget), "form-field");
1866
1867         if (field->changed) {
1868                 GList             *l;
1869                 EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field);
1870                 GdkRegion         *field_region;
1871
1872                 field_region = ev_view_form_field_get_region (view, field);
1873
1874                 if (field_choice->is_editable) {
1875                         ev_document_forms_form_field_choice_set_text (EV_DOCUMENT_FORMS (view->document),
1876                                                                       field, field_choice->text);
1877                 } else {
1878                         ev_document_forms_form_field_choice_unselect_all (EV_DOCUMENT_FORMS (view->document), field);
1879                         for (l = field_choice->selected_items; l; l = g_list_next (l)) {
1880                                 ev_document_forms_form_field_choice_select_item (EV_DOCUMENT_FORMS (view->document),
1881                                                                                  field,
1882                                                                                  GPOINTER_TO_INT (l->data));
1883                         }
1884                 }
1885                 field->changed = FALSE;
1886                 ev_pixbuf_cache_reload_page (view->pixbuf_cache,
1887                                              field_region,
1888                                              field->page->index,
1889                                              view->rotation,
1890                                              view->scale);
1891                 gdk_region_destroy (field_region);
1892         }
1893 }
1894
1895 static void
1896 ev_view_form_field_choice_changed (GtkWidget   *widget,
1897                                    EvFormField *field)
1898 {
1899         EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field);
1900         
1901         if (GTK_IS_COMBO_BOX (widget)) {
1902                 gint item;
1903                 
1904                 item = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
1905                 if (!field_choice->selected_items ||
1906                     GPOINTER_TO_INT (field_choice->selected_items->data) != item) {
1907                         g_list_free (field_choice->selected_items);
1908                         field_choice->selected_items = NULL;
1909                         field_choice->selected_items = g_list_prepend (field_choice->selected_items,
1910                                                                        GINT_TO_POINTER (item));
1911                         field->changed = TRUE;
1912                 }
1913
1914                 if (GTK_IS_COMBO_BOX_ENTRY (widget)) {
1915                         gchar *text;
1916                         
1917                         text = gtk_combo_box_get_active_text (GTK_COMBO_BOX (widget));
1918                         if (!field_choice->text ||
1919                             (field_choice->text && g_ascii_strcasecmp (field_choice->text, text) != 0)) {
1920                                 g_free (field_choice->text);
1921                                 field_choice->text = text;
1922                                 field->changed = TRUE;
1923                         }
1924                 }
1925         } else if (GTK_IS_TREE_SELECTION (widget)) {
1926                 GtkTreeSelection *selection = GTK_TREE_SELECTION (widget);
1927                 GtkTreeModel     *model;
1928                 GList            *items, *l;
1929                 
1930                 items = gtk_tree_selection_get_selected_rows (selection, &model);
1931                 g_list_free (field_choice->selected_items);
1932                 field_choice->selected_items = NULL;
1933
1934                 for (l = items; l && l->data; l = g_list_next (l)) {
1935                         GtkTreeIter  iter;
1936                         GtkTreePath *path = (GtkTreePath *)l->data;
1937                         gint         item;
1938                         
1939                         gtk_tree_model_get_iter (model, &iter, path);
1940                         gtk_tree_model_get (model, &iter, 1, &item, -1);
1941
1942                         field_choice->selected_items = g_list_prepend (field_choice->selected_items,
1943                                                                        GINT_TO_POINTER (item));
1944
1945                         gtk_tree_path_free (path);
1946                 }
1947
1948                 g_list_free (items);
1949
1950                 field->changed = TRUE;
1951         }
1952 }
1953
1954 static GtkWidget *
1955 ev_view_form_field_choice_create_widget (EvView      *view,
1956                                          EvFormField *field)
1957 {
1958         EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field);
1959         GtkWidget         *choice;
1960         GtkTreeModel      *model;
1961         gint               n_items, i;
1962         gint               selected_item = 0;
1963
1964         n_items = ev_document_forms_form_field_choice_get_n_items (EV_DOCUMENT_FORMS (view->document),
1965                                                                    field);
1966         model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT));
1967         for (i = 0; i < n_items; i++) {
1968                 GtkTreeIter iter;
1969                 gchar      *item;
1970
1971                 item = ev_document_forms_form_field_choice_get_item (EV_DOCUMENT_FORMS (view->document),
1972                                                                      field, i);
1973                 if (ev_document_forms_form_field_choice_is_item_selected (
1974                             EV_DOCUMENT_FORMS (view->document), field, i)) {
1975                         selected_item = i;
1976                         /* FIXME: we need a get_selected_items function in poppler */
1977                         field_choice->selected_items = g_list_prepend (field_choice->selected_items,
1978                                                                        GINT_TO_POINTER (i));
1979                 }
1980                 
1981                 if (item) {
1982                         gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1983                         gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1984                                             0, item,
1985                                             1, i,
1986                                             -1);
1987                         g_free (item);
1988                 }
1989         }
1990
1991         if (field_choice->type == EV_FORM_FIELD_CHOICE_LIST) {
1992                 GtkCellRenderer  *renderer;
1993                 GtkWidget        *tree_view;
1994                 GtkTreeSelection *selection;
1995
1996                 tree_view = gtk_tree_view_new_with_model (model);
1997                 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
1998
1999                 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
2000                 if (field_choice->multi_select) {
2001                         gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
2002                 }
2003
2004                 /* TODO: set selected items */
2005
2006                 renderer = gtk_cell_renderer_text_new ();
2007                 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
2008                                                              0,
2009                                                              "choix", renderer,
2010                                                              "text", 0,
2011                                                              NULL);
2012
2013                 choice = gtk_scrolled_window_new (NULL, NULL);
2014                 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (choice),
2015                                                 GTK_POLICY_AUTOMATIC,
2016                                                 GTK_POLICY_AUTOMATIC);
2017                 gtk_container_add (GTK_CONTAINER (choice), tree_view);
2018                 gtk_widget_show (tree_view);
2019
2020                 g_signal_connect (G_OBJECT (selection), "changed",
2021                                   G_CALLBACK (ev_view_form_field_choice_changed),
2022                                   field);
2023                 g_signal_connect_after (G_OBJECT (selection), "changed",
2024                                         G_CALLBACK (ev_view_form_field_destroy),
2025                                         view);
2026         } else if (field_choice->is_editable) { /* ComboBoxEntry */
2027                 gchar *text;
2028                 
2029                 choice = gtk_combo_box_entry_new_with_model (model, 0);
2030                 text = ev_document_forms_form_field_choice_get_text (EV_DOCUMENT_FORMS (view->document), field);
2031                 if (text) {
2032                         gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (choice))), text);
2033                         g_free (text);
2034                 }
2035
2036                 g_signal_connect (G_OBJECT (choice), "changed",
2037                                   G_CALLBACK (ev_view_form_field_choice_changed),
2038                                   field);
2039                 g_signal_connect_after (G_OBJECT (GTK_BIN (choice)->child), "activate",
2040                                         G_CALLBACK (ev_view_form_field_destroy),
2041                                         view);
2042         } else { /* ComboBoxText */
2043                 GtkCellRenderer *renderer;
2044
2045                 choice = gtk_combo_box_new_with_model (model);
2046                 renderer = gtk_cell_renderer_text_new ();
2047                 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (choice),
2048                                             renderer, TRUE);
2049                 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (choice),
2050                                                 renderer,
2051                                                 "text", 0,
2052                                                 NULL);
2053                 gtk_combo_box_set_active (GTK_COMBO_BOX (choice), selected_item);
2054                 gtk_combo_box_popup (GTK_COMBO_BOX (choice));
2055                 
2056                 g_signal_connect (G_OBJECT (choice), "changed",
2057                                   G_CALLBACK (ev_view_form_field_choice_changed),
2058                                   field);
2059                 g_signal_connect_after (G_OBJECT (choice), "changed",
2060                                         G_CALLBACK (ev_view_form_field_destroy),
2061                                         view);
2062         }
2063
2064         g_object_unref (model);
2065
2066         g_object_weak_ref (G_OBJECT (choice),
2067                            (GWeakNotify)ev_view_form_field_choice_save,
2068                            view);
2069
2070         return choice;
2071 }
2072
2073 static void
2074 ev_view_handle_form_field (EvView      *view,
2075                            EvFormField *field,
2076                            gdouble      x,
2077                            gdouble      y)
2078 {
2079         GtkWidget   *field_widget = NULL;
2080         GList       *form_field_mapping;
2081         EvRectangle  field_area;
2082         GdkRectangle view_area;
2083
2084         if (field->is_read_only)
2085                 return;
2086         
2087         if (EV_IS_FORM_FIELD_BUTTON (field)) {
2088                 field_widget = ev_view_form_field_button_create_widget (view, field);
2089         } else if (EV_IS_FORM_FIELD_TEXT (field)) {
2090                 field_widget = ev_view_form_field_text_create_widget (view, field);
2091         } else if (EV_IS_FORM_FIELD_CHOICE (field)) {
2092                 field_widget = ev_view_form_field_choice_create_widget (view, field);
2093         } else if (EV_IS_FORM_FIELD_SIGNATURE (field)) {
2094                 /* TODO */
2095         }
2096
2097         /* Form field doesn't require a widget */
2098         if (!field_widget)
2099                 return;
2100
2101         g_object_set_data_full (G_OBJECT (field_widget), "form-field",
2102                                 g_object_ref (field),
2103                                 (GDestroyNotify)g_object_unref);
2104
2105         form_field_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, field->page->index);
2106         ev_form_field_mapping_get_area (form_field_mapping, field, &field_area);
2107         
2108         doc_rect_to_view_rect (view, field->page->index, &field_area, &view_area);
2109         view_area.x -= view->scroll_x;
2110         view_area.y -= view->scroll_y;
2111
2112         gtk_layout_put (GTK_LAYOUT (view), field_widget, view_area.x, view_area.y);
2113         gtk_widget_show (field_widget);
2114         gtk_widget_grab_focus (field_widget);
2115 }
2116
2117 /*** GtkWidget implementation ***/
2118
2119 static void
2120 ev_view_size_request_continuous_dual_page (EvView         *view,
2121                                            GtkRequisition *requisition)
2122 {
2123         int max_width;
2124         gint n_pages;
2125         GtkBorder border;
2126
2127         ev_page_cache_get_max_width (view->page_cache, view->rotation,
2128                                      view->scale, &max_width);
2129         compute_border (view, max_width, max_width, &border);
2130
2131         n_pages = ev_page_cache_get_n_pages (view->page_cache) + 1;
2132
2133         requisition->width = (max_width + border.left + border.right) * 2 + (view->spacing * 3);
2134         get_page_y_offset (view, n_pages, view->scale, &requisition->height);
2135
2136         if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
2137                 requisition->width = 1;
2138         } else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
2139                 requisition->width = 1;
2140                 /* FIXME: This could actually be set on one page docs or docs
2141                  * with a strange aspect ratio. */
2142                 /* requisition->height = 1;*/
2143         }
2144 }
2145
2146 static void
2147 ev_view_size_request_continuous (EvView         *view,
2148                                  GtkRequisition *requisition)
2149 {
2150         int max_width;
2151         int n_pages;
2152         GtkBorder border;
2153
2154
2155         ev_page_cache_get_max_width (view->page_cache, view->rotation,
2156                                      view->scale, &max_width);
2157         n_pages = ev_page_cache_get_n_pages (view->page_cache);
2158         compute_border (view, max_width, max_width, &border);
2159
2160         requisition->width = max_width + (view->spacing * 2) + border.left + border.right;
2161         get_page_y_offset (view, n_pages, view->scale, &requisition->height);
2162
2163         if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
2164                 requisition->width = 1;
2165         } else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
2166                 requisition->width = 1;
2167                 /* FIXME: This could actually be set on one page docs or docs
2168                  * with a strange aspect ratio. */
2169                 /* requisition->height = 1;*/
2170         }
2171 }
2172
2173 static void
2174 ev_view_size_request_dual_page (EvView         *view,
2175                                 GtkRequisition *requisition)
2176 {
2177         GtkBorder border;
2178         gint width, height;
2179
2180         /* Find the largest of the two. */
2181         ev_page_cache_get_size (view->page_cache,
2182                                 view->current_page,
2183                                 view->rotation,
2184                                 view->scale,
2185                                 &width, &height);
2186         if (view->current_page + 1 < ev_page_cache_get_n_pages (view->page_cache)) {
2187                 gint width_2, height_2;
2188                 ev_page_cache_get_size (view->page_cache,
2189                                         view->current_page + 1,
2190                                         view->rotation,
2191                                         view->scale,
2192                                         &width_2, &height_2);
2193                 if (width_2 > width) {
2194                         width = width_2;
2195                         height = height_2;
2196                 }
2197         }
2198         compute_border (view, width, height, &border);
2199
2200         requisition->width = ((width + border.left + border.right) * 2) +
2201                 (view->spacing * 3);
2202         requisition->height = (height + border.top + border.bottom) +
2203                 (view->spacing * 2);
2204
2205         if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
2206                 requisition->width = 1;
2207         } else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
2208                 requisition->width = 1;
2209                 requisition->height = 1;
2210         }
2211 }
2212
2213 static void
2214 ev_view_size_request_single_page (EvView         *view,
2215                                   GtkRequisition *requisition)
2216 {
2217         GtkBorder border;
2218         gint width, height;
2219
2220         ev_page_cache_get_size (view->page_cache,
2221                                 view->current_page,
2222                                 view->rotation,
2223                                 view->scale,
2224                                 &width, &height);
2225         compute_border (view, width, height, &border);
2226
2227         requisition->width = width + border.left + border.right + (2 * view->spacing);
2228         requisition->height = height + border.top + border.bottom + (2 * view->spacing);
2229
2230         if (view->sizing_mode == EV_SIZING_FIT_WIDTH) {
2231                 requisition->width = 1;
2232                 requisition->height = height + border.top + border.bottom + (2 * view->spacing);
2233         } else if (view->sizing_mode == EV_SIZING_BEST_FIT) {
2234                 requisition->width = 1;
2235                 requisition->height = 1;
2236         }
2237 }
2238
2239 static void
2240 ev_view_size_request (GtkWidget      *widget,
2241                       GtkRequisition *requisition)
2242 {
2243         EvView *view = EV_VIEW (widget);
2244         
2245         if (view->document == NULL) {
2246                 requisition->width = 1;
2247                 requisition->height = 1;
2248                 return;
2249         }
2250
2251         if (view->presentation) {
2252                 requisition->width = 1;
2253                 requisition->height = 1;
2254                 return;
2255         }
2256
2257         if (view->continuous && view->dual_page)
2258                 ev_view_size_request_continuous_dual_page (view, requisition);
2259         else if (view->continuous)
2260                 ev_view_size_request_continuous (view, requisition);
2261         else if (view->dual_page)
2262                 ev_view_size_request_dual_page (view, requisition);
2263         else
2264                 ev_view_size_request_single_page (view, requisition);
2265 }
2266
2267 static void
2268 ev_view_size_allocate (GtkWidget      *widget,
2269                        GtkAllocation  *allocation)
2270 {
2271         EvView *view = EV_VIEW (widget);
2272         GList  *children, *l;
2273
2274         GTK_WIDGET_CLASS (ev_view_parent_class)->size_allocate (widget, allocation);
2275         
2276         if (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
2277             view->sizing_mode == EV_SIZING_BEST_FIT) {
2278
2279                 g_signal_emit (view, signals[SIGNAL_ZOOM_INVALID], 0);
2280
2281                 ev_view_size_request (widget, &widget->requisition);
2282         }
2283         
2284         view_set_adjustment_values (view, GTK_ORIENTATION_HORIZONTAL);
2285         view_set_adjustment_values (view, GTK_ORIENTATION_VERTICAL);
2286
2287         if (view->document)
2288                 view_update_range_and_current_page (view);
2289
2290         view->pending_scroll = SCROLL_TO_KEEP_POSITION;
2291         view->pending_resize = FALSE;
2292
2293         children = gtk_container_get_children (GTK_CONTAINER (widget));
2294         for (l = children; l && l->data; l = g_list_next (l)) {
2295                 EvFormField   *field;
2296                 EvRectangle    field_area;
2297                 GdkRectangle   view_area;
2298                 GList         *form_field_mapping;
2299                 GtkAllocation  child_allocation;
2300                 GtkRequisition child_requisition;
2301                 GtkWidget     *child = (GtkWidget *)l->data;
2302                 
2303                 field = g_object_get_data (G_OBJECT (child), "form-field");
2304                 if (!field)
2305                         continue;
2306
2307                 form_field_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache,
2308                                                                              field->page->index);
2309                 ev_form_field_mapping_get_area (form_field_mapping, field, &field_area);
2310
2311                 doc_rect_to_view_rect (view, field->page->index, &field_area, &view_area);
2312                 view_area.x -= view->scroll_x;
2313                 view_area.y -= view->scroll_y;
2314
2315                 gtk_widget_size_request (child, &child_requisition);
2316                 if (child_requisition.width != view_area.width ||
2317                     child_requisition.height != view_area.height)
2318                         gtk_widget_set_size_request (child, view_area.width, view_area.height);
2319
2320                 gtk_container_child_get (GTK_CONTAINER (widget),
2321                                          child,
2322                                          "x", &child_allocation.x,
2323                                          "y", &child_allocation.y,
2324                                          NULL);
2325                 if (child_allocation.x != view_area.x ||
2326                     child_allocation.y != view_area.y) {
2327                         gtk_layout_move (GTK_LAYOUT (widget), child, view_area.x, view_area.y);
2328                 }
2329         }
2330         g_list_free (children);
2331 }
2332
2333 static void
2334 ev_view_realize (GtkWidget *widget)
2335 {
2336         EvView *view = EV_VIEW (widget);
2337
2338         if (GTK_WIDGET_CLASS (ev_view_parent_class)->realize)
2339                 (* GTK_WIDGET_CLASS (ev_view_parent_class)->realize) (widget);
2340
2341         gdk_window_set_events (view->layout.bin_window,
2342                                (gdk_window_get_events (view->layout.bin_window) | 
2343                                 GDK_EXPOSURE_MASK |
2344                                 GDK_BUTTON_PRESS_MASK |
2345                                 GDK_BUTTON_RELEASE_MASK |
2346                                 GDK_SCROLL_MASK |
2347                                 GDK_KEY_PRESS_MASK |
2348                                 GDK_POINTER_MOTION_MASK |
2349                                 GDK_POINTER_MOTION_HINT_MASK |
2350                                 GDK_ENTER_NOTIFY_MASK |
2351                                 GDK_LEAVE_NOTIFY_MASK));
2352
2353         if (view->presentation)
2354                 gdk_window_set_background (view->layout.bin_window, &widget->style->black);
2355         else
2356                 gdk_window_set_background (view->layout.bin_window, &widget->style->mid [GTK_STATE_NORMAL]);
2357 }
2358
2359 static gboolean
2360 ev_view_scroll_event (GtkWidget *widget, GdkEventScroll *event)
2361 {
2362         EvView *view = EV_VIEW (widget);
2363         guint state;
2364
2365         state = event->state & gtk_accelerator_get_default_mod_mask ();
2366
2367         if (state == GDK_CONTROL_MASK && view->presentation == FALSE) {
2368                 ev_view_set_sizing_mode (view, EV_SIZING_FREE);
2369
2370                 if (event->direction == GDK_SCROLL_UP ||
2371                     event->direction == GDK_SCROLL_LEFT) {
2372                         if (ev_view_can_zoom_in (view)) {
2373                                 ev_view_zoom_in (view);
2374                         }
2375                 } else {
2376                         if (ev_view_can_zoom_out (view)) {
2377                                 ev_view_zoom_out (view);
2378                         }
2379                 }
2380
2381                 return TRUE;
2382         }
2383
2384         view->jump_to_find_result = FALSE;
2385
2386         /* Shift+Wheel scrolls the in the perpendicular direction */
2387         if (state & GDK_SHIFT_MASK) {
2388                 if (event->direction == GDK_SCROLL_UP)
2389                         event->direction = GDK_SCROLL_LEFT;
2390                 else if (event->direction == GDK_SCROLL_LEFT)
2391                         event->direction = GDK_SCROLL_UP;
2392                 else if (event->direction == GDK_SCROLL_DOWN)
2393                         event->direction = GDK_SCROLL_RIGHT;
2394                 else if (event->direction == GDK_SCROLL_RIGHT)
2395                         event->direction = GDK_SCROLL_DOWN;
2396
2397                 event->state &= ~GDK_SHIFT_MASK;
2398                 state &= ~GDK_SHIFT_MASK;
2399         }
2400
2401         if (state == 0 && view->presentation) {
2402                 switch (event->direction) {
2403                         case GDK_SCROLL_DOWN:
2404                         case GDK_SCROLL_RIGHT:
2405                                 ev_view_next_page (view);       
2406                                 break;
2407                         case GDK_SCROLL_UP:
2408                         case GDK_SCROLL_LEFT:
2409                                 ev_view_previous_page (view);
2410                                 break;
2411                 }
2412
2413                 return TRUE;
2414         }
2415
2416         return FALSE;
2417 }
2418
2419 static EvViewSelection *
2420 find_selection_for_page (EvView *view,
2421                          gint    page)
2422 {
2423         GList *list;
2424
2425         for (list = view->selection_info.selections; list != NULL; list = list->next) {
2426                 EvViewSelection *selection;
2427
2428                 selection = (EvViewSelection *) list->data;
2429
2430                 if (selection->page == page)
2431                         return selection;
2432         }
2433
2434         return NULL;
2435 }
2436
2437 static void
2438 draw_end_presentation_page (EvView       *view,
2439                             GdkRectangle *page_area)
2440 {
2441         PangoLayout *layout;
2442         PangoFontDescription *font_desc;
2443         gchar *markup;
2444         const gchar *text = _("End of presentation. Press Escape to exit.");
2445
2446         if (view->presentation_state != EV_PRESENTATION_END)
2447                 return;
2448
2449         layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), NULL);
2450         markup = g_strdup_printf ("<span foreground=\"white\">%s</span>", text);
2451         pango_layout_set_markup (layout, markup, -1);
2452         g_free (markup);
2453
2454         font_desc = pango_font_description_new ();
2455         pango_font_description_set_size (font_desc, 16 * PANGO_SCALE);
2456         pango_layout_set_font_description (layout, font_desc);
2457
2458         gtk_paint_layout (GTK_WIDGET (view)->style,
2459                           view->layout.bin_window,
2460                           GTK_WIDGET_STATE (view),
2461                           FALSE,
2462                           page_area,
2463                           GTK_WIDGET (view),
2464                           NULL,
2465                           page_area->x + 15,
2466                           page_area->y + 15,
2467                           layout);
2468
2469         pango_font_description_free (font_desc);
2470         g_object_unref (layout);
2471 }
2472
2473 static gboolean
2474 ev_view_expose_event (GtkWidget      *widget,
2475                       GdkEventExpose *event)
2476 {
2477         EvView  *view = EV_VIEW (widget);
2478         cairo_t *cr;
2479         gint     i;
2480
2481         if (view->animation && ev_transition_animation_ready (view->animation)) {
2482                 GdkRectangle page_area;
2483                 GtkBorder    border;
2484
2485                 if (get_page_extents (view, view->current_page, &page_area, &border)) {
2486                         cr = gdk_cairo_create (view->layout.bin_window);
2487
2488                         /* normalize to x=0, y=0 */
2489                         cairo_translate (cr, page_area.x, page_area.y);
2490                         page_area.x = page_area.y = 0;
2491
2492                         ev_transition_animation_paint (view->animation, cr, page_area);
2493                         cairo_destroy (cr);
2494                 }
2495
2496                 return TRUE;
2497         }
2498
2499         if (view->presentation) {
2500                 switch (view->presentation_state) {
2501                         case EV_PRESENTATION_END: {
2502                                 GdkRectangle area = {0};
2503
2504                                 area.width = widget->allocation.width;
2505                                 area.height = widget->allocation.height;
2506                                 
2507                                 draw_end_presentation_page (view, &area);
2508                         }
2509                                 return FALSE;
2510                         case EV_PRESENTATION_BLACK:
2511                         case EV_PRESENTATION_WHITE:
2512                                 return FALSE;
2513                         case EV_PRESENTATION_NORMAL:
2514                         default:
2515                                 break;
2516                 }
2517         } else if (view->loading) {
2518                 GdkRectangle area = {0};
2519                 
2520                 area.width = widget->allocation.width;
2521                 area.height = widget->allocation.height;
2522
2523                 draw_loading_text (view,
2524                                    &area,
2525                                    &(event->area));
2526         }
2527
2528         if (view->document == NULL)
2529                 return FALSE;
2530
2531         cr = gdk_cairo_create (view->layout.bin_window);
2532         
2533         for (i = view->start_page; i <= view->end_page; i++) {
2534                 GdkRectangle page_area;
2535                 GtkBorder border;
2536                 gboolean page_ready = TRUE;
2537
2538                 if (!get_page_extents (view, i, &page_area, &border))
2539                         continue;
2540
2541                 page_area.x -= view->scroll_x;
2542                 page_area.y -= view->scroll_y;
2543
2544                 draw_one_page (view, i, cr, &page_area, &border, &(event->area), &page_ready);
2545
2546                 if (page_ready && view->find_pages && view->highlight_find_results)
2547                         highlight_find_results (view, i);
2548         }
2549
2550         cairo_destroy (cr);
2551
2552         if (GTK_WIDGET_CLASS (ev_view_parent_class)->expose_event)
2553                 (* GTK_WIDGET_CLASS (ev_view_parent_class)->expose_event) (widget, event);
2554
2555         return FALSE;
2556 }
2557
2558 static gboolean
2559 ev_view_do_popup_menu (EvView *view,
2560                        gdouble x,
2561                        gdouble y)
2562 {
2563         EvLink  *link;
2564         EvImage *image;
2565
2566         image = ev_view_get_image_at_location (view, x, y);
2567         if (image) {
2568                 g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, image);
2569                 return TRUE;
2570         }
2571
2572         link = ev_view_get_link_at_location (view, x, y);
2573         if (link) {
2574                 g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, link);
2575                 return TRUE;
2576         }
2577
2578         g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, NULL);
2579
2580         return TRUE;
2581 }
2582
2583 static gboolean
2584 ev_view_popup_menu (GtkWidget *widget)
2585 {
2586         gint x, y;
2587         
2588         gtk_widget_get_pointer (widget, &x, &y);
2589         return ev_view_do_popup_menu (EV_VIEW (widget), x, y);
2590 }
2591
2592 #if GTK_CHECK_VERSION (2, 11, 7)
2593 static void
2594 get_link_area (EvView       *view,
2595                gint          x,
2596                gint          y,
2597                EvLink       *link,
2598                GdkRectangle *area)
2599 {
2600         EvRectangle  ev_rect;
2601         GList       *link_mapping;
2602         gint         page;
2603         gint         x_offset = 0, y_offset = 0;
2604
2605         x += view->scroll_x;
2606         y += view->scroll_y;
2607         
2608         find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
2609         
2610         link_mapping = ev_pixbuf_cache_get_link_mapping (view->pixbuf_cache, page);
2611         ev_link_mapping_get_area (link_mapping, link, &ev_rect);
2612
2613         doc_rect_to_view_rect (view, page, &ev_rect, area);
2614         area->y -= view->scroll_y ;
2615 }
2616
2617 static gboolean
2618 ev_view_query_tooltip (GtkWidget         *widget,
2619                        gint               x,
2620                        gint               y,
2621                        gboolean           keyboard_tip,
2622                        GtkTooltip        *tooltip)
2623 {
2624         EvView *view = EV_VIEW (widget);
2625         EvLink *link;
2626         gchar  *text;
2627
2628         link = ev_view_get_link_at_location (view, x, y);
2629         if (!link)
2630                 return FALSE;
2631
2632         text = tip_from_link (view, link);
2633         if (text && g_utf8_validate (text, -1, NULL)) {
2634                 GdkRectangle link_area;
2635
2636                 get_link_area (view, x, y, link, &link_area);
2637                 gtk_tooltip_set_text (tooltip, text);
2638                 gtk_tooltip_set_tip_area (tooltip, &link_area);
2639         }
2640         g_free (text);
2641
2642         return TRUE;
2643 }
2644 #endif /* GTK_CHECK_VERSION (2, 11, 7) */
2645
2646 static void
2647 start_selection_for_event (EvView         *view,
2648                            GdkEventButton *event)
2649 {
2650         EvSelectionStyle style;
2651
2652         clear_selection (view);
2653         
2654         view->selection_info.start.x = event->x + view->scroll_x;
2655         view->selection_info.start.y = event->y + view->scroll_y;
2656
2657         switch (event->type) {
2658                 case GDK_2BUTTON_PRESS:
2659                         style = EV_SELECTION_STYLE_WORD;
2660                         break;
2661                 case GDK_3BUTTON_PRESS:
2662                         style = EV_SELECTION_STYLE_LINE;
2663                         break;
2664                 default:
2665                         style = EV_SELECTION_STYLE_GLYPH;
2666                         break;
2667         }
2668
2669         view->selection_info.style = style;
2670 }
2671
2672 static gboolean
2673 ev_view_button_press_event (GtkWidget      *widget,
2674                             GdkEventButton *event)
2675 {
2676         EvView *view = EV_VIEW (widget);
2677
2678         if (!view->document)
2679                 return FALSE;
2680         
2681         if (!GTK_WIDGET_HAS_FOCUS (widget)) {
2682                 gtk_widget_grab_focus (widget);
2683         }
2684         
2685         view->pressed_button = event->button;
2686         view->selection_info.in_drag = FALSE;
2687
2688         if (view->scroll_info.autoscrolling)
2689                 return TRUE;
2690         
2691         switch (event->button) {
2692                 case 1: {
2693                         EvImage *image;
2694                         EvFormField *field;
2695
2696                         if (EV_IS_SELECTION (view->document) && view->selection_info.selections) {
2697                                 if (event->type == GDK_3BUTTON_PRESS) {
2698                                         start_selection_for_event (view, event);
2699                                 } else if (location_in_selected_text (view,
2700                                                                event->x + view->scroll_x,
2701                                                                event->y + view->scroll_y)) {
2702                                         view->selection_info.in_drag = TRUE;
2703                                 } else {
2704                                         start_selection_for_event (view, event);
2705                                 }
2706
2707                                 gtk_widget_queue_draw (widget);
2708                         } else if ((field = ev_view_get_form_field_at_location (view, event->x, event->y))) {
2709                                 ev_view_remove_all (view);
2710                                 ev_view_handle_form_field (view, field, event->x, event->y);
2711                         } else if (!location_in_text (view, event->x + view->scroll_x, event->y + view->scroll_y) &&
2712                                    (image = ev_view_get_image_at_location (view, event->x, event->y))) {
2713                                 if (view->image_dnd_info.image)
2714                                         g_object_unref (view->image_dnd_info.image);
2715                                 view->image_dnd_info.image = g_object_ref (image);
2716                                 view->image_dnd_info.in_drag = TRUE;
2717
2718                                 view->image_dnd_info.start.x = event->x + view->scroll_x;
2719                                 view->image_dnd_info.start.y = event->y + view->scroll_y;
2720                         } else {
2721                                 ev_view_remove_all (view);
2722                                 
2723                                 if (EV_IS_SELECTION (view->document))
2724                                         start_selection_for_event (view, event);
2725                         }
2726                 }                       
2727                         return TRUE;
2728                 case 2:
2729                         /* use root coordinates as reference point because
2730                          * scrolling changes window relative coordinates */
2731                         view->drag_info.start.x = event->x_root;
2732                         view->drag_info.start.y = event->y_root;
2733                         view->drag_info.hadj = gtk_adjustment_get_value (view->hadjustment);
2734                         view->drag_info.vadj = gtk_adjustment_get_value (view->vadjustment);
2735
2736                         ev_view_set_cursor (view, EV_VIEW_CURSOR_DRAG);
2737
2738                         return TRUE;
2739                 case 3:
2740                         view->scroll_info.start_y = event->y;
2741                         return ev_view_do_popup_menu (view, event->x, event->y);
2742         }
2743         
2744         return FALSE;
2745 }
2746
2747 static void
2748 ev_view_remove_all (EvView *view)
2749 {
2750         GList *children, *child;
2751
2752         children = gtk_container_get_children (GTK_CONTAINER (view));
2753         for (child = children; child && child->data; child = g_list_next (child)) {
2754                 gtk_container_remove (GTK_CONTAINER (view),
2755                                       GTK_WIDGET (child->data));
2756         }
2757         g_list_free (children);
2758 }
2759
2760 /*** Drag and Drop ***/
2761 static void
2762 ev_view_drag_data_get (GtkWidget        *widget,
2763                        GdkDragContext   *context,
2764                        GtkSelectionData *selection_data,
2765                        guint             info,
2766                        guint             time)
2767 {
2768         EvView *view = EV_VIEW (widget);
2769
2770         switch (info) {
2771                 case TARGET_DND_TEXT:
2772                         if (EV_IS_SELECTION (view->document) &&
2773                             view->selection_info.selections) {
2774                                 gchar *text;
2775
2776                                 text = get_selected_text (view);
2777                                 gtk_selection_data_set_text (selection_data,
2778                                                              text,
2779                                                              strlen (text));
2780                                 g_free (text);
2781                         }
2782                         break;
2783                 case TARGET_DND_IMAGE:
2784                         if (view->image_dnd_info.image) {
2785                                 GdkPixbuf *pixbuf;
2786
2787                                 ev_document_doc_mutex_lock ();
2788                                 pixbuf = ev_document_images_get_image (EV_DOCUMENT_IMAGES (view->document),
2789                                                                        view->image_dnd_info.image);
2790                                 ev_document_doc_mutex_unlock ();
2791                                 
2792                                 gtk_selection_data_set_pixbuf (selection_data, pixbuf);
2793                                 g_object_unref (pixbuf);
2794                         }
2795                         break;
2796                 case TARGET_DND_URI:
2797                         if (view->image_dnd_info.image) {
2798                                 GdkPixbuf   *pixbuf;
2799                                 const gchar *tmp_uri;
2800                                 gchar      **uris;
2801
2802                                 ev_document_doc_mutex_lock ();
2803                                 pixbuf = ev_document_images_get_image (EV_DOCUMENT_IMAGES (view->document),
2804                                                                        view->image_dnd_info.image);
2805                                 ev_document_doc_mutex_unlock ();
2806                                 
2807                                 tmp_uri = ev_image_save_tmp (view->image_dnd_info.image, pixbuf);
2808                                 g_object_unref (pixbuf);
2809
2810                                 uris = g_new0 (gchar *, 2);
2811                                 uris[0] = (gchar *)tmp_uri;
2812                                 
2813                                 gtk_selection_data_set_uris (selection_data, uris);
2814
2815                                 /* g_free instead of g_strfreev since tmp_uri is const */ 
2816                                 g_free (uris);
2817                         }
2818         }
2819 }
2820
2821 static gboolean
2822 ev_view_drag_motion (GtkWidget      *widget,
2823                      GdkDragContext *context,
2824                      gint            x,
2825                      gint            y,
2826                      guint           time)
2827 {
2828         if (gtk_drag_get_source_widget (context) == widget)
2829                 gdk_drag_status (context, 0, time);
2830         else
2831                 gdk_drag_status (context, context->suggested_action, time);
2832         
2833         return TRUE;
2834 }
2835                      
2836 static void
2837 ev_view_drag_data_received (GtkWidget          *widget,
2838                             GdkDragContext     *context,
2839                             gint                x,
2840                             gint                y,
2841                             GtkSelectionData   *selection_data,
2842                             guint               info,
2843                             guint               time)
2844 {
2845         gchar  **uris;
2846         gint     i = 0;
2847         GSList  *uri_list = NULL;
2848
2849         uris = gtk_selection_data_get_uris (selection_data);
2850         if (!uris) {
2851                 gtk_drag_finish (context, FALSE, FALSE, time);
2852                 return;
2853         }
2854
2855         for (i = 0; uris[i]; i++) {
2856                 uri_list = g_slist_prepend (uri_list, (gpointer) uris[i]);
2857         }
2858         
2859         ev_application_open_uri_list (EV_APP, uri_list,
2860                                       gtk_widget_get_screen (widget),
2861                                       0);
2862         gtk_drag_finish (context, TRUE, FALSE, time);
2863         
2864         g_strfreev (uris);
2865         g_slist_free (uri_list);
2866 }
2867
2868
2869 static gboolean
2870 selection_update_idle_cb (EvView *view)
2871 {
2872         compute_selections (view,
2873                             view->selection_info.style,
2874                             &view->selection_info.start,
2875                             &view->motion);
2876         view->selection_update_id = 0;
2877         return FALSE;
2878 }
2879
2880 static gboolean
2881 selection_scroll_timeout_cb (EvView *view)
2882 {       
2883         gint x, y, shift = 0;
2884         GtkWidget *widget = GTK_WIDGET (view);
2885         
2886         gtk_widget_get_pointer (widget, &x, &y);
2887
2888         if (y > widget->allocation.height) {
2889                 shift = (y - widget->allocation.height) / 2;
2890         } else if (y < 0) {
2891                 shift = y / 2;
2892         }
2893
2894         if (shift)
2895                 gtk_adjustment_set_value (view->vadjustment,
2896                                           CLAMP (view->vadjustment->value + shift,
2897                                           view->vadjustment->lower,
2898                                           view->vadjustment->upper -
2899                                           view->vadjustment->page_size));       
2900
2901         if (x > widget->allocation.width) {
2902                 shift = (x - widget->allocation.width) / 2;
2903         } else if (x < 0) {
2904                 shift = x / 2;
2905         }
2906
2907         if (shift)
2908                 gtk_adjustment_set_value (view->hadjustment,
2909                                           CLAMP (view->hadjustment->value + shift,
2910                                           view->hadjustment->lower,
2911                                           view->hadjustment->upper -
2912                                           view->hadjustment->page_size));       
2913
2914         return TRUE;
2915 }
2916
2917 static gboolean
2918 ev_view_drag_update_momentum (EvView *view)
2919 {
2920         int i;
2921         if (!view->drag_info.in_drag)
2922                 return FALSE;
2923         
2924         for (i = DRAG_HISTORY - 1; i > 0; i--) {
2925                 view->drag_info.buffer[i].x = view->drag_info.buffer[i-1].x;
2926                 view->drag_info.buffer[i].y = view->drag_info.buffer[i-1].y;
2927         }
2928
2929         /* Momentum is a moving average of 10ms granularity over
2930          * the last 100ms with each 10ms stored in buffer. 
2931          */
2932         
2933         view->drag_info.momentum.x = (view->drag_info.buffer[DRAG_HISTORY - 1].x - view->drag_info.buffer[0].x);
2934         view->drag_info.momentum.y = (view->drag_info.buffer[DRAG_HISTORY - 1].y - view->drag_info.buffer[0].y);
2935
2936         return TRUE;
2937 }
2938
2939 static gboolean
2940 ev_view_scroll_drag_release (EvView *view)
2941 {
2942         gdouble dhadj_value, dvadj_value;
2943         gdouble oldhadjustment, oldvadjustment;
2944
2945         view->drag_info.momentum.x /= 1.2;
2946         view->drag_info.momentum.y /= 1.2; /* Alter these constants to change "friction" */
2947
2948         dhadj_value = view->hadjustment->page_size *
2949                       (gdouble)view->drag_info.momentum.x / GTK_WIDGET (view)->allocation.width;
2950         dvadj_value = view->vadjustment->page_size *
2951                       (gdouble)view->drag_info.momentum.y / GTK_WIDGET (view)->allocation.height;
2952
2953         oldhadjustment = gtk_adjustment_get_value (view->hadjustment);
2954         oldvadjustment = gtk_adjustment_get_value (view->vadjustment);
2955
2956         if (((oldhadjustment + dhadj_value) > (view->hadjustment->upper - view->hadjustment->page_size)) ||
2957            ((oldhadjustment + dhadj_value) < 0))
2958                 view->drag_info.momentum.x *= -0.5; /* 0.5 rather than 1 means the edges absorb some momentum */
2959         if (((oldvadjustment + dvadj_value) > (view->vadjustment->upper - view->vadjustment->page_size)) ||
2960            ((oldvadjustment + dvadj_value) < 0))
2961                 view->drag_info.momentum.y *= -0.5;
2962
2963         gtk_adjustment_set_value (view->hadjustment,
2964                                 MIN (oldhadjustment + dhadj_value,
2965                                 view->hadjustment->upper - view->hadjustment->page_size));
2966         gtk_adjustment_set_value (view->vadjustment,
2967                                 MIN (oldvadjustment + dvadj_value,
2968                                 view->vadjustment->upper - view->vadjustment->page_size));
2969
2970         if (((view->drag_info.momentum.x < 1) && (view->drag_info.momentum.x > -1)) &&
2971            ((view->drag_info.momentum.y < 1) && (view->drag_info.momentum.y > -1)))
2972                 return FALSE;
2973         else
2974                 return TRUE;
2975 }
2976
2977 static gboolean
2978 ev_view_motion_notify_event (GtkWidget      *widget,
2979                              GdkEventMotion *event)
2980 {
2981         EvView *view = EV_VIEW (widget);
2982         gint x, y;
2983
2984         if (!view->document)
2985                 return FALSE;
2986         
2987                 
2988         if (event->is_hint || event->window != view->layout.bin_window) {
2989             gtk_widget_get_pointer (widget, &x, &y);
2990         } else {
2991             x = event->x;
2992             y = event->y;
2993         }
2994
2995         if (view->scroll_info.autoscrolling) {
2996                 view->scroll_info.last_y = y;
2997                 return TRUE;
2998         }
2999
3000         if (view->selection_info.in_drag) {
3001                 if (gtk_drag_check_threshold (widget,
3002                                               view->selection_info.start.x,
3003                                               view->selection_info.start.y,
3004                                               x, y)) {
3005                         GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
3006
3007                         gtk_target_list_add_text_targets (target_list, TARGET_DND_TEXT);
3008
3009                         gtk_drag_begin (widget, target_list,
3010                                         GDK_ACTION_COPY,
3011                                         1, (GdkEvent *)event);
3012
3013                         view->selection_info.in_drag = FALSE;
3014
3015                         gtk_target_list_unref (target_list);
3016
3017                         return TRUE;
3018                 }
3019         } else if (view->image_dnd_info.in_drag) {
3020                 if (gtk_drag_check_threshold (widget,
3021                                               view->selection_info.start.x,
3022                                               view->selection_info.start.y,
3023                                               x, y)) {
3024                         GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
3025
3026                         gtk_target_list_add_uri_targets (target_list, TARGET_DND_URI);
3027                         gtk_target_list_add_image_targets (target_list, TARGET_DND_IMAGE, TRUE);
3028
3029                         gtk_drag_begin (widget, target_list,
3030                                         GDK_ACTION_COPY,
3031                                         1, (GdkEvent *)event);
3032
3033                         view->image_dnd_info.in_drag = FALSE;
3034
3035                         gtk_target_list_unref (target_list);
3036
3037                         return TRUE;
3038                 }
3039         }
3040         
3041         switch (view->pressed_button) {
3042         case 1:
3043                 /* For the Evince 0.4.x release, we limit selection to un-rotated
3044                  * documents only.
3045                  */
3046                 if (view->rotation != 0)
3047                         return FALSE;
3048
3049                 /* Schedule timeout to scroll during selection and additionally 
3050                  * scroll once to allow arbitrary speed. */
3051                 if (!view->selection_scroll_id)
3052                     view->selection_scroll_id = g_timeout_add (SCROLL_TIME,
3053                                                                (GSourceFunc)selection_scroll_timeout_cb,
3054                                                                view);
3055                 else 
3056                     selection_scroll_timeout_cb (view);
3057
3058                 view->selection_info.in_selection = TRUE;
3059                 view->motion.x = x + view->scroll_x;
3060                 view->motion.y = y + view->scroll_y;
3061
3062                 /* Queue an idle to handle the motion.  We do this because      
3063                  * handling any selection events in the motion could be slower  
3064                  * than new motion events reach us.  We always put it in the    
3065                  * idle to make sure we catch up and don't visibly lag the      
3066                  * mouse. */
3067                 if (!view->selection_update_id)
3068                         view->selection_update_id = g_idle_add ((GSourceFunc)selection_update_idle_cb, view);
3069
3070                 return TRUE;
3071         case 2:
3072                 if (!view->drag_info.in_drag) {
3073                         gboolean start;
3074                         int i;
3075
3076                         start = gtk_drag_check_threshold (widget,
3077                                                           view->drag_info.start.x,
3078                                                           view->drag_info.start.y,
3079                                                           event->x_root,
3080                                                           event->y_root);
3081                         view->drag_info.in_drag = start;
3082                         view->drag_info.drag_timeout_id = g_timeout_add (10,
3083                                 (GSourceFunc)ev_view_drag_update_momentum, view);
3084                         /* Set 100 to choose how long it takes to build up momentum */
3085                         /* Clear out previous momentum info: */
3086                         for (i = 0; i < DRAG_HISTORY; i++) {
3087                                 view->drag_info.buffer[i].x = event->x;
3088                                 view->drag_info.buffer[i].y = event->y;
3089                         }
3090                         view->drag_info.momentum.x = 0;
3091                         view->drag_info.momentum.y = 0;
3092                 }
3093
3094                 if (view->drag_info.in_drag) {
3095                         int dx, dy;
3096                         gdouble dhadj_value, dvadj_value;
3097
3098                         view->drag_info.buffer[0].x = event->x;
3099                         view->drag_info.buffer[0].y = event->y;
3100
3101                         dx = event->x_root - view->drag_info.start.x;
3102                         dy = event->y_root - view->drag_info.start.y;
3103
3104                         dhadj_value = view->hadjustment->page_size *
3105                                       (gdouble)dx / widget->allocation.width;
3106                         dvadj_value = view->vadjustment->page_size *
3107                                       (gdouble)dy / widget->allocation.height;
3108
3109                         /* clamp scrolling to visible area */
3110                         gtk_adjustment_set_value (view->hadjustment,
3111                                                   MIN(view->drag_info.hadj - dhadj_value,
3112                                                       view->hadjustment->upper -
3113                                                       view->hadjustment->page_size));
3114                         gtk_adjustment_set_value (view->vadjustment,
3115                                                   MIN(view->drag_info.vadj - dvadj_value,
3116                                                       view->vadjustment->upper -
3117                                                       view->vadjustment->page_size));
3118
3119                         return TRUE;
3120                 }
3121
3122                 break;
3123         default:
3124                 ev_view_handle_cursor_over_xy (view, x, y);
3125         } 
3126
3127         return FALSE;
3128 }
3129
3130 static gboolean
3131 ev_view_button_release_event (GtkWidget      *widget,
3132                               GdkEventButton *event)
3133 {
3134         EvView *view = EV_VIEW (widget);
3135         EvLink *link = NULL;
3136
3137         view->image_dnd_info.in_drag = FALSE;
3138
3139         if (view->scroll_info.autoscrolling) {
3140                 ev_view_autoscroll_stop (view);
3141                 view->pressed_button = -1;
3142
3143                 return TRUE;
3144         } 
3145
3146         if (view->drag_info.in_drag) {
3147                 view->drag_info.release_timeout_id =
3148                         g_timeout_add (20,
3149                                        (GSourceFunc)ev_view_scroll_drag_release, view);
3150         }
3151
3152         if (view->document && !view->drag_info.in_drag && view->pressed_button != 3) {
3153                 link = ev_view_get_link_at_location (view, event->x, event->y);
3154         }
3155         
3156         view->drag_info.in_drag = FALSE;
3157
3158         if (view->pressed_button == 2) {
3159                 ev_view_handle_cursor_over_xy (view, event->x, event->y);
3160         }
3161
3162         view->pressed_button = -1;
3163
3164         if (view->selection_scroll_id) {
3165             g_source_remove (view->selection_scroll_id);
3166             view->selection_scroll_id = 0;
3167         }
3168         if (view->selection_update_id) {
3169             g_source_remove (view->selection_update_id);
3170             view->selection_update_id = 0;
3171         }
3172
3173         if (!view->selection_info.in_selection &&
3174             view->selection_info.style != EV_SELECTION_STYLE_GLYPH) {
3175                 compute_selections (view,
3176                                     view->selection_info.style,
3177                                     &(view->selection_info.start),
3178                                     &(view->selection_info.start));
3179         }
3180
3181         if (view->selection_info.selections) {
3182                 clear_link_selected (view);
3183                 ev_view_update_primary_selection (view);
3184                 
3185                 if (view->selection_info.in_drag) {
3186                         clear_selection (view);
3187                         gtk_widget_queue_draw (widget);
3188                 }
3189                 
3190                 view->selection_info.in_drag = FALSE;
3191         } else if (link) {
3192                 if (event->button == 2) {
3193                         EvLinkAction    *action;
3194                         EvLinkActionType type;
3195
3196                         action = ev_link_get_action (link);
3197                         if (!action)
3198                                 return FALSE;
3199
3200                         type = ev_link_action_get_action_type (action);
3201                         if (type == EV_LINK_ACTION_TYPE_GOTO_DEST) {
3202                                 g_signal_emit (view,
3203                                                signals[SIGNAL_EXTERNAL_LINK],
3204                                                0, action);
3205                         }
3206                 } else {
3207                         ev_view_handle_link (view, link);
3208                 }
3209         } else if (view->presentation) {
3210                 switch (event->button) {
3211                         case 1:
3212                                 ev_view_next_page (view);       
3213                                 return TRUE;
3214                         case 3:
3215                                 ev_view_previous_page (view);   
3216                                 return TRUE;
3217                 }
3218         }
3219  
3220         return FALSE;
3221 }
3222
3223 /* Goto Window */
3224 /* Cut and paste from gtkwindow.c */
3225 static void
3226 send_focus_change (GtkWidget *widget,
3227                    gboolean   in)
3228 {
3229         GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
3230
3231         g_object_ref (widget);
3232
3233         if (in)
3234                 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
3235         else
3236                 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
3237
3238         fevent->focus_change.type = GDK_FOCUS_CHANGE;
3239         fevent->focus_change.window = g_object_ref (widget->window);
3240         fevent->focus_change.in = in;
3241
3242         gtk_widget_event (widget, fevent);
3243
3244         g_object_notify (G_OBJECT (widget), "has-focus");
3245
3246         g_object_unref (widget);
3247         gdk_event_free (fevent);
3248 }
3249
3250 static void
3251 ev_view_goto_window_hide (EvView *view)
3252 {
3253         /* send focus-in event */
3254         send_focus_change (view->goto_entry, FALSE);
3255         gtk_widget_hide (view->goto_window);
3256         gtk_entry_set_text (GTK_ENTRY (view->goto_entry), "");
3257 }
3258
3259 static gboolean
3260 ev_view_goto_window_delete_event (GtkWidget   *widget,
3261                                   GdkEventAny *event,
3262                                   EvView      *view)
3263 {
3264         ev_view_goto_window_hide (view);
3265
3266         return TRUE;
3267 }
3268
3269 static gboolean
3270 key_is_numeric (guint keyval)
3271 {
3272         return ((keyval >= GDK_0 && keyval <= GDK_9) ||
3273                 (keyval >= GDK_KP_0 && keyval <= GDK_KP_9));
3274 }
3275
3276 static gboolean
3277 ev_view_goto_window_key_press_event (GtkWidget   *widget,
3278                                      GdkEventKey *event,
3279                                      EvView      *view)
3280 {
3281         switch (event->keyval) {
3282                 case GDK_Escape:
3283                 case GDK_Tab:
3284                 case GDK_KP_Tab:
3285                 case GDK_ISO_Left_Tab:
3286                         ev_view_goto_window_hide (view);
3287                         return TRUE;
3288                 case GDK_Return:
3289                 case GDK_KP_Enter:
3290                 case GDK_ISO_Enter:
3291                 case GDK_BackSpace:
3292                 case GDK_Delete:
3293                         return FALSE;
3294                 default:
3295                         if (!key_is_numeric (event->keyval))
3296                                 return TRUE;
3297         }
3298
3299         return FALSE;
3300 }
3301
3302 static gboolean
3303 ev_view_goto_window_button_press_event (GtkWidget      *widget,
3304                                         GdkEventButton *event,
3305                                         EvView         *view)
3306 {
3307         ev_view_goto_window_hide (view);
3308
3309         return TRUE;
3310 }
3311
3312 static void
3313 ev_view_goto_entry_activate (GtkEntry *entry,
3314                              EvView   *view)
3315 {
3316         const gchar *text;
3317         gint         page;
3318
3319         text = gtk_entry_get_text (entry);
3320         page = atoi (text) - 1;
3321         
3322         ev_view_goto_window_hide (view);
3323
3324         if (page >= 0 &&
3325             page < ev_page_cache_get_n_pages (view->page_cache))
3326                 ev_page_cache_set_current_page (view->page_cache, page);
3327 }
3328
3329 static void
3330 ev_view_goto_window_create (EvView *view)
3331 {
3332         GtkWidget *frame, *hbox, *toplevel, *label;
3333
3334         toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view));
3335         
3336         if (view->goto_window) {
3337                 if (GTK_WINDOW (toplevel)->group)
3338                         gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
3339                                                      GTK_WINDOW (view->goto_window));
3340                 else if (GTK_WINDOW (view->goto_window)->group)
3341                         gtk_window_group_remove_window (GTK_WINDOW (view->goto_window)->group,
3342                                                         GTK_WINDOW (view->goto_window));
3343                 return;
3344         }
3345
3346         view->goto_window = gtk_window_new (GTK_WINDOW_POPUP);
3347
3348         if (GTK_WINDOW (toplevel)->group)
3349                 gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
3350                                              GTK_WINDOW (view->goto_window));
3351         
3352         gtk_window_set_modal (GTK_WINDOW (view->goto_window), TRUE);
3353
3354         g_signal_connect (view->goto_window, "delete_event",
3355                           G_CALLBACK (ev_view_goto_window_delete_event),
3356                           view);
3357         g_signal_connect (view->goto_window, "key_press_event",
3358                           G_CALLBACK (ev_view_goto_window_key_press_event),
3359                           view);
3360         g_signal_connect (view->goto_window, "button_press_event",
3361                           G_CALLBACK (ev_view_goto_window_button_press_event),
3362                           view);
3363
3364         frame = gtk_frame_new (NULL);
3365         gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
3366         gtk_container_add (GTK_CONTAINER (view->goto_window), frame);
3367         gtk_widget_show (frame);
3368
3369         hbox = gtk_hbox_new (FALSE, 0);
3370         gtk_container_set_border_width (GTK_CONTAINER (hbox), 3);
3371         gtk_container_add (GTK_CONTAINER (frame), hbox);
3372         gtk_widget_show (hbox);
3373
3374         label = gtk_label_new(_("Jump to page:"));
3375         gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 3);
3376         gtk_widget_show (label);
3377         gtk_widget_realize (label);
3378
3379         view->goto_entry = gtk_entry_new ();
3380         g_signal_connect (view->goto_entry, "activate",
3381                           G_CALLBACK (ev_view_goto_entry_activate),
3382                           view);
3383         gtk_box_pack_start (GTK_BOX (hbox), view->goto_entry, TRUE, TRUE, 0);
3384         gtk_widget_show (view->goto_entry);
3385         gtk_widget_realize (view->goto_entry);
3386 }
3387
3388 static void
3389 ev_view_goto_entry_grab_focus (EvView *view)
3390 {
3391         GtkWidgetClass *entry_parent_class;
3392         
3393         entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (view->goto_entry));
3394         (entry_parent_class->grab_focus) (view->goto_entry);
3395
3396         send_focus_change (view->goto_entry, TRUE);
3397 }
3398
3399 static void
3400 ev_view_goto_window_send_key_event (EvView   *view,
3401                                     GdkEvent *event)
3402 {
3403         GdkEventKey *new_event;
3404         GdkScreen   *screen;
3405
3406         /* Move goto window off screen */
3407         screen = gtk_widget_get_screen (GTK_WIDGET (view));
3408         gtk_window_move (GTK_WINDOW (view->goto_window),
3409                          gdk_screen_get_width (screen) + 1,
3410                          gdk_screen_get_height (screen) + 1);
3411         gtk_widget_show (view->goto_window);
3412
3413         new_event = (GdkEventKey *) gdk_event_copy (event);
3414         g_object_unref (new_event->window);
3415         new_event->window = g_object_ref (view->goto_window->window);
3416         gtk_widget_realize (view->goto_window);
3417
3418         gtk_widget_event (view->goto_window, (GdkEvent *)new_event);
3419         gdk_event_free ((GdkEvent *)new_event);
3420         gtk_widget_hide (view->goto_window);
3421 }
3422
3423 static gboolean
3424 ev_view_key_press_event (GtkWidget   *widget,
3425                          GdkEventKey *event)
3426 {
3427         EvView *view = EV_VIEW (widget);
3428         EvPresentationState current;
3429
3430         if (!view->document)
3431                 return FALSE;
3432         
3433         if (!view->presentation ||
3434             view->presentation_state == EV_PRESENTATION_END)
3435                 return gtk_bindings_activate_event (GTK_OBJECT (widget), event);
3436
3437
3438         current = view->presentation_state;
3439
3440         switch (event->keyval) {
3441                 case GDK_b:
3442                 case GDK_B:
3443                 case GDK_period:
3444                 case GDK_KP_Decimal:
3445                         view->presentation_state =
3446                                 (view->presentation_state == EV_PRESENTATION_BLACK) ?
3447                                 EV_PRESENTATION_NORMAL : EV_PRESENTATION_BLACK;
3448                         break;
3449                 case GDK_w:
3450                 case GDK_W:
3451                         view->presentation_state =
3452                                 (view->presentation_state == EV_PRESENTATION_WHITE) ?
3453                                 EV_PRESENTATION_NORMAL : EV_PRESENTATION_WHITE;
3454                         break;
3455                 default:
3456                         if (view->presentation_state == EV_PRESENTATION_BLACK ||
3457                             view->presentation_state == EV_PRESENTATION_WHITE) {
3458                                 view->presentation_state = EV_PRESENTATION_NORMAL;
3459                         }
3460         }
3461
3462         if (current == view->presentation_state) {
3463                 if (ev_page_cache_get_n_pages (view->page_cache) > 1 &&
3464                     key_is_numeric (event->keyval)) {
3465                         gint x, y;
3466                         
3467                         ev_view_goto_window_create (view);
3468                         ev_view_goto_window_send_key_event (view, (GdkEvent *)event);
3469                         gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
3470                         gtk_window_move (GTK_WINDOW (view->goto_window), x, y);
3471                         gtk_widget_show (view->goto_window);
3472                         ev_view_goto_entry_grab_focus (view);
3473                         
3474                         return TRUE;
3475                 }
3476                 
3477                 return gtk_bindings_activate_event (GTK_OBJECT (widget), event);
3478         }
3479
3480         switch (view->presentation_state) {
3481                 case EV_PRESENTATION_NORMAL:
3482                 case EV_PRESENTATION_BLACK:
3483                         gdk_window_set_background (view->layout.bin_window,
3484                                                    &widget->style->black);
3485                         break;
3486                 case EV_PRESENTATION_WHITE:
3487                         gdk_window_set_background (view->layout.bin_window,
3488                                                    &widget->style->white);
3489                         break;
3490                 default:
3491                         return gtk_bindings_activate_event (GTK_OBJECT (widget), event);
3492         }
3493
3494         gtk_widget_queue_draw (widget);
3495         return TRUE;
3496 }
3497
3498 static gint
3499 ev_view_focus_in (GtkWidget     *widget,
3500                   GdkEventFocus *event)
3501 {
3502         if (EV_VIEW (widget)->pixbuf_cache)
3503                 ev_pixbuf_cache_style_changed (EV_VIEW (widget)->pixbuf_cache);
3504         gtk_widget_queue_draw (widget);
3505
3506         return FALSE;
3507 }
3508
3509 static gint
3510 ev_view_focus_out (GtkWidget     *widget,
3511                      GdkEventFocus *event)
3512 {
3513         if (EV_VIEW (widget)->goto_window)
3514                 ev_view_goto_window_hide (EV_VIEW (widget));
3515         
3516         if (EV_VIEW (widget)->pixbuf_cache)
3517                 ev_pixbuf_cache_style_changed (EV_VIEW (widget)->pixbuf_cache);
3518         gtk_widget_queue_draw (widget);
3519
3520         return FALSE;
3521 }
3522
3523 static gboolean
3524 ev_view_leave_notify_event (GtkWidget *widget, GdkEventCrossing   *event)
3525 {
3526         EvView *view = EV_VIEW (widget);
3527
3528         if (view->cursor != EV_VIEW_CURSOR_NORMAL)
3529                 ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
3530
3531 #if !GTK_CHECK_VERSION (2, 11, 7)
3532         if (view->link_tooltip) {
3533                 view->hovered_link = NULL;
3534                 ev_tooltip_deactivate (EV_TOOLTIP (view->link_tooltip));
3535         }
3536 #endif
3537         
3538         return FALSE;
3539 }
3540
3541 static gboolean
3542 ev_view_enter_notify_event (GtkWidget *widget, GdkEventCrossing   *event)
3543 {
3544         EvView *view = EV_VIEW (widget);
3545
3546         ev_view_handle_cursor_over_xy (view, event->x, event->y);
3547     
3548         return FALSE;
3549 }
3550
3551 static void
3552 ev_view_style_set (GtkWidget *widget,
3553                    GtkStyle  *old_style)
3554 {
3555         if (EV_VIEW (widget)->pixbuf_cache)
3556                 ev_pixbuf_cache_style_changed (EV_VIEW (widget)->pixbuf_cache);
3557
3558         GTK_WIDGET_CLASS (ev_view_parent_class)->style_set (widget, old_style);
3559 }
3560
3561 /*** Drawing ***/
3562
3563 static guint32
3564 ev_gdk_color_to_rgb (const GdkColor *color)
3565 {
3566   guint32 result;
3567   result = (0xff0000 | (color->red & 0xff00));
3568   result <<= 8;
3569   result |= ((color->green & 0xff00) | (color->blue >> 8));
3570   return result;
3571 }
3572
3573 static void
3574 draw_rubberband (GtkWidget *widget, GdkWindow *window,
3575                  const GdkRectangle *rect, guchar alpha)
3576 {
3577         GdkGC *gc;
3578         GdkPixbuf *pixbuf;
3579         GdkColor *fill_color_gdk;
3580         guint fill_color;
3581
3582         fill_color_gdk = gdk_color_copy (&GTK_WIDGET (widget)->style->base[GTK_STATE_SELECTED]);
3583         fill_color = ev_gdk_color_to_rgb (fill_color_gdk) << 8 | alpha;
3584
3585         pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
3586                                  rect->width, rect->height);
3587         gdk_pixbuf_fill (pixbuf, fill_color);
3588
3589         gdk_draw_pixbuf (window, NULL, pixbuf,
3590                          0, 0,
3591                          rect->x - EV_VIEW (widget)->scroll_x, rect->y - EV_VIEW (widget)->scroll_y,
3592                          rect->width, rect->height,
3593                          GDK_RGB_DITHER_NONE,
3594                          0, 0);
3595
3596         g_object_unref (pixbuf);
3597
3598         gc = gdk_gc_new (window);
3599         gdk_gc_set_rgb_fg_color (gc, fill_color_gdk);
3600         gdk_draw_rectangle (window, gc, FALSE,
3601                             rect->x - EV_VIEW (widget)->scroll_x, rect->y - EV_VIEW (widget)->scroll_y,
3602                             rect->width - 1,
3603                             rect->height - 1);
3604         g_object_unref (gc);
3605
3606         gdk_color_free (fill_color_gdk);
3607 }
3608
3609
3610 static void
3611 highlight_find_results (EvView *view, int page)
3612 {
3613         gint i, n_results = 0;
3614
3615         n_results = ev_view_find_get_n_results (view, page);
3616
3617         for (i = 0; i < n_results; i++) {
3618                 EvRectangle *rectangle;
3619                 GdkRectangle view_rectangle;
3620                 guchar alpha;
3621
3622                 if (i == view->find_result && page == view->current_page) {
3623                         alpha = 0x90;
3624                 } else {
3625                         alpha = 0x20;
3626                 }
3627
3628                 rectangle = ev_view_find_get_result (view, page, i);
3629                 doc_rect_to_view_rect (view, page, rectangle, &view_rectangle);
3630                 draw_rubberband (GTK_WIDGET (view), view->layout.bin_window,
3631                                  &view_rectangle, alpha);
3632         }
3633 }
3634
3635 static void
3636 draw_loading_text (EvView       *view,
3637                    GdkRectangle *page_area,
3638                    GdkRectangle *expose_area)
3639 {
3640         cairo_t *cr;
3641         gint     width, height;
3642
3643         if (!view->loading_text) {
3644                 const gchar *loading_text = _("Loading...");
3645                 PangoLayout *layout;
3646                 PangoFontDescription *font_desc;
3647                 PangoRectangle logical_rect;
3648                 gint target_width;
3649                 gdouble real_scale;
3650
3651                 ev_document_fc_mutex_lock ();
3652
3653                 layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), loading_text);
3654                 
3655                 font_desc = pango_font_description_new ();
3656                 
3657                 /* We set the font to be 10 points, get the size, and scale appropriately */
3658                 pango_font_description_set_size (font_desc, 10 * PANGO_SCALE);
3659                 pango_layout_set_font_description (layout, font_desc);
3660                 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
3661
3662                 target_width = MAX (page_area->width / 2, 1);
3663                 real_scale = ((double)target_width / (double) logical_rect.width) * (PANGO_SCALE * 10);
3664                 pango_font_description_set_size (font_desc, (int)real_scale);
3665                 pango_layout_set_font_description (layout, font_desc);
3666                 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
3667
3668                 view->loading_text = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
3669                                                                  logical_rect.width,
3670                                                                  logical_rect.height);
3671                 cr = cairo_create (view->loading_text);
3672                 cairo_set_source_rgb (cr,
3673                                       155 / (double)255,
3674                                       155 / (double)255,
3675                                       155 / (double)255);
3676                 pango_cairo_show_layout (cr, layout);
3677                 cairo_destroy (cr);
3678
3679                 pango_font_description_free (font_desc);
3680                 g_object_unref (layout);
3681
3682                 ev_document_fc_mutex_unlock ();
3683         }
3684
3685         width = (page_area->width - cairo_image_surface_get_width (view->loading_text)) / 2;
3686         height = (page_area->height - cairo_image_surface_get_height (view->loading_text)) / 2;
3687         
3688         cr = gdk_cairo_create (view->layout.bin_window);
3689         cairo_translate (cr,
3690                          page_area->x + width,
3691                          page_area->y + height);
3692         cairo_set_source_surface (cr, view->loading_text, 0, 0);
3693         cairo_paint (cr);
3694         cairo_destroy (cr);
3695 }
3696
3697 static void
3698 draw_one_page (EvView       *view,
3699                gint          page,
3700                cairo_t      *cr,
3701                GdkRectangle *page_area,
3702                GtkBorder    *border,
3703                GdkRectangle *expose_area,
3704                gboolean     *page_ready)
3705 {
3706         GdkRectangle overlap;
3707         GdkRectangle real_page_area;
3708
3709         g_assert (view->document);
3710
3711         if (! gdk_rectangle_intersect (page_area, expose_area, &overlap))
3712                 return;
3713
3714         /* Render the document itself */
3715         real_page_area = *page_area;
3716
3717         real_page_area.x += border->left;
3718         real_page_area.y += border->top;
3719         real_page_area.width -= (border->left + border->right);
3720         real_page_area.height -= (border->top + border->bottom);
3721         *page_ready = TRUE;
3722
3723         if (!view->presentation) {
3724                 gint current_page;
3725                 
3726                 current_page = ev_page_cache_get_current_page (view->page_cache);
3727                 ev_document_misc_paint_one_page (view->layout.bin_window,
3728                                                  GTK_WIDGET (view),
3729                                                  page_area, border, 
3730                                                  page == current_page);
3731         }
3732
3733         if (gdk_rectangle_intersect (&real_page_area, expose_area, &overlap)) {
3734                 gint             width, height;
3735                 gint             page_width, page_height;
3736                 cairo_surface_t *page_surface = NULL;
3737                 gint             selection_width, selection_height;
3738                 cairo_surface_t *selection_surface = NULL;
3739
3740                 page_surface = ev_pixbuf_cache_get_surface (view->pixbuf_cache, page);
3741
3742                 if (!page_surface) {
3743                         if (!view->presentation) {
3744                                 draw_loading_text (view,
3745                                                    &real_page_area,
3746                                                    expose_area);
3747                         }
3748
3749                         *page_ready = FALSE;
3750
3751                         return;
3752                 }
3753
3754                 ev_page_cache_get_size (view->page_cache,
3755                                         page, view->rotation,
3756                                         view->scale,
3757                                         &width, &height);
3758
3759                 page_width = cairo_image_surface_get_width (page_surface);
3760                 page_height = cairo_image_surface_get_height (page_surface);
3761
3762                 cairo_save (cr);
3763                 cairo_translate (cr, overlap.x, overlap.y);
3764
3765                 if (width != page_width || height != page_height) {
3766                         cairo_pattern_set_filter (cairo_get_source (cr),
3767                                                   CAIRO_FILTER_FAST);
3768                         cairo_scale (cr,
3769                                      (gdouble)width / page_width,
3770                                      (gdouble)height / page_height);
3771                 }
3772
3773                 cairo_surface_set_device_offset (page_surface,
3774                                                  overlap.x - real_page_area.x,
3775                                                  overlap.y - real_page_area.y);
3776                 cairo_set_source_surface (cr, page_surface, 0, 0);
3777                 cairo_paint (cr);
3778                 cairo_restore (cr);
3779                 
3780                 /* Get the selection pixbuf iff we have something to draw */
3781                 if (find_selection_for_page (view, page) &&
3782                     view->selection_mode == EV_VIEW_SELECTION_TEXT) {
3783                         selection_surface =
3784                                 ev_pixbuf_cache_get_selection_surface (view->pixbuf_cache,
3785                                                                        page,
3786                                                                        view->scale,
3787                                                                        NULL);
3788                 }
3789
3790                 if (!selection_surface) {
3791                         return;
3792                 }
3793
3794                 selection_width = cairo_image_surface_get_width (selection_surface);
3795                 selection_height = cairo_image_surface_get_height (selection_surface);
3796
3797                 cairo_save (cr);
3798                 cairo_translate (cr, overlap.x, overlap.y);
3799
3800                 if (width != selection_width || height != selection_height) {
3801                         cairo_pattern_set_filter (cairo_get_source (cr),
3802                                                   CAIRO_FILTER_FAST);
3803                         cairo_scale (cr,
3804                                      (gdouble)width / selection_width,
3805                                      (gdouble)height / selection_height);
3806                 }
3807
3808                 cairo_surface_set_device_offset (selection_surface,
3809                                                  overlap.x - real_page_area.x,
3810                                                  overlap.y - real_page_area.y);
3811                 cairo_set_source_surface (cr, selection_surface, 0, 0);
3812                 cairo_paint (cr);
3813                 cairo_restore (cr);
3814         }
3815 }
3816
3817 /*** GObject functions ***/
3818
3819 static void
3820 ev_view_finalize (GObject *object)
3821 {
3822         EvView *view = EV_VIEW (object);
3823
3824         clear_selection (view);
3825         clear_link_selected (view);
3826
3827         if (view->image_dnd_info.image)
3828                 g_object_unref (view->image_dnd_info.image);
3829         view->image_dnd_info.image = NULL;
3830
3831         G_OBJECT_CLASS (ev_view_parent_class)->finalize (object);
3832 }
3833
3834 static void
3835 ev_view_destroy (GtkObject *object)
3836 {
3837         EvView *view = EV_VIEW (object);
3838
3839         if (view->document) {
3840                 g_object_unref (view->document);
3841                 view->document = NULL;
3842         }
3843
3844         if (view->pixbuf_cache) {
3845                 g_object_unref (view->pixbuf_cache);
3846                 view->pixbuf_cache = NULL;
3847         }
3848
3849 #if !GTK_CHECK_VERSION (2, 11, 7)
3850         if (view->link_tooltip) {
3851                 gtk_widget_destroy (view->link_tooltip);
3852                 view->link_tooltip = NULL;
3853         }
3854 #endif
3855         if (view->goto_window) {
3856                 gtk_widget_destroy (view->goto_window);
3857                 view->goto_window = NULL;
3858                 view->goto_entry = NULL;
3859         }
3860
3861         if (view->selection_scroll_id) {
3862             g_source_remove (view->selection_scroll_id);
3863             view->selection_scroll_id = 0;
3864         }
3865
3866         if (view->selection_update_id) {
3867             g_source_remove (view->selection_update_id);
3868             view->selection_update_id = 0;
3869         }
3870
3871         if (view->loading_text) {
3872                 cairo_surface_destroy (view->loading_text);
3873                 view->loading_text = NULL;
3874         }
3875
3876         if (view->scroll_info.timeout_id) {
3877             g_source_remove (view->scroll_info.timeout_id);
3878             view->scroll_info.timeout_id = 0;
3879         }
3880
3881         if (view->drag_info.drag_timeout_id) {
3882                 g_source_remove (view->drag_info.drag_timeout_id);
3883                 view->drag_info.drag_timeout_id = 0;
3884         }
3885
3886         if (view->drag_info.release_timeout_id) {
3887                 g_source_remove (view->drag_info.release_timeout_id);
3888                 view->drag_info.release_timeout_id = 0;
3889         }
3890
3891         ev_view_presentation_transition_stop (view);
3892
3893         ev_view_set_scroll_adjustments (GTK_LAYOUT (view), NULL, NULL);
3894
3895         GTK_OBJECT_CLASS (ev_view_parent_class)->destroy (object);
3896 }
3897
3898 static void
3899 ev_view_set_property (GObject      *object,
3900                       guint         prop_id,
3901                       const GValue *value,
3902                       GParamSpec   *pspec)
3903 {
3904         EvView *view = EV_VIEW (object);
3905
3906         switch (prop_id) {
3907                 case PROP_CONTINUOUS:
3908                         ev_view_set_continuous (view, g_value_get_boolean (value));
3909                         break;
3910                 case PROP_DUAL_PAGE:
3911                         ev_view_set_dual_page (view, g_value_get_boolean (value));
3912                         break;
3913                 case PROP_FULLSCREEN:
3914                         ev_view_set_fullscreen (view, g_value_get_boolean (value));
3915                         break;
3916                 case PROP_PRESENTATION:
3917                         ev_view_set_presentation (view, g_value_get_boolean (value));
3918                         break;
3919                 case PROP_SIZING_MODE:
3920                         ev_view_set_sizing_mode (view, g_value_get_enum (value));
3921                         break;
3922                 case PROP_ZOOM:
3923                         ev_view_set_zoom (view, g_value_get_double (value), FALSE);
3924                         break;
3925                 case PROP_ROTATION:
3926                         ev_view_set_rotation (view, g_value_get_int (value));
3927                         break;
3928                 default:
3929                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3930         }
3931 }
3932
3933 static AtkObject *
3934 ev_view_get_accessible (GtkWidget *widget)
3935 {
3936         static gboolean first_time = TRUE;
3937
3938         if (first_time) {
3939                 AtkObjectFactory *factory;
3940                 AtkRegistry *registry;
3941                 GType derived_type; 
3942                 GType derived_atk_type; 
3943
3944                 /*
3945                  * Figure out whether accessibility is enabled by looking at the
3946                  * type of the accessible object which would be created for
3947                  * the parent type of EvView.
3948                  */
3949                 derived_type = g_type_parent (EV_TYPE_VIEW);
3950
3951                 registry = atk_get_default_registry ();
3952                 factory = atk_registry_get_factory (registry,
3953                                                     derived_type);
3954                 derived_atk_type = atk_object_factory_get_accessible_type (factory);
3955                 if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE)) 
3956                         atk_registry_set_factory_type (registry, 
3957                                                        EV_TYPE_VIEW,
3958                                                        ev_view_accessible_factory_get_type ());
3959                 first_time = FALSE;
3960         } 
3961         return GTK_WIDGET_CLASS (ev_view_parent_class)->get_accessible (widget);
3962 }
3963
3964 static void
3965 ev_view_get_property (GObject *object,
3966                       guint prop_id,
3967                       GValue *value,
3968                       GParamSpec *pspec)
3969 {
3970         EvView *view = EV_VIEW (object);
3971
3972         switch (prop_id) {
3973                 case PROP_CONTINUOUS:
3974                         g_value_set_boolean (value, view->continuous);
3975                         break;
3976                 case PROP_DUAL_PAGE:
3977                         g_value_set_boolean (value, view->dual_page);
3978                         break;
3979                 case PROP_FULLSCREEN:
3980                         g_value_set_boolean (value, view->fullscreen);
3981                         break;
3982                 case PROP_PRESENTATION:
3983                         g_value_set_boolean (value, view->presentation);
3984                         break;
3985                 case PROP_SIZING_MODE:
3986                         g_value_set_enum (value, view->sizing_mode);
3987                         break;
3988                 case PROP_ZOOM:
3989                         g_value_set_double (value, view->scale);
3990                         break;
3991                 case PROP_ROTATION:
3992                         g_value_set_int (value, view->rotation);
3993                         break;
3994                 case PROP_HAS_SELECTION:
3995                         g_value_set_boolean (value,
3996                                              view->selection_info.selections != NULL);
3997                         break;
3998                 default:
3999                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4000         }
4001 }
4002
4003 static void
4004 ev_view_class_init (EvViewClass *class)
4005 {
4006         GObjectClass *object_class = G_OBJECT_CLASS (class);
4007         GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (class);
4008         GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
4009         GtkLayoutClass *layout_class = GTK_LAYOUT_CLASS (class);
4010         GtkBindingSet *binding_set;
4011
4012         object_class->finalize = ev_view_finalize;
4013         object_class->set_property = ev_view_set_property;
4014         object_class->get_property = ev_view_get_property;
4015
4016         widget_class->expose_event = ev_view_expose_event;
4017         widget_class->button_press_event = ev_view_button_press_event;
4018         widget_class->motion_notify_event = ev_view_motion_notify_event;
4019         widget_class->button_release_event = ev_view_button_release_event;
4020         widget_class->key_press_event = ev_view_key_press_event;
4021         widget_class->focus_in_event = ev_view_focus_in;
4022         widget_class->focus_out_event = ev_view_focus_out;
4023         widget_class->get_accessible = ev_view_get_accessible;
4024         widget_class->size_request = ev_view_size_request;
4025         widget_class->size_allocate = ev_view_size_allocate;
4026         widget_class->realize = ev_view_realize;
4027         widget_class->scroll_event = ev_view_scroll_event;
4028         widget_class->enter_notify_event = ev_view_enter_notify_event;
4029         widget_class->leave_notify_event = ev_view_leave_notify_event;
4030         widget_class->style_set = ev_view_style_set;
4031         widget_class->drag_data_get = ev_view_drag_data_get;
4032         widget_class->drag_motion = ev_view_drag_motion;
4033         widget_class->drag_data_received = ev_view_drag_data_received;
4034         widget_class->popup_menu = ev_view_popup_menu;
4035 #if GTK_CHECK_VERSION (2, 11, 7)
4036         widget_class->query_tooltip = ev_view_query_tooltip;
4037 #endif
4038
4039         gtk_object_class->destroy = ev_view_destroy;
4040
4041         layout_class->set_scroll_adjustments = ev_view_set_scroll_adjustments;
4042         
4043         class->binding_activated = ev_view_scroll;
4044
4045         signals[SIGNAL_BINDING_ACTIVATED] = g_signal_new ("binding_activated",
4046                          G_TYPE_FROM_CLASS (object_class),
4047                          G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
4048                          G_STRUCT_OFFSET (EvViewClass, binding_activated),
4049                          NULL, NULL,
4050                          ev_marshal_VOID__ENUM_BOOLEAN,
4051                          G_TYPE_NONE, 2,
4052                          GTK_TYPE_SCROLL_TYPE,
4053                          G_TYPE_BOOLEAN);
4054
4055         signals[SIGNAL_ZOOM_INVALID] = g_signal_new ("zoom-invalid",
4056                          G_TYPE_FROM_CLASS (object_class),
4057                          G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
4058                          G_STRUCT_OFFSET (EvViewClass, zoom_invalid),
4059                          NULL, NULL,
4060                          ev_marshal_VOID__VOID,
4061                          G_TYPE_NONE, 0, G_TYPE_NONE);
4062         signals[SIGNAL_HANDLE_LINK] = g_signal_new ("handle-link",
4063                          G_TYPE_FROM_CLASS (object_class),
4064                          G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
4065                          G_STRUCT_OFFSET (EvViewClass, handle_link),
4066                          NULL, NULL,
4067                          g_cclosure_marshal_VOID__OBJECT,
4068                          G_TYPE_NONE, 1,
4069                          G_TYPE_OBJECT);
4070         signals[SIGNAL_EXTERNAL_LINK] = g_signal_new ("external-link",
4071                          G_TYPE_FROM_CLASS (object_class),
4072                          G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
4073                          G_STRUCT_OFFSET (EvViewClass, external_link),
4074                          NULL, NULL,
4075                          g_cclosure_marshal_VOID__OBJECT,
4076                          G_TYPE_NONE, 1,
4077                          G_TYPE_OBJECT);
4078         signals[SIGNAL_POPUP_MENU] = g_signal_new ("popup",
4079                          G_TYPE_FROM_CLASS (object_class),
4080                          G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
4081                          G_STRUCT_OFFSET (EvViewClass, popup_menu),
4082                          NULL, NULL,
4083                          g_cclosure_marshal_VOID__OBJECT,
4084                          G_TYPE_NONE, 1,
4085                          G_TYPE_OBJECT);
4086
4087
4088         g_object_class_install_property (object_class,
4089                                          PROP_CONTINUOUS,
4090                                          g_param_spec_boolean ("continuous",
4091                                                                "Continuous",
4092                                                                "Continuous scrolling mode",
4093                                                                TRUE,
4094                                                                G_PARAM_READWRITE));
4095
4096         g_object_class_install_property (object_class,
4097                                          PROP_DUAL_PAGE,
4098                                          g_param_spec_boolean ("dual-page",
4099                                                                "Dual Page",
4100                                                                "Two pages visible at once",
4101                                                                FALSE,
4102                                                                G_PARAM_READWRITE));
4103         g_object_class_install_property (object_class,
4104                                          PROP_FULLSCREEN,
4105                                          g_param_spec_boolean ("fullscreen",
4106                                                                "Full Screen",
4107                                                                "Draw page in a fullscreen fashion",
4108                                                                FALSE,
4109                                                                G_PARAM_READWRITE));
4110         g_object_class_install_property (object_class,
4111                                          PROP_PRESENTATION,
4112                                          g_param_spec_boolean ("presentation",
4113                                                                "Presentation",
4114                                                                "Draw page in presentation mode",
4115                                                                TRUE,
4116                                                                G_PARAM_READWRITE));
4117
4118         g_object_class_install_property (object_class,
4119                                          PROP_SIZING_MODE,
4120                                          g_param_spec_enum ("sizing-mode",
4121                                                             "Sizing Mode",
4122                                                             "Sizing Mode",
4123                                                             EV_TYPE_SIZING_MODE,
4124                                                             EV_SIZING_FIT_WIDTH,
4125                                                             G_PARAM_READWRITE));
4126
4127         g_object_class_install_property (object_class,
4128                                          PROP_ZOOM,
4129                                          g_param_spec_double ("zoom",
4130                                                               "Zoom factor",
4131                                                               "Zoom factor",
4132                                                               0,
4133                                                               G_MAXDOUBLE,
4134                                                               1.0,
4135                                                               G_PARAM_READWRITE));
4136         g_object_class_install_property (object_class,
4137                                          PROP_ROTATION,
4138                                          g_param_spec_double ("rotation",
4139                                                               "Rotation",
4140                                                               "Rotation",
4141                                                               0,
4142                                                               360,
4143                                                               0,
4144                                                               G_PARAM_READWRITE));
4145         g_object_class_install_property (object_class,
4146                                          PROP_HAS_SELECTION,
4147                                          g_param_spec_boolean ("has-selection",
4148                                                                "Has selection",
4149                                                                "The view has selections",
4150                                                                FALSE,
4151                                                                G_PARAM_READABLE));
4152
4153         binding_set = gtk_binding_set_by_class (class);
4154
4155         add_scroll_binding_keypad (binding_set, GDK_Left,  0, GTK_SCROLL_STEP_BACKWARD, TRUE);
4156         add_scroll_binding_keypad (binding_set, GDK_Right, 0, GTK_SCROLL_STEP_FORWARD,  TRUE);
4157         add_scroll_binding_keypad (binding_set, GDK_Left,  GDK_MOD1_MASK, GTK_SCROLL_STEP_DOWN, TRUE);
4158         add_scroll_binding_keypad (binding_set, GDK_Right, GDK_MOD1_MASK, GTK_SCROLL_STEP_UP,  TRUE);
4159         add_scroll_binding_keypad (binding_set, GDK_Up,    0, GTK_SCROLL_STEP_BACKWARD, FALSE);
4160         add_scroll_binding_keypad (binding_set, GDK_Down,  0, GTK_SCROLL_STEP_FORWARD,  FALSE);
4161         add_scroll_binding_keypad (binding_set, GDK_Up,    GDK_MOD1_MASK, GTK_SCROLL_STEP_DOWN, FALSE);
4162         add_scroll_binding_keypad (binding_set, GDK_Down,  GDK_MOD1_MASK, GTK_SCROLL_STEP_UP,  FALSE);
4163         gtk_binding_entry_add_signal (binding_set, GDK_H, 0, "binding_activated", 2, GTK_TYPE_SCROLL_TYPE,
4164                                       GTK_SCROLL_STEP_BACKWARD, G_TYPE_BOOLEAN, TRUE);
4165         gtk_binding_entry_add_signal (binding_set, GDK_J, 0, "binding_activated", 2, GTK_TYPE_SCROLL_TYPE,
4166                                       GTK_SCROLL_STEP_FORWARD, G_TYPE_BOOLEAN, FALSE);
4167         gtk_binding_entry_add_signal (binding_set, GDK_K, 0, "binding_activated", 2, GTK_TYPE_SCROLL_TYPE,
4168                                       GTK_SCROLL_STEP_BACKWARD, G_TYPE_BOOLEAN, FALSE);
4169         gtk_binding_entry_add_signal (binding_set, GDK_L, 0, "binding_activated", 2, GTK_TYPE_SCROLL_TYPE,
4170                                       GTK_SCROLL_STEP_FORWARD, G_TYPE_BOOLEAN, TRUE);
4171         
4172 }
4173
4174 static void
4175 ev_view_init (EvView *view)
4176 {
4177         GTK_WIDGET_SET_FLAGS (view, GTK_CAN_FOCUS);
4178
4179         view->spacing = 5;
4180         view->scale = 1.0;
4181         view->current_page = 0;
4182         view->pressed_button = -1;
4183         view->cursor = EV_VIEW_CURSOR_NORMAL;
4184         view->drag_info.in_drag = FALSE;
4185         view->scroll_info.autoscrolling = FALSE;
4186         view->selection_info.selections = NULL;
4187         view->selection_info.in_selection = FALSE;
4188         view->selection_info.in_drag = FALSE;
4189         view->selection_mode = EV_VIEW_SELECTION_TEXT;
4190         view->continuous = TRUE;
4191         view->dual_page = FALSE;
4192         view->presentation = FALSE;
4193         view->presentation_state = EV_PRESENTATION_NORMAL;
4194         view->fullscreen = FALSE;
4195         view->sizing_mode = EV_SIZING_FIT_WIDTH;
4196         view->pending_scroll = SCROLL_TO_KEEP_POSITION;
4197         view->jump_to_find_result = TRUE;
4198         view->highlight_find_results = FALSE;
4199
4200         gtk_layout_set_hadjustment (GTK_LAYOUT (view), NULL);
4201         gtk_layout_set_vadjustment (GTK_LAYOUT (view), NULL);
4202
4203         gtk_drag_dest_set (GTK_WIDGET (view),
4204                            GTK_DEST_DEFAULT_ALL,
4205                            view_drop_targets,
4206                            G_N_ELEMENTS (view_drop_targets),
4207                            GDK_ACTION_COPY);
4208 }
4209
4210 /*** Callbacks ***/
4211
4212 static void
4213 ev_view_change_page (EvView *view,
4214                      gint    new_page,
4215                      gboolean start_transition)
4216 {
4217         gint x, y;
4218
4219         view->current_page = new_page;
4220         view->pending_scroll = SCROLL_TO_PAGE_POSITION;
4221
4222         if (view->presentation && start_transition)
4223                 ev_view_presentation_transition_start (view);
4224
4225         gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
4226         ev_view_handle_cursor_over_xy (view, x, y);
4227
4228         gtk_widget_queue_resize (GTK_WIDGET (view));
4229 }
4230
4231 static void
4232 ev_view_transition_animation_finish (EvTransitionAnimation *animation,
4233                                      EvView                *view)
4234 {
4235         g_object_unref (view->animation);
4236         view->animation = NULL;
4237         ev_view_change_page (view, view->current_page, TRUE);
4238 }
4239
4240 /**
4241  * ev_view_transition_animation_cancel:
4242  * @animation: Animation to finish
4243  * @view: An EvView
4244  *
4245  * Does almost the same as cancel, but without scheduling the transition.
4246  */
4247
4248 static void
4249 ev_view_transition_animation_cancel (EvTransitionAnimation *animation,
4250                                      EvView                *view)
4251 {
4252         g_object_unref (view->animation);
4253         view->animation = NULL;
4254         ev_view_change_page (view, view->current_page, FALSE);
4255 }
4256
4257 static void
4258 ev_view_transition_animation_frame (EvTransitionAnimation *animation,
4259                                     gdouble                progress,
4260                                     EvView                *view)
4261 {
4262         gtk_widget_queue_draw (GTK_WIDGET (view));
4263 }
4264
4265 static void
4266 ev_view_presentation_animation_start (EvView *view,
4267                                       int     new_page)
4268 {
4269         EvTransitionEffect *effect = NULL;
4270         cairo_surface_t *surface;
4271
4272         if (EV_IS_DOCUMENT_TRANSITION (view->document))
4273                 effect = ev_document_transition_get_effect (EV_DOCUMENT_TRANSITION (view->document),
4274                                                             view->current_page);
4275         if (!effect)
4276                 return;
4277
4278         surface = ev_pixbuf_cache_get_surface (view->pixbuf_cache, view->current_page);
4279         view->animation = ev_transition_animation_new (effect);
4280         ev_transition_animation_set_origin_surface (view->animation, surface);
4281                 
4282         g_signal_connect (view->animation, "frame",
4283                           G_CALLBACK (ev_view_transition_animation_frame), view);
4284         g_signal_connect (view->animation, "finished",
4285                           G_CALLBACK (ev_view_transition_animation_finish), view);
4286 }
4287
4288 static void
4289 job_finished_cb (EvPixbufCache *pixbuf_cache,
4290                  GdkRegion     *region,
4291                  EvView        *view)
4292 {
4293         if (view->animation) {
4294                 cairo_surface_t *surface;
4295
4296                 surface = ev_pixbuf_cache_get_surface (pixbuf_cache, view->current_page);
4297                 ev_transition_animation_set_dest_surface (view->animation, surface);
4298         }
4299
4300         if (region) {
4301                 gdk_window_invalidate_region (view->layout.bin_window,
4302                                               region, TRUE);
4303         } else {
4304                 gtk_widget_queue_draw (GTK_WIDGET (view));
4305         }
4306 }
4307
4308 static void
4309 page_changed_cb (EvPageCache *page_cache,
4310                  int          new_page,
4311                  EvView      *view)
4312 {
4313         if (view->current_page != new_page) {
4314                 if (view->presentation)
4315                         ev_view_presentation_animation_start (view, new_page);
4316
4317                 ev_view_change_page (view, new_page, TRUE);
4318         } else {
4319                 gtk_widget_queue_draw (GTK_WIDGET (view));
4320         }
4321
4322         view->find_result = 0;
4323 }
4324
4325 static void
4326 on_adjustment_value_changed (GtkAdjustment *adjustment,
4327                              EvView        *view)
4328 {
4329         int dx = 0, dy = 0;
4330         gint x, y;
4331         GList *children, *l;
4332
4333         if (! GTK_WIDGET_REALIZED (view))
4334                 return;
4335
4336         if (view->hadjustment) {
4337                 dx = view->scroll_x - (int) view->hadjustment->value;
4338                 view->scroll_x = (int) view->hadjustment->value;
4339         } else {
4340                 view->scroll_x = 0;
4341         }
4342
4343         if (view->vadjustment) {
4344                 dy = view->scroll_y - (int) view->vadjustment->value;
4345                 view->scroll_y = (int) view->vadjustment->value;
4346         } else {
4347                 view->scroll_y = 0;
4348         }
4349
4350         children = gtk_container_get_children (GTK_CONTAINER (view));
4351         for (l = children; l && l->data; l = g_list_next (l)) {
4352                 gint       child_x, child_y;
4353                 GtkWidget *child = (GtkWidget *)l->data;
4354                 
4355                 gtk_container_child_get (GTK_CONTAINER (view),
4356                                          child,
4357                                          "x", &child_x,
4358                                          "y", &child_y,
4359                                          NULL);
4360                 gtk_layout_move (GTK_LAYOUT (view), child, child_x + dx, child_y + dy);
4361         }
4362         g_list_free (children);
4363         
4364         if (view->pending_resize)
4365                 gtk_widget_queue_draw (GTK_WIDGET (view));
4366         else
4367                 gdk_window_scroll (view->layout.bin_window, dx, dy);
4368                 
4369         gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
4370         ev_view_handle_cursor_over_xy (view, x, y);
4371
4372         if (view->document)
4373                 view_update_range_and_current_page (view);
4374 }
4375
4376 GtkWidget*
4377 ev_view_new (void)
4378 {
4379         GtkWidget *view;
4380
4381         view = g_object_new (EV_TYPE_VIEW, NULL);
4382
4383         return view;
4384 }
4385
4386 static void
4387 setup_caches (EvView *view)
4388 {
4389         view->page_cache = ev_page_cache_get (view->document);
4390         g_signal_connect (view->page_cache, "page-changed", G_CALLBACK (page_changed_cb), view);
4391         view->pixbuf_cache = ev_pixbuf_cache_new (GTK_WIDGET (view), view->document);
4392         g_signal_connect (view->pixbuf_cache, "job-finished", G_CALLBACK (job_finished_cb), view);
4393         page_changed_cb (view->page_cache,
4394                          ev_page_cache_get_current_page (view->page_cache),
4395                          view);
4396 }
4397
4398 static void
4399 clear_caches (EvView *view)
4400 {
4401         if (view->pixbuf_cache) {
4402                 g_object_unref (view->pixbuf_cache);
4403                 view->pixbuf_cache = NULL;
4404         }
4405
4406         if (view->page_cache) {
4407                 view->page_cache = NULL;
4408         }
4409 }
4410
4411 void
4412 ev_view_set_loading (EvView       *view,
4413                      gboolean      loading)
4414 {
4415         view->loading = loading;
4416         gtk_widget_queue_draw (GTK_WIDGET (view));
4417 }
4418
4419 static gboolean
4420 ev_view_autoscroll_cb (EvView *view)
4421 {
4422         gdouble speed, value;
4423
4424         /* If the user stops autoscrolling, autoscrolling will be
4425          * set to false but the timeout will continue; stop the timeout: */
4426         if (!view->scroll_info.autoscrolling) {
4427                 view->scroll_info.timeout_id = 0;
4428                 return FALSE;
4429         }
4430         
4431         if (view->scroll_info.last_y > view->scroll_info.start_y && 
4432                 (view->scroll_info.last_y < view->scroll_info.start_y))
4433                 return TRUE; 
4434
4435         /* Replace 100 with your speed of choice: The lower the faster.
4436          * Replace 3 with another speed of choice: The higher, the faster it accelerated
4437          *      based on the distance of the starting point from the mouse
4438          * (All also effected by the timeout interval of this callback) */
4439
4440         if (view->scroll_info.start_y > view->scroll_info.last_y)
4441                 speed = -pow ((((gdouble)view->scroll_info.start_y - view->scroll_info.last_y) / 100), 3);
4442         else
4443                 speed = pow ((((gdouble)view->scroll_info.last_y - view->scroll_info.start_y) / 100), 3);
4444         
4445         value = gtk_adjustment_get_value (view->vadjustment);
4446         value = CLAMP (value + speed, 0, view->vadjustment->upper - view->vadjustment->page_size);
4447         gtk_adjustment_set_value (view->vadjustment, value);
4448         
4449         return TRUE;
4450
4451 }
4452
4453 void
4454 ev_view_autoscroll_start (EvView *view)
4455 {
4456         gint x, y;
4457         
4458         g_return_if_fail (EV_IS_VIEW (view));
4459
4460         if (view->scroll_info.autoscrolling)
4461                 return;
4462         
4463         view->scroll_info.autoscrolling = TRUE;
4464         view->scroll_info.timeout_id =
4465                 g_timeout_add (20, (GSourceFunc)ev_view_autoscroll_cb,
4466                                view);
4467         
4468         gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
4469         ev_view_handle_cursor_over_xy (view, x, y);
4470 }
4471
4472 void
4473 ev_view_autoscroll_stop (EvView *view)
4474 {
4475         gint x, y;
4476         
4477         g_return_if_fail (EV_IS_VIEW (view));
4478
4479         if (!view->scroll_info.autoscrolling)
4480                 return;
4481
4482         view->scroll_info.autoscrolling = FALSE;
4483         if (view->scroll_info.timeout_id) {
4484                 g_source_remove (view->scroll_info.timeout_id);
4485                 view->scroll_info.timeout_id = 0;
4486         }
4487
4488         gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
4489         ev_view_handle_cursor_over_xy (view, x, y);
4490 }
4491
4492 void
4493 ev_view_set_document (EvView     *view,
4494                       EvDocument *document)
4495 {
4496         g_return_if_fail (EV_IS_VIEW (view));
4497
4498         view->loading = FALSE;
4499         
4500         if (document != view->document) {
4501                 clear_caches (view);
4502
4503                 if (view->document) {
4504                         g_object_unref (view->document);
4505                         view->page_cache = NULL;
4506                 }
4507
4508                 view->document = document;
4509                 view->find_result = 0;
4510
4511                 if (view->document) {
4512                         g_object_ref (view->document);
4513                         setup_caches (view);
4514                 }
4515
4516                 gtk_widget_queue_resize (GTK_WIDGET (view));
4517         }
4518 }
4519
4520 /*** Zoom and sizing mode ***/
4521
4522 #define EPSILON 0.0000001
4523 void
4524 ev_view_set_zoom (EvView   *view,
4525                   double    factor,
4526                   gboolean  relative)
4527 {
4528         double scale;
4529
4530         if (relative)
4531                 scale = view->scale * factor;
4532         else
4533                 scale = factor;
4534
4535         scale = CLAMP (scale,
4536                        view->sizing_mode == EV_SIZING_FREE ? view->min_scale : 0,
4537                        view->max_scale);
4538
4539         if (ABS (view->scale - scale) < EPSILON)
4540                 return;
4541
4542         if (view->loading_text) {
4543                 cairo_surface_destroy (view->loading_text);
4544                 view->loading_text = NULL;
4545         }
4546
4547         view->scale = scale;
4548         view->pending_resize = TRUE;
4549
4550         gtk_widget_queue_resize (GTK_WIDGET (view));
4551
4552         g_object_notify (G_OBJECT (view), "zoom");
4553 }
4554
4555 double
4556 ev_view_get_zoom (EvView *view)
4557 {
4558         return view->scale;
4559 }
4560
4561 void
4562 ev_view_set_screen_dpi (EvView  *view,
4563                         gdouble  dpi)
4564 {
4565         g_return_if_fail (EV_IS_VIEW (view));
4566         g_return_if_fail (dpi > 0);
4567
4568         view->dpi = dpi;
4569         view->min_scale = MIN_SCALE * dpi / 72.0;
4570         view->max_scale = MAX_SCALE * dpi / 72.0;
4571 }
4572
4573 gboolean
4574 ev_view_get_continuous (EvView *view)
4575 {
4576         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
4577
4578         return view->continuous;
4579 }
4580
4581 void
4582 ev_view_set_continuous (EvView   *view,
4583                         gboolean  continuous)
4584 {
4585         g_return_if_fail (EV_IS_VIEW (view));
4586
4587         continuous = continuous != FALSE;
4588
4589         if (view->continuous != continuous) {
4590                 view->continuous = continuous;
4591                 view->pending_scroll = SCROLL_TO_PAGE_POSITION;
4592                 gtk_widget_queue_resize (GTK_WIDGET (view));
4593         }
4594
4595         g_object_notify (G_OBJECT (view), "continuous");
4596 }
4597
4598 gboolean
4599 ev_view_get_dual_page (EvView *view)
4600 {
4601         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
4602
4603         return view->dual_page;
4604 }
4605
4606 void
4607 ev_view_set_dual_page (EvView   *view,
4608                        gboolean  dual_page)
4609 {
4610         g_return_if_fail (EV_IS_VIEW (view));
4611
4612         dual_page = dual_page != FALSE;
4613
4614         if (view->dual_page == dual_page)
4615                 return;
4616
4617         view->pending_scroll = SCROLL_TO_PAGE_POSITION;
4618         view->dual_page = dual_page;
4619         /* FIXME: if we're keeping the pixbuf cache around, we should extend the
4620          * preload_cache_size to be 2 if dual_page is set.
4621          */
4622         gtk_widget_queue_resize (GTK_WIDGET (view));
4623
4624         g_object_notify (G_OBJECT (view), "dual-page");
4625 }
4626
4627 void
4628 ev_view_set_fullscreen (EvView   *view,
4629                          gboolean  fullscreen)
4630 {
4631         g_return_if_fail (EV_IS_VIEW (view));
4632
4633         fullscreen = fullscreen != FALSE;
4634
4635         if (view->fullscreen == fullscreen) 
4636                 return;
4637                 
4638         view->fullscreen = fullscreen;
4639         gtk_widget_queue_resize (GTK_WIDGET (view));
4640         
4641         g_object_notify (G_OBJECT (view), "fullscreen");
4642 }
4643
4644 gboolean
4645 ev_view_get_fullscreen (EvView *view)
4646 {
4647         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
4648
4649         return view->fullscreen;
4650 }
4651
4652 void
4653 ev_view_set_presentation (EvView   *view,
4654                           gboolean  presentation)
4655 {
4656         g_return_if_fail (EV_IS_VIEW (view));
4657
4658         presentation = presentation != FALSE;
4659
4660         if (view->presentation == presentation)
4661                 return;
4662
4663         if (!presentation)
4664                 view->presentation_state = EV_PRESENTATION_NORMAL;
4665         
4666         view->presentation = presentation;
4667         view->pending_scroll = SCROLL_TO_PAGE_POSITION;
4668         
4669         if (presentation) {
4670                 view->sizing_mode_saved = view->sizing_mode;
4671                 view->scale_saved = view->scale;
4672                 ev_view_set_sizing_mode (view, EV_SIZING_BEST_FIT);
4673         } else {
4674                 ev_view_set_sizing_mode (view, view->sizing_mode_saved);
4675                 ev_view_set_zoom (view, view->scale_saved, FALSE);
4676         }
4677         
4678         gtk_widget_queue_resize (GTK_WIDGET (view));
4679
4680         if (presentation)
4681                 ev_view_presentation_transition_start (view);
4682         else {
4683                 ev_view_presentation_transition_stop (view);
4684
4685                 if (view->animation) {
4686                         /* stop any running animation */
4687                         ev_view_transition_animation_cancel (view->animation, view);
4688                 }
4689         }
4690
4691         if (GTK_WIDGET_REALIZED (view)) {
4692                 if (view->presentation)
4693                         gdk_window_set_background (view->layout.bin_window,
4694                                                    &GTK_WIDGET (view)->style->black);
4695                 else
4696                         gdk_window_set_background (view->layout.bin_window,
4697                                                    &GTK_WIDGET (view)->style->mid [GTK_STATE_NORMAL]);
4698         }
4699
4700         g_object_notify (G_OBJECT (view), "presentation");
4701 }
4702
4703 gboolean
4704 ev_view_get_presentation (EvView *view)
4705 {
4706         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
4707
4708         return view->presentation;
4709 }
4710
4711 static gboolean
4712 transition_next_page (EvView *view)
4713 {
4714         ev_view_next_page (view);
4715
4716         return FALSE;
4717 }
4718
4719 static void
4720 ev_view_presentation_transition_stop (EvView *view)
4721 {
4722         if (view->trans_timeout_id > 0)
4723                 g_source_remove (view->trans_timeout_id);
4724         view->trans_timeout_id = 0;
4725 }
4726
4727 static void
4728 ev_view_presentation_transition_start (EvView *view)
4729 {
4730         gdouble duration;
4731         
4732         if (!EV_IS_DOCUMENT_TRANSITION (view->document))
4733                 return;
4734
4735         ev_view_presentation_transition_stop (view);
4736
4737         duration = ev_document_transition_get_page_duration (EV_DOCUMENT_TRANSITION (view->document),
4738                                                              view->current_page);
4739         if (duration > 0) {
4740                 view->trans_timeout_id =
4741                         g_timeout_add_seconds (duration,
4742                                                (GSourceFunc) transition_next_page,
4743                                                view);
4744         }
4745 }
4746
4747 void
4748 ev_view_set_sizing_mode (EvView       *view,
4749                          EvSizingMode  sizing_mode)
4750 {
4751         g_return_if_fail (EV_IS_VIEW (view));
4752
4753         if (view->sizing_mode == sizing_mode)
4754                 return;
4755
4756         view->sizing_mode = sizing_mode;
4757         gtk_widget_queue_resize (GTK_WIDGET (view));
4758
4759         g_object_notify (G_OBJECT (view), "sizing-mode");
4760 }
4761
4762 EvSizingMode
4763 ev_view_get_sizing_mode (EvView *view)
4764 {
4765         g_return_val_if_fail (EV_IS_VIEW (view), EV_SIZING_FREE);
4766
4767         return view->sizing_mode;
4768 }
4769
4770 gboolean
4771 ev_view_can_zoom_in (EvView *view)
4772 {
4773         return view->scale * ZOOM_IN_FACTOR <= view->max_scale;
4774 }
4775
4776 gboolean
4777 ev_view_can_zoom_out (EvView *view)
4778 {
4779         return view->scale * ZOOM_OUT_FACTOR >= view->min_scale;
4780 }
4781
4782 void
4783 ev_view_zoom_in (EvView *view)
4784 {
4785         g_return_if_fail (view->sizing_mode == EV_SIZING_FREE);
4786
4787         if (view->presentation)
4788                 return;
4789         
4790         view->pending_scroll = SCROLL_TO_CENTER;
4791         ev_view_set_zoom (view, ZOOM_IN_FACTOR, TRUE);
4792 }
4793
4794 void
4795 ev_view_zoom_out (EvView *view)
4796 {
4797         g_return_if_fail (view->sizing_mode == EV_SIZING_FREE);
4798
4799         if (view->presentation)
4800                 return;
4801         
4802         view->pending_scroll = SCROLL_TO_CENTER;
4803         ev_view_set_zoom (view, ZOOM_OUT_FACTOR, TRUE);
4804 }
4805
4806 void
4807 ev_view_rotate_right (EvView *view)
4808 {
4809         int rotation = view->rotation + 90;
4810
4811         if (rotation >= 360) {
4812                 rotation -= 360;
4813         }
4814
4815         ev_view_set_rotation (view, rotation);
4816 }
4817
4818 void
4819 ev_view_rotate_left (EvView *view)
4820 {
4821         int rotation = view->rotation - 90;
4822
4823         if (rotation < 0) {
4824                 rotation += 360;
4825         }
4826
4827         ev_view_set_rotation (view, rotation);
4828 }
4829
4830 void
4831 ev_view_set_rotation (EvView *view, int rotation)
4832 {
4833         view->rotation = rotation;
4834
4835         if (view->pixbuf_cache) {
4836                 ev_pixbuf_cache_clear (view->pixbuf_cache);
4837                 gtk_widget_queue_resize (GTK_WIDGET (view));
4838         }
4839
4840         if (rotation != 0)
4841                 clear_selection (view);
4842
4843         g_object_notify (G_OBJECT (view), "rotation");
4844 }
4845
4846 int
4847 ev_view_get_rotation (EvView *view)
4848 {
4849         return view->rotation;
4850 }
4851
4852 static double
4853 zoom_for_size_fit_width (int doc_width,
4854                          int doc_height,
4855                          int target_width,
4856                          int target_height,
4857                          int vsb_width)
4858 {
4859         double scale;
4860
4861         scale = (double)target_width / doc_width;
4862
4863         if (doc_height * scale > target_height)
4864                 scale = (double) (target_width - vsb_width) / doc_width;
4865
4866         return scale;
4867 }
4868
4869 static double
4870 zoom_for_size_fit_height (int doc_width,
4871                           int doc_height,
4872                           int target_width,
4873                           int target_height,
4874                           int vsb_height)
4875 {
4876         double scale;
4877
4878         scale = (double)target_height / doc_height;
4879
4880         if (doc_width * scale > target_width)
4881                 scale = (double) (target_height - vsb_height) / doc_height;
4882
4883         return scale;
4884 }
4885
4886 static double
4887 zoom_for_size_best_fit (int doc_width,
4888                         int doc_height,
4889                         int target_width,
4890                         int target_height,
4891                         int vsb_width,
4892                         int hsb_width)
4893 {
4894         double w_scale;
4895         double h_scale;
4896
4897         w_scale = (double)target_width / doc_width;
4898         h_scale = (double)target_height / doc_height;
4899
4900         if (doc_height * w_scale > target_height)
4901                 w_scale = (double) (target_width - vsb_width) / doc_width;
4902         if (doc_width * h_scale > target_width)
4903                 h_scale = (double) (target_height - hsb_width) / doc_height;
4904
4905         return MIN (w_scale, h_scale);
4906 }
4907
4908
4909 static void
4910 ev_view_zoom_for_size_presentation (EvView *view,
4911                                     int     width,
4912                                     int     height)
4913 {
4914         int doc_width, doc_height;
4915         gdouble scale;
4916
4917         ev_page_cache_get_size (view->page_cache,
4918                                 view->current_page,
4919                                 view->rotation,
4920                                 1.0,
4921                                 &doc_width,
4922                                 &doc_height);
4923         scale = zoom_for_size_best_fit (doc_width, doc_height, width, height, 0, 0);
4924         ev_view_set_zoom (view, scale, FALSE);
4925 }
4926
4927 static void
4928 ev_view_zoom_for_size_continuous_and_dual_page (EvView *view,
4929                            int     width,
4930                            int     height,
4931                            int     vsb_width,
4932                            int     hsb_height)
4933 {
4934         int doc_width, doc_height;
4935         GtkBorder border;
4936         gdouble scale;
4937
4938         ev_page_cache_get_max_width (view->page_cache,
4939                                      view->rotation,
4940                                      1.0,
4941                                      &doc_width);
4942         ev_page_cache_get_max_height (view->page_cache,
4943                                       view->rotation,
4944                                       1.0,
4945                                       &doc_height);
4946         compute_border (view, doc_width, doc_height, &border);
4947
4948         doc_width = doc_width * 2;
4949         width -= (2 * (border.left + border.right) + 3 * view->spacing);
4950         height -= (border.top + border.bottom + 2 * view->spacing - 1);
4951
4952         /* FIXME: We really need to calculate the overall height here, not the
4953          * page height.  We assume there's always a vertical scrollbar for
4954          * now.  We need to fix this. */
4955         if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
4956                 scale = zoom_for_size_fit_width (doc_width, doc_height, width - vsb_width, height, 0);
4957         else if (view->sizing_mode == EV_SIZING_BEST_FIT)
4958                 scale = zoom_for_size_best_fit (doc_width, doc_height, width - vsb_width, height, 0, hsb_height);
4959         else
4960                 g_assert_not_reached ();
4961
4962         ev_view_set_zoom (view, scale, FALSE);
4963 }
4964
4965 static void
4966 ev_view_zoom_for_size_continuous (EvView *view,
4967                                   int     width,
4968                                   int     height,
4969                                   int     vsb_width,
4970                                   int     hsb_height)
4971 {
4972         int doc_width, doc_height;
4973         GtkBorder border;
4974         gdouble scale;
4975
4976         ev_page_cache_get_max_width (view->page_cache,
4977                                      view->rotation,
4978                                      1.0,
4979                                      &doc_width);
4980         ev_page_cache_get_max_height (view->page_cache,
4981                                       view->rotation,
4982                                       1.0,
4983                                       &doc_height);
4984         compute_border (view, doc_width, doc_height, &border);
4985
4986         width -= (border.left + border.right + 2 * view->spacing);
4987         height -= (border.top + border.bottom + 2 * view->spacing - 1);
4988
4989         /* FIXME: We really need to calculate the overall height here, not the
4990          * page height.  We assume there's always a vertical scrollbar for
4991          * now.  We need to fix this. */
4992         if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
4993                 scale = zoom_for_size_fit_width (doc_width, doc_height, width - vsb_width, height, 0);
4994         else if (view->sizing_mode == EV_SIZING_BEST_FIT)
4995                 scale = zoom_for_size_best_fit (doc_width, doc_height, width - vsb_width, height, 0, hsb_height);
4996         else
4997                 g_assert_not_reached ();
4998
4999         ev_view_set_zoom (view, scale, FALSE);
5000 }
5001
5002 static void
5003 ev_view_zoom_for_size_dual_page (EvView *view,
5004                                  int     width,
5005                                  int     height,
5006                                  int     vsb_width,
5007                                  int     hsb_height)
5008 {
5009         GtkBorder border;
5010         gint doc_width, doc_height;
5011         gdouble scale;
5012         gint other_page;
5013
5014         other_page = view->current_page ^ 1;
5015
5016         /* Find the largest of the two. */
5017         ev_page_cache_get_size (view->page_cache,
5018                                 view->current_page,
5019                                 view->rotation,
5020                                 1.0,
5021                                 &doc_width, &doc_height);
5022
5023         if (other_page < ev_page_cache_get_n_pages (view->page_cache)) {
5024                 gint width_2, height_2;
5025                 ev_page_cache_get_size (view->page_cache,
5026                                         other_page,
5027                                         view->rotation,
5028                                         1.0,
5029                                         &width_2, &height_2);
5030                 if (width_2 > doc_width)
5031                         doc_width = width_2;
5032                 if (height_2 > doc_height)
5033                         doc_height = height_2;
5034         }
5035         compute_border (view, doc_width, doc_height, &border);
5036
5037         doc_width = doc_width * 2;
5038         width -= ((border.left + border.right)* 2 + 3 * view->spacing);
5039         height -= (border.top + border.bottom + 2 * view->spacing);
5040
5041         if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
5042                 scale = zoom_for_size_fit_width (doc_width, doc_height, width, height, vsb_width);
5043         else if (view->sizing_mode == EV_SIZING_BEST_FIT)
5044                 scale = zoom_for_size_best_fit (doc_width, doc_height, width, height, vsb_width, hsb_height);
5045         else
5046                 g_assert_not_reached ();
5047
5048         ev_view_set_zoom (view, scale, FALSE);
5049 }
5050
5051 static void
5052 ev_view_zoom_for_size_single_page (EvView *view,
5053                                    int     width,
5054                                    int     height,
5055                                    int     vsb_width,
5056                                    int     hsb_height)
5057 {
5058         int doc_width, doc_height;
5059         GtkBorder border;
5060         gdouble scale;
5061
5062         ev_page_cache_get_size (view->page_cache,
5063                                 view->current_page,
5064                                 view->rotation,
5065                                 1.0,
5066                                 &doc_width,
5067                                 &doc_height);
5068         /* Get an approximate border */
5069         compute_border (view, width, height, &border);
5070
5071         width -= (border.left + border.right + 2 * view->spacing);
5072         height -= (border.top + border.bottom + 2 * view->spacing);
5073
5074         if (view->sizing_mode == EV_SIZING_FIT_WIDTH)
5075                 scale = zoom_for_size_fit_width (doc_width, doc_height, width, height, vsb_width);
5076         else if (view->sizing_mode == EV_SIZING_BEST_FIT)
5077                 scale = zoom_for_size_best_fit (doc_width, doc_height, width, height, vsb_width, hsb_height);
5078         else
5079                 g_assert_not_reached ();
5080
5081         ev_view_set_zoom (view, scale, FALSE);
5082 }
5083
5084 static void
5085 ev_view_set_zoom_for_size (EvView *view,
5086                            int     width,
5087                            int     height,
5088                            int     vsb_width,
5089                            int     hsb_height)
5090 {
5091         g_return_if_fail (EV_IS_VIEW (view));
5092         g_return_if_fail (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
5093                           view->sizing_mode == EV_SIZING_BEST_FIT);
5094         g_return_if_fail (width >= 0);
5095         g_return_if_fail (height >= 0);
5096
5097         if (view->document == NULL)
5098                 return;
5099
5100         if (view->presentation)
5101                 ev_view_zoom_for_size_presentation (view, width, height);
5102         else if (view->continuous && view->dual_page)
5103                 ev_view_zoom_for_size_continuous_and_dual_page (view, width, height, vsb_width, hsb_height);
5104         else if (view->continuous)
5105                 ev_view_zoom_for_size_continuous (view, width, height, vsb_width, hsb_height);
5106         else if (view->dual_page)
5107                 ev_view_zoom_for_size_dual_page (view, width, height, vsb_width, hsb_height);
5108         else
5109                 ev_view_zoom_for_size_single_page (view, width, height, vsb_width, hsb_height);
5110 }
5111
5112 /*** Find ***/
5113 static gint
5114 ev_view_find_get_n_results (EvView *view, gint page)
5115 {
5116         return view->find_pages ? g_list_length (view->find_pages[page]) : 0;
5117 }
5118
5119 static EvRectangle *
5120 ev_view_find_get_result (EvView *view, gint page, gint result)
5121 {
5122         return view->find_pages ? (EvRectangle *) g_list_nth_data (view->find_pages[page], result) : NULL;
5123 }
5124
5125 static void
5126 jump_to_find_result (EvView *view)
5127 {
5128         gint n_results;
5129         gint page = view->current_page;
5130
5131         n_results = ev_view_find_get_n_results (view, page);
5132
5133         if (n_results > 0 && view->find_result < n_results) {
5134                 EvRectangle *rect;
5135                 GdkRectangle view_rect;
5136
5137                 rect = ev_view_find_get_result (view, page, view->find_result);
5138                 doc_rect_to_view_rect (view, page, rect, &view_rect);
5139                 ensure_rectangle_is_visible (view, &view_rect);
5140         }
5141 }
5142
5143 /**
5144  * jump_to_find_page
5145  * @view: #EvView instance
5146  * @direction: Direction to look
5147  * @shift: Shift from current page
5148  *
5149  * Jumps to the first page that has occurences of searched word.
5150  * Uses a direction where to look and a shift from current page. 
5151  *
5152  */
5153 static void
5154 jump_to_find_page (EvView *view, EvViewFindDirection direction, gint shift)
5155 {
5156         int n_pages, i;
5157
5158         n_pages = ev_page_cache_get_n_pages (view->page_cache);
5159
5160         for (i = 0; i < n_pages; i++) {
5161                 int page;
5162                 
5163                 if (direction == EV_VIEW_FIND_NEXT)
5164                         page = view->current_page + i;
5165                 else
5166                         page = view->current_page - i;          
5167                 page += shift;
5168                 
5169                 if (page >= n_pages) {
5170                         page = page - n_pages;
5171                 } else if (page < 0) 
5172                         page = page + n_pages;
5173
5174                 if (ev_view_find_get_n_results (view, page) > 0) {
5175                         ev_page_cache_set_current_page (view->page_cache, page);
5176                         break;
5177                 }
5178         }
5179 }
5180
5181 void
5182 ev_view_find_changed (EvView *view, GList **results, gint page)
5183 {
5184         view->find_pages = results;
5185         
5186         if (view->jump_to_find_result == TRUE) {
5187                 jump_to_find_page (view, EV_VIEW_FIND_NEXT, 0);
5188                 jump_to_find_result (view);
5189         }
5190
5191         if (view->current_page == page)
5192                 gtk_widget_queue_draw (GTK_WIDGET (view));
5193 }
5194
5195 void
5196 ev_view_find_next (EvView *view)
5197 {
5198         gint n_results;
5199
5200         n_results = ev_view_find_get_n_results (view, view->current_page);
5201         view->find_result++;
5202
5203         if (view->find_result >= n_results) {
5204                 view->find_result = 0;
5205                 jump_to_find_page (view, EV_VIEW_FIND_NEXT, 1);
5206                 jump_to_find_result (view);
5207         } else {
5208                 jump_to_find_result (view);
5209                 gtk_widget_queue_draw (GTK_WIDGET (view));
5210         }
5211 }
5212
5213 void
5214 ev_view_find_previous (EvView *view)
5215 {
5216         view->find_result--;
5217
5218         if (view->find_result < 0) {
5219                 jump_to_find_page (view, EV_VIEW_FIND_PREV, -1);
5220                 view->find_result = ev_view_find_get_n_results (view, view->current_page) - 1;
5221                 jump_to_find_result (view);
5222         } else {
5223                 jump_to_find_result (view);
5224                 gtk_widget_queue_draw (GTK_WIDGET (view));
5225         }
5226 }
5227
5228 void
5229 ev_view_find_search_changed (EvView *view)
5230 {
5231         /* search string has changed, focus on new search result */
5232         view->jump_to_find_result = TRUE;
5233         view->find_pages = NULL;
5234 }
5235
5236 void
5237 ev_view_find_set_highlight_search (EvView *view, gboolean value)
5238 {
5239         view->highlight_find_results = value;
5240         gtk_widget_queue_draw (GTK_WIDGET (view));
5241 }
5242
5243 void
5244 ev_view_find_cancel (EvView *view)
5245 {
5246         view->find_pages = NULL;
5247 }
5248
5249 /*** Selections ***/
5250
5251 /* compute_new_selection_rect/text calculates the area currently selected by
5252  * view_rect.  each handles a different mode;
5253  */
5254 static GList *
5255 compute_new_selection_rect (EvView       *view,
5256                             GdkPoint     *start,
5257                             GdkPoint     *stop)
5258 {
5259         GdkRectangle view_rect;
5260         int n_pages, i;
5261         GList *list = NULL;
5262
5263         g_assert (view->selection_mode == EV_VIEW_SELECTION_RECTANGLE);
5264         
5265         view_rect.x = MIN (start->x, stop->x);
5266         view_rect.y = MIN (start->y, stop->y);
5267         view_rect.width = MAX (start->x, stop->x) - view_rect.x;
5268         view_rect.width = MAX (start->y, stop->y) - view_rect.y;
5269
5270         n_pages = ev_page_cache_get_n_pages (view->page_cache);
5271
5272         for (i = 0; i < n_pages; i++) {
5273                 GdkRectangle page_area;
5274                 GtkBorder border;
5275                 
5276                 if (get_page_extents (view, i, &page_area, &border)) {
5277                         GdkRectangle overlap;
5278
5279                         if (gdk_rectangle_intersect (&page_area, &view_rect, &overlap)) {
5280                                 EvViewSelection *selection;
5281
5282                                 selection = g_new0 (EvViewSelection, 1);
5283                                 selection->page = i;
5284                                 view_rect_to_doc_rect (view, &overlap, &page_area,
5285                                                        &(selection->rect));
5286
5287                                 list = g_list_append (list, selection);
5288                         }
5289                 }
5290         }
5291
5292         return list;
5293 }
5294
5295 static gboolean
5296 gdk_rectangle_point_in (GdkRectangle *rectangle,
5297                         GdkPoint     *point)
5298 {
5299         return rectangle->x <= point->x &&
5300                 rectangle->y <= point->y &&
5301                 point->x < rectangle->x + rectangle->width &&
5302                 point->y < rectangle->y + rectangle->height;
5303 }
5304
5305 static GList *
5306 compute_new_selection_text (EvView          *view,
5307                             EvSelectionStyle style,
5308                             GdkPoint        *start,
5309                             GdkPoint        *stop)
5310 {
5311         int n_pages, i, first, last;
5312         GList *list = NULL;
5313         EvViewSelection *selection;
5314         gint width, height;
5315         int start_page, end_page;
5316
5317         g_assert (view->selection_mode == EV_VIEW_SELECTION_TEXT);
5318
5319         n_pages = ev_page_cache_get_n_pages (view->page_cache);
5320
5321         /* First figure out the range of pages the selection
5322          * affects. */
5323         first = n_pages;
5324         last = 0;
5325         if (view->continuous) {
5326                 start_page = 0;
5327                 end_page = n_pages;
5328         } else if (view->dual_page) {
5329                 start_page = view->start_page;
5330                 end_page = view->end_page + 1;
5331         } else {
5332                 start_page = view->current_page;
5333                 end_page = view->current_page + 1;
5334         }
5335
5336         for (i = start_page; i < end_page; i++) {
5337                 GdkRectangle page_area;
5338                 GtkBorder border;
5339                 
5340                 get_page_extents (view, i, &page_area, &border);
5341                 if (gdk_rectangle_point_in (&page_area, start) || 
5342                     gdk_rectangle_point_in (&page_area, stop)) {
5343                         if (first == n_pages)
5344                                 first = i;
5345                         last = i;
5346                 }
5347
5348         }
5349
5350         /* Now create a list of EvViewSelection's for the affected
5351          * pages.  This could be an empty list, a list of just one
5352          * page or a number of pages.*/
5353         for (i = first; i < last + 1; i++) {
5354                 GdkRectangle page_area;
5355                 GtkBorder border;
5356                 GdkPoint *point;
5357
5358                 ev_page_cache_get_size (view->page_cache, i,
5359                                         view->rotation,
5360                                         1.0, &width, &height);
5361
5362                 selection = g_new0 (EvViewSelection, 1);
5363                 selection->page = i;
5364                 selection->style = style;
5365                 selection->rect.x1 = selection->rect.y1 = 0;
5366                 selection->rect.x2 = width;
5367                 selection->rect.y2 = height;
5368
5369                 get_page_extents (view, i, &page_area, &border);
5370
5371                 if (gdk_rectangle_point_in (&page_area, start))
5372                         point = start;
5373                 else
5374                         point = stop;
5375
5376                 if (i == first)
5377                         view_point_to_doc_point (view, point, &page_area,
5378                                                  &selection->rect.x1,
5379                                                  &selection->rect.y1);
5380
5381                 /* If the selection is contained within just one page,
5382                  * make sure we don't write 'start' into both points
5383                  * in selection->rect. */
5384                 if (first == last)
5385                         point = stop;
5386
5387                 if (i == last)
5388                         view_point_to_doc_point (view, point, &page_area,
5389                                                  &selection->rect.x2,
5390                                                  &selection->rect.y2);
5391
5392                 list = g_list_append (list, selection);
5393         }
5394
5395         return list;
5396 }
5397
5398 /* This function takes the newly calculated list, and figures out which regions
5399  * have changed.  It then queues a redraw approporiately.
5400  */
5401 static void
5402 merge_selection_region (EvView *view,
5403                         GList  *new_list)
5404 {
5405         GList *old_list;
5406         GList *new_list_ptr, *old_list_ptr;
5407
5408         /* Update the selection */
5409         old_list = ev_pixbuf_cache_get_selection_list (view->pixbuf_cache);
5410         g_list_foreach (view->selection_info.selections, (GFunc)selection_free, NULL);
5411         g_list_free (view->selection_info.selections);
5412         view->selection_info.selections = new_list;
5413         ev_pixbuf_cache_set_selection_list (view->pixbuf_cache, new_list);
5414         g_object_notify (G_OBJECT (view), "has-selection");
5415
5416         new_list_ptr = new_list;
5417         old_list_ptr = old_list;
5418
5419         while (new_list_ptr || old_list_ptr) {
5420                 EvViewSelection *old_sel, *new_sel;
5421                 int cur_page;
5422                 GdkRegion *region = NULL;
5423
5424                 new_sel = (new_list_ptr) ? (new_list_ptr->data) : NULL;
5425                 old_sel = (old_list_ptr) ? (old_list_ptr->data) : NULL;
5426
5427                 /* Assume that the lists are in order, and we run through them
5428                  * comparing them, one page at a time.  We come out with the
5429                  * first page we see. */
5430                 if (new_sel && old_sel) {
5431                         if (new_sel->page < old_sel->page) {
5432                                 new_list_ptr = new_list_ptr->next;
5433                                 old_sel = NULL;
5434                         } else if (new_sel->page > old_sel->page) {
5435                                 old_list_ptr = old_list_ptr->next;
5436                                 new_sel = NULL;
5437                         } else {
5438                                 new_list_ptr = new_list_ptr->next;
5439                                 old_list_ptr = old_list_ptr->next;
5440                         }
5441                 } else if (new_sel) {
5442                         new_list_ptr = new_list_ptr->next;
5443                 } else if (old_sel) {
5444                         old_list_ptr = old_list_ptr->next;
5445                 }
5446
5447                 g_assert (new_sel || old_sel);
5448
5449                 /* is the page we're looking at on the screen?*/
5450                 cur_page = new_sel ? new_sel->page : old_sel->page;
5451                 if (cur_page < view->start_page || cur_page > view->end_page)
5452                         continue;
5453
5454                 /* seed the cache with a new page.  We are going to need the new
5455                  * region too. */
5456                 if (new_sel) {
5457                         GdkRegion *tmp_region = NULL;
5458
5459                         ev_pixbuf_cache_get_selection_surface (view->pixbuf_cache,
5460                                                                cur_page,
5461                                                                view->scale,
5462                                                                &tmp_region);
5463
5464                         if (tmp_region) {
5465                                 new_sel->covered_region = gdk_region_copy (tmp_region);
5466                         }
5467                 }
5468
5469                 /* Now we figure out what needs redrawing */
5470                 if (old_sel && new_sel) {
5471                         if (old_sel->covered_region && new_sel->covered_region) {
5472                                 /* We only want to redraw the areas that have
5473                                  * changed, so we xor the old and new regions
5474                                  * and redraw if it's different */
5475                                 region = gdk_region_copy (old_sel->covered_region);
5476                                 gdk_region_xor (region, new_sel->covered_region);
5477                                 if (gdk_region_empty (region)) {
5478                                         gdk_region_destroy (region);
5479                                         region = NULL;
5480                                 }
5481                         } else if (old_sel->covered_region) {
5482                                 region = gdk_region_copy (old_sel->covered_region);
5483                         } else if (new_sel->covered_region) {
5484                                 region = gdk_region_copy (new_sel->covered_region);
5485                         }
5486                 } else if (old_sel && !new_sel) {
5487                         if (old_sel->covered_region && !gdk_region_empty (old_sel->covered_region)) {
5488                                 region = gdk_region_copy (old_sel->covered_region);
5489                         }
5490                 } else if (!old_sel && new_sel) {
5491                         if (new_sel->covered_region && !gdk_region_empty (new_sel->covered_region)) {
5492                                 region = gdk_region_copy (new_sel->covered_region);
5493                         }
5494                 } else {
5495                         g_assert_not_reached ();
5496                 }
5497
5498                 /* Redraw the damaged region! */
5499                 if (region) {
5500                         GdkRectangle page_area;
5501                         GtkBorder border;
5502
5503                         /* I don't know why but the region is smaller
5504                          * than expected. This hack fixes it, I guess
5505                          * 10 pixels more won't hurt
5506                          */
5507                         gdk_region_shrink (region, -5, -5);
5508
5509                         get_page_extents (view, cur_page, &page_area, &border);
5510                         gdk_region_offset (region,
5511                                            page_area.x + border.left - view->scroll_x,
5512                                            page_area.y + border.top - view->scroll_y);
5513                         gdk_window_invalidate_region (view->layout.bin_window, region, TRUE);
5514                         gdk_region_destroy (region);
5515                 }
5516         }
5517
5518         /* Free the old list, now that we're done with it. */
5519         g_list_foreach (old_list, (GFunc) selection_free, NULL);
5520         g_list_free (old_list);
5521 }
5522
5523 static void
5524 compute_selections (EvView          *view,
5525                     EvSelectionStyle style,
5526                     GdkPoint        *start,
5527                     GdkPoint        *stop)
5528 {
5529         GList *list;
5530
5531         if (view->selection_mode == EV_VIEW_SELECTION_RECTANGLE)
5532                 list = compute_new_selection_rect (view, start, stop);
5533         else
5534                 list = compute_new_selection_text (view, style, start, stop);
5535         merge_selection_region (view, list);
5536 }
5537
5538 /* Free's the selection.  It's up to the caller to queue redraws if needed.
5539  */
5540 static void
5541 selection_free (EvViewSelection *selection)
5542 {
5543         if (selection->covered_region)
5544                 gdk_region_destroy (selection->covered_region);
5545         g_free (selection);
5546 }
5547
5548 static void
5549 clear_selection (EvView *view)
5550 {
5551         g_list_foreach (view->selection_info.selections, (GFunc)selection_free, NULL);
5552         g_list_free (view->selection_info.selections);
5553         view->selection_info.selections = NULL;
5554         view->selection_info.in_selection = FALSE;
5555         if (view->pixbuf_cache)
5556                 ev_pixbuf_cache_set_selection_list (view->pixbuf_cache, NULL);
5557         g_object_notify (G_OBJECT (view), "has-selection");
5558 }
5559
5560 void
5561 ev_view_select_all (EvView *view)
5562 {
5563         GList *selections = NULL;
5564         int n_pages, i;
5565
5566         /* Disable selection on rotated pages for the 0.4.0 series */
5567         if (view->rotation != 0)
5568                 return;
5569
5570         clear_selection (view);
5571         
5572         n_pages = ev_page_cache_get_n_pages (view->page_cache);
5573         for (i = 0; i < n_pages; i++) {
5574                 int width, height;
5575                 EvViewSelection *selection;
5576
5577                 ev_page_cache_get_size (view->page_cache,
5578                                         i,
5579                                         view->rotation,
5580                                         1.0, &width, &height);
5581
5582                 selection = g_new0 (EvViewSelection, 1);
5583                 selection->page = i;
5584                 selection->style = EV_SELECTION_STYLE_GLYPH;
5585                 selection->rect.x1 = selection->rect.y1 = 0;
5586                 selection->rect.x2 = width;
5587                 selection->rect.y2 = height;
5588
5589                 selections = g_list_append (selections, selection);
5590         }
5591
5592         merge_selection_region (view, selections);
5593         gtk_widget_queue_draw (GTK_WIDGET (view));
5594 }
5595
5596 gboolean
5597 ev_view_get_has_selection (EvView *view)
5598 {
5599         return view->selection_info.selections != NULL;
5600 }
5601
5602 static char *
5603 get_selected_text (EvView *view)
5604 {
5605         GString *text;
5606         GList *l;
5607         gchar *normalized_text;
5608         EvRenderContext *rc;
5609
5610         text = g_string_new (NULL);
5611         rc = ev_render_context_new (NULL, view->rotation, view->scale);
5612
5613         ev_document_doc_mutex_lock ();
5614
5615         for (l = view->selection_info.selections; l != NULL; l = l->next) {
5616                 EvViewSelection *selection = (EvViewSelection *)l->data;
5617                 EvPage *page;
5618                 gchar *tmp;
5619
5620                 page = ev_document_get_page (view->document, selection->page);
5621                 ev_render_context_set_page (rc, page);
5622                 g_object_unref (page);
5623                 
5624                 tmp = ev_selection_get_selected_text (EV_SELECTION (view->document),
5625                                                       rc, selection->style,
5626                                                       &(selection->rect));
5627
5628                 g_string_append (text, tmp);
5629                 g_free (tmp);
5630         }
5631
5632         g_object_unref (rc);
5633         
5634         ev_document_doc_mutex_unlock ();
5635         
5636         normalized_text = g_utf8_normalize (text->str, text->len, G_NORMALIZE_NFKC);
5637         g_string_free (text, TRUE);
5638         return normalized_text;
5639 }
5640
5641 static void
5642 ev_view_clipboard_copy (EvView      *view,
5643                         const gchar *text)
5644 {
5645         GtkClipboard *clipboard;
5646
5647         clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view),
5648                                               GDK_SELECTION_CLIPBOARD);
5649         gtk_clipboard_set_text (clipboard, text, -1);
5650 }
5651
5652 void
5653 ev_view_copy (EvView *ev_view)
5654 {
5655         char *text;
5656
5657         if (!EV_IS_SELECTION (ev_view->document))
5658                 return;
5659
5660         text = get_selected_text (ev_view);
5661         ev_view_clipboard_copy (ev_view, text);
5662         g_free (text);
5663 }
5664
5665 static void
5666 ev_view_primary_get_cb (GtkClipboard     *clipboard,
5667                         GtkSelectionData *selection_data,
5668                         guint             info,
5669                         gpointer          data)
5670 {
5671         EvView *ev_view = EV_VIEW (data);
5672
5673         if (ev_view->link_selected) {
5674                 gtk_selection_data_set_text (selection_data,
5675                                              ev_link_action_get_uri (ev_view->link_selected),
5676                                              -1);
5677         } else if (EV_IS_SELECTION (ev_view->document) &&
5678                    ev_view->selection_info.selections) {
5679                 gchar *text;
5680                 
5681                 text = get_selected_text (ev_view);
5682                 if (text) {
5683                         gtk_selection_data_set_text (selection_data, text, -1);
5684                         g_free (text);
5685                 }
5686         }
5687 }
5688
5689 static void
5690 ev_view_primary_clear_cb (GtkClipboard *clipboard,
5691                           gpointer      data)
5692 {
5693         EvView *view = EV_VIEW (data);
5694
5695         clear_selection (view);
5696         clear_link_selected (view);
5697 }
5698
5699 static void
5700 ev_view_update_primary_selection (EvView *ev_view)
5701 {
5702         GtkClipboard *clipboard;
5703
5704         clipboard = gtk_widget_get_clipboard (GTK_WIDGET (ev_view),
5705                                               GDK_SELECTION_PRIMARY);
5706
5707         if (ev_view->selection_info.selections || ev_view->link_selected) {
5708                 if (!gtk_clipboard_set_with_owner (clipboard,
5709                                                    clipboard_targets,
5710                                                    G_N_ELEMENTS (clipboard_targets),
5711                                                    ev_view_primary_get_cb,
5712                                                    ev_view_primary_clear_cb,
5713                                                    G_OBJECT (ev_view)))
5714                         ev_view_primary_clear_cb (clipboard, ev_view);
5715         } else {
5716                 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (ev_view))
5717                         gtk_clipboard_clear (clipboard);
5718         }
5719 }
5720
5721 static void
5722 clear_link_selected (EvView *view)
5723 {
5724         if (view->link_selected) {
5725                 g_object_unref (view->link_selected);
5726                 view->link_selected = NULL;
5727         }
5728 }
5729
5730 void
5731 ev_view_copy_link_address (EvView       *view,
5732                            EvLinkAction *action)
5733 {
5734         clear_link_selected (view);
5735         
5736         ev_view_clipboard_copy (view, ev_link_action_get_uri (action));
5737         
5738         view->link_selected = g_object_ref (action);
5739         ev_view_update_primary_selection (view);
5740 }
5741
5742 /*** Cursor operations ***/
5743
5744 static GdkCursor *
5745 ev_view_create_invisible_cursor(void)
5746 {
5747        GdkBitmap *empty;
5748        GdkColor black = { 0, 0, 0, 0 };
5749        static char bits[] = { 0x00 };
5750
5751        empty = gdk_bitmap_create_from_data (NULL, bits, 1, 1);
5752
5753        return gdk_cursor_new_from_pixmap (empty, empty, &black, &black, 0, 0);
5754 }
5755
5756 static void
5757 ev_view_set_cursor (EvView *view, EvViewCursor new_cursor)
5758 {
5759         GdkCursor *cursor = NULL;
5760         GdkDisplay *display;
5761         GtkWidget *widget;
5762
5763         if (view->cursor == new_cursor) {
5764                 return;
5765         }
5766
5767         widget = gtk_widget_get_toplevel (GTK_WIDGET (view));
5768         display = gtk_widget_get_display (widget);
5769         view->cursor = new_cursor;
5770
5771         switch (new_cursor) {
5772                 case EV_VIEW_CURSOR_NORMAL:
5773                         gdk_window_set_cursor (view->layout.bin_window, NULL);
5774                         break;
5775                 case EV_VIEW_CURSOR_IBEAM:
5776                         cursor = gdk_cursor_new_for_display (display, GDK_XTERM);
5777                         break;
5778                 case EV_VIEW_CURSOR_LINK:
5779                         cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
5780                         break;
5781                 case EV_VIEW_CURSOR_WAIT:
5782                         cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
5783                         break;
5784                 case EV_VIEW_CURSOR_HIDDEN:
5785                         cursor = ev_view_create_invisible_cursor ();
5786                         break;
5787                 case EV_VIEW_CURSOR_DRAG:
5788                         cursor = gdk_cursor_new_for_display (display, GDK_FLEUR);
5789                         break;
5790                 case EV_VIEW_CURSOR_AUTOSCROLL:
5791                         cursor = gdk_cursor_new_for_display (display, GDK_DOUBLE_ARROW);
5792                         break;
5793         }
5794
5795         if (cursor) {
5796                 gdk_window_set_cursor (view->layout.bin_window, cursor);
5797                 gdk_cursor_unref (cursor);
5798                 gdk_flush();
5799         }
5800 }
5801
5802 void
5803 ev_view_hide_cursor (EvView *view)
5804 {
5805        ev_view_set_cursor (view, EV_VIEW_CURSOR_HIDDEN);
5806 }
5807
5808 void
5809 ev_view_show_cursor (EvView *view)
5810 {
5811        ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
5812 }
5813
5814 static void
5815 ev_view_reset_presentation_state (EvView *view)
5816 {
5817         if (!view->presentation ||
5818             view->presentation_state == EV_PRESENTATION_NORMAL)
5819                 return;
5820
5821         view->presentation_state = EV_PRESENTATION_NORMAL;
5822         gdk_window_set_background (view->layout.bin_window,
5823                                    &GTK_WIDGET (view)->style->black);
5824         gtk_widget_queue_draw (GTK_WIDGET (view));
5825 }
5826
5827 gboolean
5828 ev_view_next_page (EvView *view)
5829 {
5830         int page, n_pages;
5831
5832         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
5833         
5834         if (!view->page_cache)
5835                 return FALSE;
5836
5837         if (view->presentation &&
5838             (view->presentation_state == EV_PRESENTATION_BLACK ||
5839              view->presentation_state == EV_PRESENTATION_WHITE)) {
5840                 ev_view_reset_presentation_state (view);
5841                 return FALSE; 
5842         }
5843
5844         if (view->animation) {
5845                 ev_view_transition_animation_cancel (view->animation, view);
5846         }
5847
5848         ev_view_presentation_transition_stop (view);
5849         ev_view_reset_presentation_state (view);
5850         
5851         page = ev_page_cache_get_current_page (view->page_cache);
5852         n_pages = ev_page_cache_get_n_pages (view->page_cache);
5853
5854         if (view->dual_page && !view->presentation)
5855                 page = page + 2; 
5856         else 
5857                 page = page + 1;
5858
5859         if (page < n_pages) {
5860                 ev_page_cache_set_current_page (view->page_cache, page);
5861                 return TRUE;
5862         } else if (view->presentation && page == n_pages) {
5863                 view->presentation_state = EV_PRESENTATION_END;
5864                 gtk_widget_queue_draw (GTK_WIDGET (view));
5865                 return TRUE;
5866         } else if (view->dual_page && page == n_pages) {
5867                 ev_page_cache_set_current_page (view->page_cache, page - 1);
5868                 return TRUE;
5869         } else {
5870                 return FALSE;
5871         }
5872 }
5873
5874 gboolean
5875 ev_view_previous_page (EvView *view)
5876 {
5877         int page;
5878
5879         g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
5880
5881         if (!view->page_cache)
5882                 return FALSE;
5883
5884         if (view->presentation &&
5885             view->presentation_state == EV_PRESENTATION_END) {
5886                 ev_view_reset_presentation_state (view);
5887                 return TRUE;
5888         }
5889         
5890         if (view->presentation && 
5891             (view->presentation_state == EV_PRESENTATION_BLACK ||
5892              view->presentation_state == EV_PRESENTATION_WHITE)) {
5893                 ev_view_reset_presentation_state (view);
5894                 return FALSE; 
5895         }       
5896
5897         if (view->animation) {
5898                 ev_view_transition_animation_cancel (view->animation, view);
5899         }
5900
5901         ev_view_reset_presentation_state (view);
5902
5903         page = ev_page_cache_get_current_page (view->page_cache);
5904
5905         if (view->dual_page && !view->presentation)
5906                 page = page - 2; 
5907         else 
5908                 page = page - 1;
5909
5910         if (page >= 0) {
5911                 ev_page_cache_set_current_page (view->page_cache, page);
5912                 return TRUE;
5913         } else if (ev_view_get_dual_page (view) && page == -1) {
5914                 ev_page_cache_set_current_page (view->page_cache, 0);
5915                 return TRUE;
5916         } else {        
5917                 return FALSE;
5918         }
5919 }
5920
5921 /*** Enum description for usage in signal ***/
5922
5923 GType
5924 ev_sizing_mode_get_type (void)
5925 {
5926   static GType etype = 0;
5927   if (etype == 0) {
5928     static const GEnumValue values[] = {
5929       { EV_SIZING_FIT_WIDTH, "EV_SIZING_FIT_WIDTH", "fit-width" },
5930       { EV_SIZING_BEST_FIT, "EV_SIZING_BEST_FIT", "best-fit" },
5931       { EV_SIZING_FREE, "EV_SIZING_FREE", "free" },
5932       { 0, NULL, NULL }
5933     };
5934     etype = g_enum_register_static ("EvSizingMode", values);
5935   }
5936   return etype;
5937 }
5938
5939 void
5940 ev_view_update_view_size (EvView *view, GtkScrolledWindow * scrolled_window)
5941 {
5942         int width, height;
5943         GtkRequisition vsb_requisition;
5944         GtkRequisition hsb_requisition;
5945         int scrollbar_spacing;
5946         
5947         /* Calculate the width available for the content */ 
5948         width  = GTK_WIDGET (scrolled_window)->allocation.width;
5949         height = GTK_WIDGET (scrolled_window)->allocation.height;
5950
5951         if (gtk_scrolled_window_get_shadow_type (scrolled_window) == GTK_SHADOW_IN 
5952             && view) {
5953                 width -=  2 * GTK_WIDGET(view)->style->xthickness;
5954                 height -= 2 * GTK_WIDGET(view)->style->ythickness;
5955         }
5956
5957         gtk_widget_size_request (scrolled_window->vscrollbar, &vsb_requisition);
5958         gtk_widget_size_request (scrolled_window->hscrollbar, &hsb_requisition);
5959         gtk_widget_style_get (GTK_WIDGET (scrolled_window), 
5960                               "scrollbar_spacing", 
5961                               &scrollbar_spacing, 
5962                               NULL);
5963         
5964         if (EV_IS_VIEW(view)) {
5965                 ev_view_set_zoom_for_size (EV_VIEW (view),
5966                                            MAX (1, width),
5967                                            MAX (1, height),
5968                                            vsb_requisition.width + scrollbar_spacing,
5969                                            hsb_requisition.height + scrollbar_spacing);
5970         }
5971 }