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