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