~ubuntu-branches/ubuntu/precise/evince/precise-updates

« back to all changes in this revision

Viewing changes to libview/ev-view.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2009-01-19 10:39:43 UTC
  • mto: (1.6.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 70.
  • Revision ID: james.westby@ubuntu.com-20090119103943-dhe56g9rmuq7khys
Tags: upstream-2.25.5
ImportĀ upstreamĀ versionĀ 2.25.5

Show diffs side-by-side

added added

removed removed

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