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

« back to all changes in this revision

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