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
4
* Copyright (C) 2004 Red Hat, Inc
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.
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.
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.
27
#include <glib/gi18n.h>
29
#include <gdk/gdkkeysyms.h>
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"
43
#include "ev-view-private.h"
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))
62
SIGNAL_BINDING_ACTIVATED,
81
TARGET_TEXT_BUFFER_CONTENTS
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 },
91
static const GtkTargetEntry view_drop_targets[] = {
92
{ "text/uri-list", 0, 0 }
95
static guint signals[N_SIGNALS];
100
} EvViewFindDirection;
102
#define ZOOM_IN_FACTOR 1.2
103
#define ZOOM_OUT_FACTOR (1.0/ZOOM_IN_FACTOR)
105
#define MIN_SCALE 0.05409
106
#define MAX_SCALE 4.0
108
#define SCROLL_TIME 150
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,
122
GdkModifierType modifiers,
123
GtkScrollType scroll,
124
gboolean horizontal);
125
static void ensure_rectangle_is_visible (EvView *view,
128
/*** Geometry computations ***/
129
static void compute_border (EvView *view,
133
static void get_page_y_offset (EvView *view,
137
static gboolean get_page_extents (EvView *view,
139
GdkRectangle *page_area,
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,
147
EvRectangle *doc_rect,
148
GdkRectangle *view_rect);
149
static void find_page_at_location (EvView *view,
155
static gboolean doc_point_to_view_point (EvView *view,
158
GdkPoint *view_point);
160
static EvLink * ev_view_get_link_at_location (EvView *view,
163
static char* tip_from_link (EvView *view,
166
static EvFormField *ev_view_get_form_field_at_location (EvView *view,
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);
203
static AtkObject *ev_view_get_accessible (GtkWidget *widget);
206
static guint32 ev_gdk_color_to_rgb (const GdkColor *color);
207
static void draw_rubberband (GtkWidget *widget,
209
const GdkRectangle *rect,
211
static void highlight_find_results (EvView *view,
213
static void draw_one_page (EvView *view,
216
GdkRectangle *page_area,
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,
228
static void job_finished_cb (EvPixbufCache *pixbuf_cache,
231
static void page_changed_cb (EvPageCache *page_cache,
234
static void on_adjustment_value_changed (GtkAdjustment *adjustment,
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,
244
static void ev_view_get_property (GObject *object,
248
static void ev_view_class_init (EvViewClass *class);
249
static void ev_view_init (EvView *view);
251
/*** Zoom and sizing ***/
252
static double zoom_for_size_fit_width (int doc_width,
257
static double zoom_for_size_fit_height (int doc_width,
262
static double zoom_for_size_best_fit (int doc_width,
268
static void ev_view_zoom_for_size_presentation (EvView *view,
271
static void ev_view_zoom_for_size_continuous_and_dual_page (EvView *view,
276
static void ev_view_zoom_for_size_continuous (EvView *view,
281
static void ev_view_zoom_for_size_dual_page (EvView *view,
286
static void ev_view_zoom_for_size_single_page (EvView *view,
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,
300
static gint ev_view_find_get_n_results (EvView *view,
302
static EvRectangle *ev_view_find_get_result (EvView *view,
305
static void jump_to_find_result (EvView *view);
306
static void jump_to_find_page (EvView *view,
307
EvViewFindDirection direction,
311
static void compute_selections (EvView *view,
312
EvSelectionStyle style,
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,
323
static void ev_view_primary_clear_cb (GtkClipboard *clipboard,
325
static void ev_view_update_primary_selection (EvView *ev_view);
327
/*** Presentation ***/
328
static void ev_view_presentation_transition_start (EvView *ev_view);
329
static void ev_view_presentation_transition_stop (EvView *ev_view);
332
G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_LAYOUT)
335
scroll_to_current_page (EvView *view, GtkOrientation orientation)
339
if (view->document == NULL) {
343
doc_point_to_view_point (view, view->current_page, &view->pending_point, &view_point);
345
if (orientation == GTK_ORIENTATION_VERTICAL) {
346
view->pending_point.y = 0;
348
view->pending_point.x = 0;
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);
357
gtk_adjustment_set_value (view->vadjustment,
359
view->vadjustment->lower,
360
view->vadjustment->upper -
361
view->vadjustment->page_size));
364
if (view->dual_page) {
365
gtk_adjustment_clamp_page (view->hadjustment,
367
view_point.x + view->hadjustment->page_size);
369
gtk_adjustment_set_value (view->hadjustment,
371
view->hadjustment->lower,
372
view->hadjustment->upper -
373
view->hadjustment->page_size));
379
view_set_adjustment_values (EvView *view,
380
GtkOrientation orientation)
382
GtkWidget *widget = GTK_WIDGET (view);
383
GtkAdjustment *adjustment;
390
if (orientation == GTK_ORIENTATION_HORIZONTAL) {
391
requisition = widget->requisition.width;
392
allocation = widget->allocation.width;
393
adjustment = view->hadjustment;
395
requisition = widget->requisition.height;
396
allocation = widget->allocation.height;
397
adjustment = view->vadjustment;
404
switch (view->pending_scroll) {
405
case SCROLL_TO_KEEP_POSITION:
406
case SCROLL_TO_FIND_LOCATION:
407
factor = (adjustment->value) / adjustment->upper;
409
case SCROLL_TO_PAGE_POSITION:
411
case SCROLL_TO_CENTER:
412
factor = (adjustment->value + adjustment->page_size * 0.5) / adjustment->upper;
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);
423
* We add 0.5 to the values before to average out our rounding errors.
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);
431
case SCROLL_TO_PAGE_POSITION:
432
scroll_to_current_page (view, orientation);
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);
441
gtk_adjustment_changed (adjustment);
445
view_update_range_and_current_page (EvView *view)
448
gint best_current_page = -1;
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;
457
gboolean found = FALSE;
458
gint area_max = -1, area;
461
if (!(view->vadjustment && view->hadjustment))
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;
469
for (i = 0; i < ev_page_cache_get_n_pages (view->page_cache); i++) {
471
get_page_extents (view, i, &page_area, &border);
473
if (gdk_rectangle_intersect (¤t_area, &page_area, &unused)) {
474
area = unused.width * unused.height;
478
view->start_page = i;
480
best_current_page = i;
482
if (area > area_max) {
483
best_current_page = (area == area_max) ? MIN (i, best_current_page) : i;
488
} else if (found && view->current_page <= view->end_page) {
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;
499
view->end_page = view->start_page;
501
if (view->current_page < 1)
502
view->start_page = view->current_page;
504
view->start_page = view->current_page - 1;
505
view->end_page = view->current_page;
508
view->start_page = view->current_page;
509
view->end_page = view->current_page;
512
best_current_page = MAX (best_current_page, view->start_page);
513
current_page = ev_page_cache_get_current_page (view->page_cache);
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);
520
ev_pixbuf_cache_set_page_range (view->pixbuf_cache,
525
view->selection_info.selections);
529
set_scroll_adjustment (EvView *view,
530
GtkOrientation orientation,
531
GtkAdjustment *adjustment)
533
GtkAdjustment **to_set;
535
if (orientation == GTK_ORIENTATION_HORIZONTAL)
536
to_set = &view->hadjustment;
538
to_set = &view->vadjustment;
540
if (*to_set != adjustment) {
542
g_signal_handlers_disconnect_by_func (*to_set,
543
(gpointer) on_adjustment_value_changed,
545
g_object_unref (*to_set);
548
*to_set = adjustment;
549
view_set_adjustment_values (view, orientation);
552
g_object_ref (*to_set);
553
g_signal_connect (*to_set, "value_changed",
554
G_CALLBACK (on_adjustment_value_changed), view);
560
ev_view_set_scroll_adjustments (GtkLayout *layout,
561
GtkAdjustment *hadjustment,
562
GtkAdjustment *vadjustment)
564
EvView *view = EV_VIEW (layout);
566
set_scroll_adjustment (view, GTK_ORIENTATION_HORIZONTAL, hadjustment);
567
set_scroll_adjustment (view, GTK_ORIENTATION_VERTICAL, vadjustment);
569
on_adjustment_value_changed (NULL, view);
573
add_scroll_binding_keypad (GtkBindingSet *binding_set,
575
GdkModifierType modifiers,
576
GtkScrollType scroll,
579
guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
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);
592
ev_view_scroll (EvView *view,
593
GtkScrollType scroll,
596
GtkAdjustment *adjustment;
597
double value, increment;
598
gboolean first_page = FALSE;
599
gboolean last_page = FALSE;
601
view->jump_to_find_result = FALSE;
603
if (view->presentation || view->sizing_mode == EV_SIZING_BEST_FIT) {
605
case GTK_SCROLL_PAGE_BACKWARD:
606
case GTK_SCROLL_STEP_BACKWARD:
607
ev_view_previous_page (view);
609
case GTK_SCROLL_PAGE_FORWARD:
610
case GTK_SCROLL_STEP_FORWARD:
611
ev_view_next_page (view);
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;
624
/* Assign boolean for first and last page */
625
if (view->current_page == 0)
627
if (view->current_page == ev_page_cache_get_n_pages (view->page_cache) - 1)
631
case GTK_SCROLL_PAGE_BACKWARD:
632
/* Do not jump backwards if at the first page */
633
if (value == (adjustment->lower) && first_page) {
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 */
641
value = MAX (value - increment, adjustment->lower);
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) {
648
/* At the bottom of a page, assign the lower bound limit of next page */
649
} else if (value == (adjustment->upper - adjustment->page_size)) {
651
ev_view_next_page (view);
652
/* Jump to the bottom */
654
value = MIN (value + increment, adjustment->upper - adjustment->page_size);
657
case GTK_SCROLL_STEP_BACKWARD:
658
value -= adjustment->step_increment;
660
case GTK_SCROLL_STEP_FORWARD:
661
value += adjustment->step_increment;
663
case GTK_SCROLL_STEP_DOWN:
664
value -= adjustment->step_increment / 10;
666
case GTK_SCROLL_STEP_UP:
667
value += adjustment->step_increment / 10;
673
value = CLAMP (value, adjustment->lower,
674
adjustment->upper - adjustment->page_size);
676
gtk_adjustment_set_value (adjustment, value);
682
ensure_rectangle_is_visible (EvView *view, GdkRectangle *rect)
684
GtkWidget *widget = GTK_WIDGET (view);
685
GtkAdjustment *adjustment;
688
view->pending_scroll = SCROLL_TO_FIND_LOCATION;
690
adjustment = view->vadjustment;
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);
702
adjustment = view->hadjustment;
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);
714
gtk_widget_queue_resize (GTK_WIDGET (view));
717
/*** Geometry computations ***/
720
compute_border (EvView *view, int width, int height, GtkBorder *border)
722
if (view->presentation) {
728
ev_document_misc_get_page_border_size (width, height, border);
733
get_page_y_offset (EvView *view, int page, double zoom, int *y_offset)
735
int max_width, offset;
738
g_return_if_fail (y_offset != NULL);
740
ev_page_cache_get_max_width (view->page_cache, view->rotation, zoom, &max_width);
742
compute_border (view, max_width, max_width, &border);
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);
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);
759
get_page_extents (EvView *view,
761
GdkRectangle *page_area,
767
widget = GTK_WIDGET (view);
769
/* Get the size of the page */
770
ev_page_cache_get_size (view->page_cache, page,
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;
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) {
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);
796
x = x + MAX (0, widget->allocation.width - (width + view->spacing * 2)) / 2;
799
get_page_y_offset (view, page, view->scale, &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;
812
other_page = (page % 2 == ev_page_cache_get_dual_even_left (view->page_cache)) ? page + 1: page - 1;
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,
821
&width_2, &height_2);
824
if (height_2 > height)
825
max_height = height_2;
827
compute_border (view, max_width, max_height, &overall_border);
829
/* Find the offsets */
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;
837
x = x + (max_width + overall_border.left + overall_border.right) + view->spacing;
839
y = y + (max_height - height)/2;
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;
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;
862
view_point_to_doc_point (EvView *view,
863
GdkPoint *view_point,
864
GdkRectangle *page_area,
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;
873
view_rect_to_doc_rect (EvView *view,
874
GdkRectangle *view_rect,
875
GdkRectangle *page_area,
876
EvRectangle *doc_rect)
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;
885
doc_point_to_view_point (EvView *view,
888
GdkPoint *view_point)
890
GdkRectangle page_area;
892
double x, y, view_x, view_y;
895
ev_page_cache_get_size (view->page_cache, page,
900
if (view->rotation == 0) {
903
} else if (view->rotation == 90) {
904
x = width - doc_point->y;
906
} else if (view->rotation == 180) {
907
x = width - doc_point->x;
908
y = height - doc_point->y;
909
} else if (view->rotation == 270) {
911
y = height - doc_point->x;
913
g_assert_not_reached ();
916
get_page_extents (view, page, &page_area, &border);
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;
923
return (view_x > 0 && view_x <= page_area.width &&
924
view_y > 0 && view_y <= page_area.height);
928
doc_rect_to_view_rect (EvView *view,
930
EvRectangle *doc_rect,
931
GdkRectangle *view_rect)
933
GdkRectangle page_area;
938
ev_page_cache_get_size (view->page_cache, page,
943
if (view->rotation == 0) {
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;
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) {
960
y = height - doc_rect->x2;
961
w = doc_rect->y2 - doc_rect->y1;
962
h = doc_rect->x2 - doc_rect->x1;
964
g_assert_not_reached ();
967
get_page_extents (view, page, &page_area, &border);
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;
976
find_page_at_location (EvView *view,
985
if (view->document == NULL)
992
for (i = view->start_page; i <= view->end_page; i++) {
993
GdkRectangle page_area;
996
if (! get_page_extents (view, i, &page_area, &border))
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)) {
1004
*x_offset = x - (page_area.x + border.left);
1005
*y_offset = y - (page_area.y + border.top);
1014
location_in_text (EvView *view,
1020
gint x_offset = 0, y_offset = 0;
1022
find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
1027
region = ev_pixbuf_cache_get_text_mapping (view->pixbuf_cache, page);
1030
return gdk_region_point_in (region, x_offset / view->scale, y_offset / view->scale);
1036
ev_view_get_width (EvView *view)
1038
return GTK_WIDGET (view)->allocation.width;
1042
ev_view_get_height (EvView *view)
1044
return GTK_WIDGET (view)->allocation.height;
1048
location_in_selected_text (EvView *view,
1053
gint x_offset = 0, y_offset = 0;
1054
EvViewSelection *selection;
1057
for (l = view->selection_info.selections; l != NULL; l = l->next) {
1058
selection = (EvViewSelection *)l->data;
1060
find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
1062
if (page != selection->page)
1065
if (selection->covered_region &&
1066
gdk_region_point_in (selection->covered_region, x_offset, y_offset))
1074
get_doc_point_from_offset (EvView *view,
1084
ev_page_cache_get_size (view->page_cache, page,
1089
x_offset = x_offset / view->scale;
1090
y_offset = y_offset / view->scale;
1092
if (view->rotation == 0) {
1095
} else if (view->rotation == 90) {
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;
1105
g_assert_not_reached ();
1116
ev_view_get_link_at_location (EvView *view,
1121
gint x_offset = 0, y_offset = 0;
1122
gint x_new = 0, y_new = 0;
1123
GList *link_mapping;
1125
if (!EV_IS_DOCUMENT_LINKS (view->document))
1128
x += view->scroll_x;
1129
y += view->scroll_y;
1131
find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
1137
if (get_doc_point_from_offset (view, page, x_offset,
1138
y_offset, &x_new, &y_new) == FALSE)
1141
link_mapping = ev_pixbuf_cache_get_link_mapping (view->pixbuf_cache, page);
1144
return ev_link_mapping_find (link_mapping, x_new, y_new);
1150
goto_fitr_dest (EvView *view, EvLinkDest *dest)
1153
gdouble zoom, left, top;
1154
gboolean change_left, change_top;
1156
left = ev_link_dest_get_left (dest, &change_left);
1157
top = ev_link_dest_get_top (dest, &change_top);
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);
1164
ev_view_set_sizing_mode (view, EV_SIZING_FREE);
1165
ev_view_set_zoom (view, zoom, FALSE);
1167
doc_point.x = change_left ? left : 0;
1168
doc_point.y = change_top ? top : 0;
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;
1175
gtk_widget_queue_resize (GTK_WIDGET (view));
1179
goto_fitv_dest (EvView *view, EvLinkDest *dest)
1182
int doc_width, doc_height, page;
1184
gboolean change_left;
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);
1189
left = ev_link_dest_get_left (dest, &change_left);
1190
doc_point.x = change_left ? left : 0;
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);
1197
ev_view_set_sizing_mode (view, EV_SIZING_FREE);
1198
ev_view_set_zoom (view, zoom, FALSE);
1200
view->current_page = page;
1202
view->pending_point = doc_point;
1203
view->pending_scroll = SCROLL_TO_PAGE_POSITION;
1205
gtk_widget_queue_resize (GTK_WIDGET (view));
1209
goto_fith_dest (EvView *view, EvLinkDest *dest)
1212
int doc_width, doc_height, page;
1214
gboolean change_top;
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);
1219
top = ev_link_dest_get_top (dest, &change_top);
1222
doc_point.y = change_top ? top : 0;
1224
zoom = zoom_for_size_fit_width (doc_width, top,
1225
ev_view_get_width (view),
1226
ev_view_get_height (view), 0);
1228
ev_view_set_sizing_mode (view, EV_SIZING_FIT_WIDTH);
1229
ev_view_set_zoom (view, zoom, FALSE);
1231
view->current_page = page;
1233
view->pending_point = doc_point;
1234
view->pending_scroll = SCROLL_TO_PAGE_POSITION;
1236
gtk_widget_queue_resize (GTK_WIDGET (view));
1240
goto_fit_dest (EvView *view, EvLinkDest *dest)
1243
int doc_width, doc_height;
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);
1249
zoom = zoom_for_size_best_fit (doc_width, doc_height, ev_view_get_width (view),
1250
ev_view_get_height (view), 0, 0);
1252
ev_view_set_sizing_mode (view, EV_SIZING_BEST_FIT);
1253
ev_view_set_zoom (view, zoom, FALSE);
1255
view->current_page = page;
1256
view->pending_scroll = SCROLL_TO_PAGE_POSITION;
1258
gtk_widget_queue_resize (GTK_WIDGET (view));
1262
goto_xyz_dest (EvView *view, EvLinkDest *dest)
1266
gdouble zoom, left, top;
1267
gboolean change_zoom, change_left, change_top;
1269
zoom = ev_link_dest_get_zoom (dest, &change_zoom);
1270
page = ev_link_dest_get_page (dest);
1272
if (change_zoom && zoom > 1) {
1273
ev_view_set_sizing_mode (view, EV_SIZING_FREE);
1274
ev_view_set_zoom (view, zoom, FALSE);
1277
left = ev_link_dest_get_left (dest, &change_left);
1278
top = ev_link_dest_get_top (dest, &change_top);
1280
doc_point.x = change_left ? left : 0;
1281
doc_point.y = change_top ? top : 0;
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;
1288
gtk_widget_queue_resize (GTK_WIDGET (view));
1292
goto_dest (EvView *view, EvLinkDest *dest)
1294
EvLinkDestType type;
1295
int page, n_pages, current_page;
1297
page = ev_link_dest_get_page (dest);
1298
n_pages = ev_page_cache_get_n_pages (view->page_cache);
1300
if (page < 0 || page >= n_pages)
1303
current_page = view->current_page;
1305
type = ev_link_dest_get_dest_type (dest);
1308
case EV_LINK_DEST_TYPE_PAGE:
1309
ev_page_cache_set_current_page (view->page_cache, page);
1311
case EV_LINK_DEST_TYPE_FIT:
1312
goto_fit_dest (view, dest);
1314
case EV_LINK_DEST_TYPE_FITH:
1315
goto_fith_dest (view, dest);
1317
case EV_LINK_DEST_TYPE_FITV:
1318
goto_fitv_dest (view, dest);
1320
case EV_LINK_DEST_TYPE_FITR:
1321
goto_fitr_dest (view, dest);
1323
case EV_LINK_DEST_TYPE_XYZ:
1324
goto_xyz_dest (view, dest);
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));
1330
g_assert_not_reached ();
1333
if (current_page != view->current_page)
1334
ev_page_cache_set_current_page (view->page_cache,
1335
view->current_page);
1339
ev_view_goto_dest (EvView *view, EvLinkDest *dest)
1341
EvLinkDestType type;
1343
type = ev_link_dest_get_dest_type (dest);
1345
if (type == EV_LINK_DEST_TYPE_NAMED) {
1347
const gchar *named_dest;
1349
named_dest = ev_link_dest_get_named_dest (dest);
1350
dest2 = ev_document_links_find_link_dest (EV_DOCUMENT_LINKS (view->document),
1353
goto_dest (view, dest2);
1354
g_object_unref (dest2);
1360
goto_dest (view, dest);
1364
ev_view_handle_link (EvView *view, EvLink *link)
1366
EvLinkAction *action = NULL;
1367
EvLinkActionType type;
1369
action = ev_link_get_action (link);
1373
type = ev_link_action_get_action_type (action);
1376
case EV_LINK_ACTION_TYPE_GOTO_DEST: {
1379
g_signal_emit (view, signals[SIGNAL_HANDLE_LINK], 0, link);
1381
dest = ev_link_action_get_dest (action);
1382
ev_view_goto_dest (view, dest);
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);
1395
ev_view_page_label_from_dest (EvView *view, EvLinkDest *dest)
1397
EvLinkDestType type;
1400
type = ev_link_dest_get_dest_type (dest);
1403
case EV_LINK_DEST_TYPE_NAMED: {
1405
const gchar *named_dest;
1407
named_dest = ev_link_dest_get_named_dest (dest);
1408
dest2 = ev_document_links_find_link_dest (EV_DOCUMENT_LINKS (view->document),
1411
msg = ev_page_cache_get_page_label (view->page_cache,
1412
ev_link_dest_get_page (dest2));
1413
g_object_unref (dest2);
1418
case EV_LINK_DEST_TYPE_PAGE_LABEL: {
1419
msg = g_strdup (ev_link_dest_get_page_label (dest));
1423
msg = ev_page_cache_get_page_label (view->page_cache,
1424
ev_link_dest_get_page (dest));
1431
tip_from_action_named (EvLinkAction *action)
1433
const gchar *name = ev_link_action_get_name (action);
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"));
1453
tip_from_link (EvView *view, EvLink *link)
1455
EvLinkAction *action;
1456
EvLinkActionType type;
1461
action = ev_link_get_action (link);
1462
title = ev_link_get_title (link);
1465
return title ? g_strdup (title) : NULL;
1467
type = ev_link_action_get_action_type (action);
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));
1474
msg = g_strdup_printf (_("Go to page %s"), page_label);
1475
g_free (page_label);
1478
case EV_LINK_ACTION_TYPE_GOTO_REMOTE:
1480
msg = g_strdup_printf (_("Go to %s on file ā%sā"), title,
1481
ev_link_action_get_filename (action));
1483
msg = g_strdup_printf (_("Go to file ā%sā"),
1484
ev_link_action_get_filename (action));
1487
case EV_LINK_ACTION_TYPE_EXTERNAL_URI:
1488
msg = g_strdup (ev_link_action_get_uri (action));
1490
case EV_LINK_ACTION_TYPE_LAUNCH:
1491
msg = g_strdup_printf (_("Launch %s"),
1492
ev_link_action_get_filename (action));
1494
case EV_LINK_ACTION_TYPE_NAMED:
1495
msg = tip_from_action_named (action);
1499
msg = g_strdup (title);
1507
ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y)
1512
if (view->cursor == EV_VIEW_CURSOR_HIDDEN)
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);
1521
if (view->scroll_info.autoscrolling) {
1522
if (view->cursor != EV_VIEW_CURSOR_AUTOSCROLL)
1523
ev_view_set_cursor (view, EV_VIEW_CURSOR_AUTOSCROLL);
1527
link = ev_view_get_link_at_location (view, x, y);
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);
1540
ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK);
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);
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);
1555
ev_view_get_image_at_location (EvView *view,
1560
gint x_offset = 0, y_offset = 0;
1561
gint x_new = 0, y_new = 0;
1562
GList *image_mapping;
1564
if (!EV_IS_DOCUMENT_IMAGES (view->document))
1567
x += view->scroll_x;
1568
y += view->scroll_y;
1570
find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
1575
if (get_doc_point_from_offset (view, page, x_offset,
1576
y_offset, &x_new, &y_new) == FALSE)
1579
image_mapping = ev_pixbuf_cache_get_image_mapping (view->pixbuf_cache, page);
1582
return ev_image_mapping_find (image_mapping, x_new, y_new);
1588
static EvFormField *
1589
ev_view_get_form_field_at_location (EvView *view,
1594
gint x_offset = 0, y_offset = 0;
1595
gint x_new = 0, y_new = 0;
1596
GList *forms_mapping;
1598
if (!EV_IS_DOCUMENT_FORMS (view->document))
1601
x += view->scroll_x;
1602
y += view->scroll_y;
1604
find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
1609
if (get_doc_point_from_offset (view, page, x_offset,
1610
y_offset, &x_new, &y_new) == FALSE)
1613
forms_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, page);
1616
return ev_form_field_mapping_find (forms_mapping, x_new, y_new);
1622
ev_view_form_field_get_region (EvView *view,
1625
EvRectangle field_area;
1626
GdkRectangle view_area;
1627
GList *forms_mapping;
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;
1636
return gdk_region_rectangle (&view_area);
1640
ev_view_forms_remove_widgets (EvView *view)
1642
ev_view_remove_all (view);
1648
ev_view_form_field_destroy (GtkWidget *widget,
1651
g_idle_add ((GSourceFunc)ev_view_forms_remove_widgets, view);
1655
ev_view_form_field_button_create_widget (EvView *view,
1658
EvFormFieldButton *field_button = EV_FORM_FIELD_BUTTON (field);
1659
GdkRegion *field_region = NULL;
1661
switch (field_button->type) {
1662
case EV_FORM_FIELD_BUTTON_PUSH:
1664
case EV_FORM_FIELD_BUTTON_CHECK:
1665
case EV_FORM_FIELD_BUTTON_RADIO: {
1667
GList *forms_mapping, *l;
1669
state = ev_document_forms_form_field_button_get_state (EV_DOCUMENT_FORMS (view->document),
1672
/* FIXME: it actually depends on NoToggleToOff flags */
1673
if (field_button->type == EV_FORM_FIELD_BUTTON_RADIO &&
1674
state && field_button->state)
1677
field_region = ev_view_form_field_get_region (view, field);
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
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;
1688
if (button->id == field->id)
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)
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);
1702
ev_document_forms_form_field_button_set_state (EV_DOCUMENT_FORMS (view->document),
1704
field_button->state = !state;
1709
ev_view_reload_page (view, field->page->index, field_region);
1710
gdk_region_destroy (field_region);
1716
ev_view_form_field_text_save (EvView *view,
1721
if (!view->document)
1724
field = g_object_get_data (G_OBJECT (widget), "form-field");
1726
if (field->changed) {
1727
EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field);
1728
GdkRegion *field_region;
1730
field_region = ev_view_form_field_get_region (view, field);
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);
1741
ev_view_form_field_text_changed (GtkWidget *widget,
1744
EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field);
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;
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);
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;
1766
ev_view_form_field_text_create_widget (EvView *view,
1769
EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field);
1770
GtkWidget *text = NULL;
1773
txt = ev_document_forms_form_field_text_get_text (EV_DOCUMENT_FORMS (view->document),
1776
switch (field_text->type) {
1777
case EV_FORM_FIELD_TEXT_FILE_SELECT:
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);
1786
gtk_entry_set_text (GTK_ENTRY (text), txt);
1790
g_signal_connect (G_OBJECT (text), "changed",
1791
G_CALLBACK (ev_view_form_field_text_changed),
1793
g_signal_connect_after (G_OBJECT (text), "activate",
1794
G_CALLBACK (ev_view_form_field_destroy),
1797
case EV_FORM_FIELD_TEXT_MULTILINE: {
1798
GtkTextBuffer *buffer;
1800
text = gtk_text_view_new ();
1801
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text));
1804
gtk_text_buffer_set_text (buffer, txt, -1);
1808
g_signal_connect (G_OBJECT (buffer), "changed",
1809
G_CALLBACK (ev_view_form_field_text_changed),
1815
g_object_weak_ref (G_OBJECT (text),
1816
(GWeakNotify)ev_view_form_field_text_save,
1823
ev_view_form_field_choice_save (EvView *view,
1828
if (!view->document)
1831
field = g_object_get_data (G_OBJECT (widget), "form-field");
1833
if (field->changed) {
1835
EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field);
1836
GdkRegion *field_region;
1838
field_region = ev_view_form_field_get_region (view, field);
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);
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),
1848
GPOINTER_TO_INT (l->data));
1851
field->changed = FALSE;
1852
ev_view_reload_page (view, field->page->index, field_region);
1853
gdk_region_destroy (field_region);
1858
ev_view_form_field_choice_changed (GtkWidget *widget,
1861
EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field);
1863
if (GTK_IS_COMBO_BOX (widget)) {
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;
1876
if (GTK_IS_COMBO_BOX_ENTRY (widget)) {
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;
1887
} else if (GTK_IS_TREE_SELECTION (widget)) {
1888
GtkTreeSelection *selection = GTK_TREE_SELECTION (widget);
1889
GtkTreeModel *model;
1892
items = gtk_tree_selection_get_selected_rows (selection, &model);
1893
g_list_free (field_choice->selected_items);
1894
field_choice->selected_items = NULL;
1896
for (l = items; l && l->data; l = g_list_next (l)) {
1898
GtkTreePath *path = (GtkTreePath *)l->data;
1901
gtk_tree_model_get_iter (model, &iter, path);
1902
gtk_tree_model_get (model, &iter, 1, &item, -1);
1904
field_choice->selected_items = g_list_prepend (field_choice->selected_items,
1905
GINT_TO_POINTER (item));
1907
gtk_tree_path_free (path);
1910
g_list_free (items);
1912
field->changed = TRUE;
1917
ev_view_form_field_choice_create_widget (EvView *view,
1920
EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field);
1922
GtkTreeModel *model;
1924
gint selected_item = 0;
1926
n_items = ev_document_forms_form_field_choice_get_n_items (EV_DOCUMENT_FORMS (view->document),
1928
model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT));
1929
for (i = 0; i < n_items; i++) {
1933
item = ev_document_forms_form_field_choice_get_item (EV_DOCUMENT_FORMS (view->document),
1935
if (ev_document_forms_form_field_choice_is_item_selected (
1936
EV_DOCUMENT_FORMS (view->document), field, 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));
1944
gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1945
gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1953
if (field_choice->type == EV_FORM_FIELD_CHOICE_LIST) {
1954
GtkCellRenderer *renderer;
1955
GtkWidget *tree_view;
1956
GtkTreeSelection *selection;
1958
tree_view = gtk_tree_view_new_with_model (model);
1959
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
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);
1966
/* TODO: set selected items */
1968
renderer = gtk_cell_renderer_text_new ();
1969
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
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);
1982
g_signal_connect (G_OBJECT (selection), "changed",
1983
G_CALLBACK (ev_view_form_field_choice_changed),
1985
g_signal_connect_after (G_OBJECT (selection), "changed",
1986
G_CALLBACK (ev_view_form_field_destroy),
1988
} else if (field_choice->is_editable) { /* ComboBoxEntry */
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);
1994
gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (choice))), text);
1998
g_signal_connect (G_OBJECT (choice), "changed",
1999
G_CALLBACK (ev_view_form_field_choice_changed),
2001
g_signal_connect_after (G_OBJECT (GTK_BIN (choice)->child), "activate",
2002
G_CALLBACK (ev_view_form_field_destroy),
2004
} else { /* ComboBoxText */
2005
GtkCellRenderer *renderer;
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),
2011
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (choice),
2015
gtk_combo_box_set_active (GTK_COMBO_BOX (choice), selected_item);
2016
gtk_combo_box_popup (GTK_COMBO_BOX (choice));
2018
g_signal_connect (G_OBJECT (choice), "changed",
2019
G_CALLBACK (ev_view_form_field_choice_changed),
2021
g_signal_connect_after (G_OBJECT (choice), "changed",
2022
G_CALLBACK (ev_view_form_field_destroy),
2026
g_object_unref (model);
2028
g_object_weak_ref (G_OBJECT (choice),
2029
(GWeakNotify)ev_view_form_field_choice_save,
2036
ev_view_handle_form_field (EvView *view,
2041
GtkWidget *field_widget = NULL;
2042
GList *form_field_mapping;
2043
EvRectangle field_area;
2044
GdkRectangle view_area;
2046
if (field->is_read_only)
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)) {
2059
/* Form field doesn't require a widget */
2063
g_object_set_data_full (G_OBJECT (field_widget), "form-field",
2064
g_object_ref (field),
2065
(GDestroyNotify)g_object_unref);
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);
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;
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);
2079
/*** GtkWidget implementation ***/
2082
ev_view_size_request_continuous_dual_page (EvView *view,
2083
GtkRequisition *requisition)
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);
2093
n_pages = ev_page_cache_get_n_pages (view->page_cache) + 1;
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);
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;*/
2109
ev_view_size_request_continuous (EvView *view,
2110
GtkRequisition *requisition)
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);
2122
requisition->width = max_width + (view->spacing * 2) + border.left + border.right;
2123
get_page_y_offset (view, n_pages, view->scale, &requisition->height);
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;*/
2136
ev_view_size_request_dual_page (EvView *view,
2137
GtkRequisition *requisition)
2142
/* Find the largest of the two. */
2143
ev_page_cache_get_size (view->page_cache,
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,
2154
&width_2, &height_2);
2155
if (width_2 > width) {
2160
compute_border (view, width, height, &border);
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);
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;
2176
ev_view_size_request_single_page (EvView *view,
2177
GtkRequisition *requisition)
2182
ev_page_cache_get_size (view->page_cache,
2187
compute_border (view, width, height, &border);
2189
requisition->width = width + border.left + border.right + (2 * view->spacing);
2190
requisition->height = height + border.top + border.bottom + (2 * view->spacing);
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;
2202
ev_view_size_request (GtkWidget *widget,
2203
GtkRequisition *requisition)
2205
EvView *view = EV_VIEW (widget);
2207
if (view->document == NULL) {
2208
requisition->width = 1;
2209
requisition->height = 1;
2213
if (view->presentation) {
2214
requisition->width = 1;
2215
requisition->height = 1;
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);
2226
ev_view_size_request_single_page (view, requisition);
2230
ev_view_size_allocate (GtkWidget *widget,
2231
GtkAllocation *allocation)
2233
EvView *view = EV_VIEW (widget);
2234
GList *children, *l;
2236
GTK_WIDGET_CLASS (ev_view_parent_class)->size_allocate (widget, allocation);
2238
if (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
2239
view->sizing_mode == EV_SIZING_BEST_FIT) {
2241
g_signal_emit (view, signals[SIGNAL_ZOOM_INVALID], 0);
2243
ev_view_size_request (widget, &widget->requisition);
2246
view_set_adjustment_values (view, GTK_ORIENTATION_HORIZONTAL);
2247
view_set_adjustment_values (view, GTK_ORIENTATION_VERTICAL);
2250
view_update_range_and_current_page (view);
2252
view->pending_scroll = SCROLL_TO_KEEP_POSITION;
2253
view->pending_resize = FALSE;
2255
children = gtk_container_get_children (GTK_CONTAINER (widget));
2256
for (l = children; l && l->data; l = g_list_next (l)) {
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;
2265
field = g_object_get_data (G_OBJECT (child), "form-field");
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);
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;
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);
2282
gtk_container_child_get (GTK_CONTAINER (widget),
2284
"x", &child_allocation.x,
2285
"y", &child_allocation.y,
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);
2292
g_list_free (children);
2296
ev_view_realize (GtkWidget *widget)
2298
EvView *view = EV_VIEW (widget);
2300
if (GTK_WIDGET_CLASS (ev_view_parent_class)->realize)
2301
(* GTK_WIDGET_CLASS (ev_view_parent_class)->realize) (widget);
2303
gdk_window_set_events (view->layout.bin_window,
2304
(gdk_window_get_events (view->layout.bin_window) |
2306
GDK_BUTTON_PRESS_MASK |
2307
GDK_BUTTON_RELEASE_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));
2315
if (view->presentation)
2316
gdk_window_set_background (view->layout.bin_window, &widget->style->black);
2318
gdk_window_set_background (view->layout.bin_window, &widget->style->mid [GTK_STATE_NORMAL]);
2322
ev_view_scroll_event (GtkWidget *widget, GdkEventScroll *event)
2324
EvView *view = EV_VIEW (widget);
2327
state = event->state & gtk_accelerator_get_default_mod_mask ();
2329
if (state == GDK_CONTROL_MASK && view->presentation == FALSE) {
2330
ev_view_set_sizing_mode (view, EV_SIZING_FREE);
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);
2338
if (ev_view_can_zoom_out (view)) {
2339
ev_view_zoom_out (view);
2346
view->jump_to_find_result = FALSE;
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;
2359
event->state &= ~GDK_SHIFT_MASK;
2360
state &= ~GDK_SHIFT_MASK;
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);
2370
case GDK_SCROLL_LEFT:
2371
ev_view_previous_page (view);
2381
static EvViewSelection *
2382
find_selection_for_page (EvView *view,
2387
for (list = view->selection_info.selections; list != NULL; list = list->next) {
2388
EvViewSelection *selection;
2390
selection = (EvViewSelection *) list->data;
2392
if (selection->page == page)
2400
draw_end_presentation_page (EvView *view,
2401
GdkRectangle *page_area)
2403
PangoLayout *layout;
2404
PangoFontDescription *font_desc;
2406
const gchar *text = _("End of presentation. Press Escape to exit.");
2408
if (view->presentation_state != EV_PRESENTATION_END)
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);
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);
2420
gtk_paint_layout (GTK_WIDGET (view)->style,
2421
view->layout.bin_window,
2422
GTK_WIDGET_STATE (view),
2431
pango_font_description_free (font_desc);
2432
g_object_unref (layout);
2436
ev_view_expose_event (GtkWidget *widget,
2437
GdkEventExpose *event)
2439
EvView *view = EV_VIEW (widget);
2443
if (view->animation && ev_transition_animation_ready (view->animation)) {
2444
GdkRectangle page_area;
2447
if (get_page_extents (view, view->current_page, &page_area, &border)) {
2448
cr = gdk_cairo_create (view->layout.bin_window);
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;
2454
ev_transition_animation_paint (view->animation, cr, page_area);
2461
if (view->presentation) {
2462
switch (view->presentation_state) {
2463
case EV_PRESENTATION_END: {
2464
GdkRectangle area = {0};
2466
area.width = widget->allocation.width;
2467
area.height = widget->allocation.height;
2469
draw_end_presentation_page (view, &area);
2472
case EV_PRESENTATION_BLACK:
2473
case EV_PRESENTATION_WHITE:
2475
case EV_PRESENTATION_NORMAL:
2479
} else if (view->loading) {
2480
GdkRectangle area = {0};
2482
area.width = widget->allocation.width;
2483
area.height = widget->allocation.height;
2485
draw_loading_text (view,
2490
if (view->document == NULL)
2493
cr = gdk_cairo_create (view->layout.bin_window);
2495
for (i = view->start_page; i <= view->end_page; i++) {
2496
GdkRectangle page_area;
2498
gboolean page_ready = TRUE;
2500
if (!get_page_extents (view, i, &page_area, &border))
2503
page_area.x -= view->scroll_x;
2504
page_area.y -= view->scroll_y;
2506
draw_one_page (view, i, cr, &page_area, &border, &(event->area), &page_ready);
2508
if (page_ready && view->find_pages && view->highlight_find_results)
2509
highlight_find_results (view, i);
2514
if (GTK_WIDGET_CLASS (ev_view_parent_class)->expose_event)
2515
(* GTK_WIDGET_CLASS (ev_view_parent_class)->expose_event) (widget, event);
2521
ev_view_do_popup_menu (EvView *view,
2528
image = ev_view_get_image_at_location (view, x, y);
2530
g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, image);
2534
link = ev_view_get_link_at_location (view, x, y);
2536
g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, link);
2540
g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, NULL);
2546
ev_view_popup_menu (GtkWidget *widget)
2550
gtk_widget_get_pointer (widget, &x, &y);
2551
return ev_view_do_popup_menu (EV_VIEW (widget), x, y);
2555
get_link_area (EvView *view,
2561
EvRectangle ev_rect;
2562
GList *link_mapping;
2564
gint x_offset = 0, y_offset = 0;
2566
x += view->scroll_x;
2567
y += view->scroll_y;
2569
find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
2571
link_mapping = ev_pixbuf_cache_get_link_mapping (view->pixbuf_cache, page);
2572
ev_link_mapping_get_area (link_mapping, link, &ev_rect);
2574
doc_rect_to_view_rect (view, page, &ev_rect, area);
2575
area->y -= view->scroll_y ;
2579
ev_view_query_tooltip (GtkWidget *widget,
2582
gboolean keyboard_tip,
2583
GtkTooltip *tooltip)
2585
EvView *view = EV_VIEW (widget);
2589
link = ev_view_get_link_at_location (view, x, y);
2593
text = tip_from_link (view, link);
2594
if (text && g_utf8_validate (text, -1, NULL)) {
2595
GdkRectangle link_area;
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);
2607
start_selection_for_event (EvView *view,
2608
GdkEventButton *event)
2610
EvSelectionStyle style;
2612
clear_selection (view);
2614
view->selection_info.start.x = event->x + view->scroll_x;
2615
view->selection_info.start.y = event->y + view->scroll_y;
2617
switch (event->type) {
2618
case GDK_2BUTTON_PRESS:
2619
style = EV_SELECTION_STYLE_WORD;
2621
case GDK_3BUTTON_PRESS:
2622
style = EV_SELECTION_STYLE_LINE;
2625
style = EV_SELECTION_STYLE_GLYPH;
2629
view->selection_info.style = style;
2633
ev_view_button_press_event (GtkWidget *widget,
2634
GdkEventButton *event)
2636
EvView *view = EV_VIEW (widget);
2638
if (!view->document)
2641
if (!GTK_WIDGET_HAS_FOCUS (widget)) {
2642
gtk_widget_grab_focus (widget);
2645
view->pressed_button = event->button;
2646
view->selection_info.in_drag = FALSE;
2648
if (view->scroll_info.autoscrolling)
2651
switch (event->button) {
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;
2664
start_selection_for_event (view, event);
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;
2678
view->image_dnd_info.start.x = event->x + view->scroll_x;
2679
view->image_dnd_info.start.y = event->y + view->scroll_y;
2681
ev_view_remove_all (view);
2683
if (EV_IS_SELECTION (view->document))
2684
start_selection_for_event (view, event);
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);
2696
ev_view_set_cursor (view, EV_VIEW_CURSOR_DRAG);
2700
view->scroll_info.start_y = event->y;
2701
return ev_view_do_popup_menu (view, event->x, event->y);
2708
ev_view_remove_all (EvView *view)
2710
GList *children, *child;
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));
2717
g_list_free (children);
2720
/*** Drag and Drop ***/
2722
ev_view_drag_data_get (GtkWidget *widget,
2723
GdkDragContext *context,
2724
GtkSelectionData *selection_data,
2728
EvView *view = EV_VIEW (widget);
2731
case TARGET_DND_TEXT:
2732
if (EV_IS_SELECTION (view->document) &&
2733
view->selection_info.selections) {
2736
text = get_selected_text (view);
2737
gtk_selection_data_set_text (selection_data,
2743
case TARGET_DND_IMAGE:
2744
if (view->image_dnd_info.image) {
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 ();
2752
gtk_selection_data_set_pixbuf (selection_data, pixbuf);
2753
g_object_unref (pixbuf);
2756
case TARGET_DND_URI:
2757
if (view->image_dnd_info.image) {
2759
const gchar *tmp_uri;
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 ();
2767
tmp_uri = ev_image_save_tmp (view->image_dnd_info.image, pixbuf);
2768
g_object_unref (pixbuf);
2770
uris = g_new0 (gchar *, 2);
2771
uris[0] = (gchar *)tmp_uri;
2773
gtk_selection_data_set_uris (selection_data, uris);
2775
/* g_free instead of g_strfreev since tmp_uri is const */
2782
ev_view_drag_motion (GtkWidget *widget,
2783
GdkDragContext *context,
2788
if (gtk_drag_get_source_widget (context) == widget)
2789
gdk_drag_status (context, 0, time);
2791
gdk_drag_status (context, context->suggested_action, time);
2797
ev_view_drag_data_received (GtkWidget *widget,
2798
GdkDragContext *context,
2801
GtkSelectionData *selection_data,
2807
GSList *uri_list = NULL;
2809
uris = gtk_selection_data_get_uris (selection_data);
2811
gtk_drag_finish (context, FALSE, FALSE, time);
2815
for (i = 0; uris[i]; i++) {
2816
uri_list = g_slist_prepend (uri_list, (gpointer) uris[i]);
2819
ev_application_open_uri_list (EV_APP, uri_list,
2820
gtk_widget_get_screen (widget),
2822
gtk_drag_finish (context, TRUE, FALSE, time);
2825
g_slist_free (uri_list);
2830
selection_update_idle_cb (EvView *view)
2832
compute_selections (view,
2833
view->selection_info.style,
2834
&view->selection_info.start,
2836
view->selection_update_id = 0;
2841
selection_scroll_timeout_cb (EvView *view)
2843
gint x, y, shift = 0;
2844
GtkWidget *widget = GTK_WIDGET (view);
2846
gtk_widget_get_pointer (widget, &x, &y);
2848
if (y > widget->allocation.height) {
2849
shift = (y - widget->allocation.height) / 2;
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));
2861
if (x > widget->allocation.width) {
2862
shift = (x - widget->allocation.width) / 2;
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));
2878
ev_view_drag_update_momentum (EvView *view)
2881
if (!view->drag_info.in_drag)
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;
2889
/* Momentum is a moving average of 10ms granularity over
2890
* the last 100ms with each 10ms stored in buffer.
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);
2900
ev_view_scroll_drag_release (EvView *view)
2902
gdouble dhadj_value, dvadj_value;
2903
gdouble oldhadjustment, oldvadjustment;
2905
view->drag_info.momentum.x /= 1.2;
2906
view->drag_info.momentum.y /= 1.2; /* Alter these constants to change "friction" */
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;
2913
oldhadjustment = gtk_adjustment_get_value (view->hadjustment);
2914
oldvadjustment = gtk_adjustment_get_value (view->vadjustment);
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;
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));
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)))
2938
ev_view_motion_notify_event (GtkWidget *widget,
2939
GdkEventMotion *event)
2941
EvView *view = EV_VIEW (widget);
2944
if (!view->document)
2948
if (event->is_hint || event->window != view->layout.bin_window) {
2949
gtk_widget_get_pointer (widget, &x, &y);
2955
if (view->scroll_info.autoscrolling) {
2956
view->scroll_info.last_y = y;
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,
2965
GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
2967
gtk_target_list_add_text_targets (target_list, TARGET_DND_TEXT);
2969
gtk_drag_begin (widget, target_list,
2971
1, (GdkEvent *)event);
2973
view->selection_info.in_drag = FALSE;
2975
gtk_target_list_unref (target_list);
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,
2984
GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
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);
2989
gtk_drag_begin (widget, target_list,
2991
1, (GdkEvent *)event);
2993
view->image_dnd_info.in_drag = FALSE;
2995
gtk_target_list_unref (target_list);
3001
switch (view->pressed_button) {
3003
/* For the Evince 0.4.x release, we limit selection to un-rotated
3006
if (view->rotation != 0)
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,
3016
selection_scroll_timeout_cb (view);
3018
view->selection_info.in_selection = TRUE;
3019
view->motion.x = x + view->scroll_x;
3020
view->motion.y = y + view->scroll_y;
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
3027
if (!view->selection_update_id)
3028
view->selection_update_id = g_idle_add ((GSourceFunc)selection_update_idle_cb, view);
3032
if (!view->drag_info.in_drag) {
3036
start = gtk_drag_check_threshold (widget,
3037
view->drag_info.start.x,
3038
view->drag_info.start.y,
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;
3050
view->drag_info.momentum.x = 0;
3051
view->drag_info.momentum.y = 0;
3054
if (view->drag_info.in_drag) {
3056
gdouble dhadj_value, dvadj_value;
3058
view->drag_info.buffer[0].x = event->x;
3059
view->drag_info.buffer[0].y = event->y;
3061
dx = event->x_root - view->drag_info.start.x;
3062
dy = event->y_root - view->drag_info.start.y;
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;
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));
3084
ev_view_handle_cursor_over_xy (view, x, y);
3091
ev_view_button_release_event (GtkWidget *widget,
3092
GdkEventButton *event)
3094
EvView *view = EV_VIEW (widget);
3095
EvLink *link = NULL;
3097
view->image_dnd_info.in_drag = FALSE;
3099
if (view->scroll_info.autoscrolling) {
3100
ev_view_autoscroll_stop (view);
3101
view->pressed_button = -1;
3106
if (view->drag_info.in_drag) {
3107
view->drag_info.release_timeout_id =
3109
(GSourceFunc)ev_view_scroll_drag_release, view);
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);
3116
view->drag_info.in_drag = FALSE;
3118
if (view->pressed_button == 2) {
3119
ev_view_handle_cursor_over_xy (view, event->x, event->y);
3122
view->pressed_button = -1;
3124
if (view->selection_scroll_id) {
3125
g_source_remove (view->selection_scroll_id);
3126
view->selection_scroll_id = 0;
3128
if (view->selection_update_id) {
3129
g_source_remove (view->selection_update_id);
3130
view->selection_update_id = 0;
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));
3141
if (view->selection_info.selections) {
3142
clear_link_selected (view);
3143
ev_view_update_primary_selection (view);
3145
if (view->selection_info.in_drag) {
3146
clear_selection (view);
3147
gtk_widget_queue_draw (widget);
3150
view->selection_info.in_drag = FALSE;
3152
if (event->button == 2) {
3153
EvLinkAction *action;
3154
EvLinkActionType type;
3156
action = ev_link_get_action (link);
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],
3167
ev_view_handle_link (view, link);
3169
} else if (view->presentation) {
3170
switch (event->button) {
3172
ev_view_next_page (view);
3175
ev_view_previous_page (view);
3184
/* Cut and paste from gtkwindow.c */
3186
send_focus_change (GtkWidget *widget,
3189
GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
3191
g_object_ref (widget);
3194
GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
3196
GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
3198
fevent->focus_change.type = GDK_FOCUS_CHANGE;
3199
fevent->focus_change.window = g_object_ref (widget->window);
3200
fevent->focus_change.in = in;
3202
gtk_widget_event (widget, fevent);
3204
g_object_notify (G_OBJECT (widget), "has-focus");
3206
g_object_unref (widget);
3207
gdk_event_free (fevent);
3211
ev_view_goto_window_hide (EvView *view)
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), "");
3220
ev_view_goto_window_delete_event (GtkWidget *widget,
3224
ev_view_goto_window_hide (view);
3230
key_is_numeric (guint keyval)
3232
return ((keyval >= GDK_0 && keyval <= GDK_9) ||
3233
(keyval >= GDK_KP_0 && keyval <= GDK_KP_9));
3237
ev_view_goto_window_key_press_event (GtkWidget *widget,
3241
switch (event->keyval) {
3245
case GDK_ISO_Left_Tab:
3246
ev_view_goto_window_hide (view);
3255
if (!key_is_numeric (event->keyval))
3263
ev_view_goto_window_button_press_event (GtkWidget *widget,
3264
GdkEventButton *event,
3267
ev_view_goto_window_hide (view);
3273
ev_view_goto_entry_activate (GtkEntry *entry,
3279
text = gtk_entry_get_text (entry);
3280
page = atoi (text) - 1;
3282
ev_view_goto_window_hide (view);
3285
page < ev_page_cache_get_n_pages (view->page_cache))
3286
ev_page_cache_set_current_page (view->page_cache, page);
3290
ev_view_goto_window_create (EvView *view)
3292
GtkWidget *frame, *hbox, *toplevel, *label;
3294
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view));
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));
3306
view->goto_window = gtk_window_new (GTK_WINDOW_POPUP);
3308
if (GTK_WINDOW (toplevel)->group)
3309
gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
3310
GTK_WINDOW (view->goto_window));
3312
gtk_window_set_modal (GTK_WINDOW (view->goto_window), TRUE);
3314
g_signal_connect (view->goto_window, "delete_event",
3315
G_CALLBACK (ev_view_goto_window_delete_event),
3317
g_signal_connect (view->goto_window, "key_press_event",
3318
G_CALLBACK (ev_view_goto_window_key_press_event),
3320
g_signal_connect (view->goto_window, "button_press_event",
3321
G_CALLBACK (ev_view_goto_window_button_press_event),
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);
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);
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);
3339
view->goto_entry = gtk_entry_new ();
3340
g_signal_connect (view->goto_entry, "activate",
3341
G_CALLBACK (ev_view_goto_entry_activate),
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);
3349
ev_view_goto_entry_grab_focus (EvView *view)
3351
GtkWidgetClass *entry_parent_class;
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);
3356
send_focus_change (view->goto_entry, TRUE);
3360
ev_view_goto_window_send_key_event (EvView *view,
3363
GdkEventKey *new_event;
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);
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);
3378
gtk_widget_event (view->goto_window, (GdkEvent *)new_event);
3379
gdk_event_free ((GdkEvent *)new_event);
3380
gtk_widget_hide (view->goto_window);
3384
ev_view_key_press_event (GtkWidget *widget,
3387
EvView *view = EV_VIEW (widget);
3388
EvPresentationState current;
3390
if (!view->document)
3393
if (!view->presentation ||
3394
view->presentation_state == EV_PRESENTATION_END)
3395
return gtk_bindings_activate_event (GTK_OBJECT (widget), event);
3398
current = view->presentation_state;
3400
switch (event->keyval) {
3404
case GDK_KP_Decimal:
3405
view->presentation_state =
3406
(view->presentation_state == EV_PRESENTATION_BLACK) ?
3407
EV_PRESENTATION_NORMAL : EV_PRESENTATION_BLACK;
3411
view->presentation_state =
3412
(view->presentation_state == EV_PRESENTATION_WHITE) ?
3413
EV_PRESENTATION_NORMAL : EV_PRESENTATION_WHITE;
3416
if (view->presentation_state == EV_PRESENTATION_BLACK ||
3417
view->presentation_state == EV_PRESENTATION_WHITE) {
3418
view->presentation_state = EV_PRESENTATION_NORMAL;
3422
if (current == view->presentation_state) {
3423
if (ev_page_cache_get_n_pages (view->page_cache) > 1 &&
3424
key_is_numeric (event->keyval)) {
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);
3437
return gtk_bindings_activate_event (GTK_OBJECT (widget), event);
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);
3446
case EV_PRESENTATION_WHITE:
3447
gdk_window_set_background (view->layout.bin_window,
3448
&widget->style->white);
3451
return gtk_bindings_activate_event (GTK_OBJECT (widget), event);
3454
gtk_widget_queue_draw (widget);
3459
ev_view_focus_in (GtkWidget *widget,
3460
GdkEventFocus *event)
3462
if (EV_VIEW (widget)->pixbuf_cache)
3463
ev_pixbuf_cache_style_changed (EV_VIEW (widget)->pixbuf_cache);
3464
gtk_widget_queue_draw (widget);
3470
ev_view_focus_out (GtkWidget *widget,
3471
GdkEventFocus *event)
3473
if (EV_VIEW (widget)->goto_window)
3474
ev_view_goto_window_hide (EV_VIEW (widget));
3476
if (EV_VIEW (widget)->pixbuf_cache)
3477
ev_pixbuf_cache_style_changed (EV_VIEW (widget)->pixbuf_cache);
3478
gtk_widget_queue_draw (widget);
3484
ev_view_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event)
3486
EvView *view = EV_VIEW (widget);
3488
if (view->cursor != EV_VIEW_CURSOR_NORMAL)
3489
ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
3495
ev_view_enter_notify_event (GtkWidget *widget, GdkEventCrossing *event)
3497
EvView *view = EV_VIEW (widget);
3499
ev_view_handle_cursor_over_xy (view, event->x, event->y);
3505
ev_view_style_set (GtkWidget *widget,
3506
GtkStyle *old_style)
3508
if (EV_VIEW (widget)->pixbuf_cache)
3509
ev_pixbuf_cache_style_changed (EV_VIEW (widget)->pixbuf_cache);
3511
GTK_WIDGET_CLASS (ev_view_parent_class)->style_set (widget, old_style);
3517
ev_gdk_color_to_rgb (const GdkColor *color)
3520
result = (0xff0000 | (color->red & 0xff00));
3522
result |= ((color->green & 0xff00) | (color->blue >> 8));
3527
draw_rubberband (GtkWidget *widget, GdkWindow *window,
3528
const GdkRectangle *rect, guchar alpha)
3532
GdkColor *fill_color_gdk;
3535
fill_color_gdk = gdk_color_copy (>K_WIDGET (widget)->style->base[GTK_STATE_SELECTED]);
3536
fill_color = ev_gdk_color_to_rgb (fill_color_gdk) << 8 | alpha;
3538
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
3539
rect->width, rect->height);
3540
gdk_pixbuf_fill (pixbuf, fill_color);
3542
gdk_draw_pixbuf (window, NULL, pixbuf,
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,
3549
g_object_unref (pixbuf);
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,
3557
g_object_unref (gc);
3559
gdk_color_free (fill_color_gdk);
3564
highlight_find_results (EvView *view, int page)
3566
gint i, n_results = 0;
3568
n_results = ev_view_find_get_n_results (view, page);
3570
for (i = 0; i < n_results; i++) {
3571
EvRectangle *rectangle;
3572
GdkRectangle view_rectangle;
3575
if (i == view->find_result && page == view->current_page) {
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);
3589
draw_loading_text (EvView *view,
3590
GdkRectangle *page_area,
3591
GdkRectangle *expose_area)
3596
if (!view->loading_text) {
3597
const gchar *loading_text = _("Loading...");
3598
PangoLayout *layout;
3599
PangoFontDescription *font_desc;
3600
PangoRectangle logical_rect;
3604
ev_document_fc_mutex_lock ();
3606
layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), loading_text);
3608
font_desc = pango_font_description_new ();
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);
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);
3621
view->loading_text = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
3623
logical_rect.height);
3624
cr = cairo_create (view->loading_text);
3625
cairo_set_source_rgb (cr,
3629
pango_cairo_show_layout (cr, layout);
3632
pango_font_description_free (font_desc);
3633
g_object_unref (layout);
3635
ev_document_fc_mutex_unlock ();
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;
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);
3651
draw_one_page (EvView *view,
3654
GdkRectangle *page_area,
3656
GdkRectangle *expose_area,
3657
gboolean *page_ready)
3659
GdkRectangle overlap;
3660
GdkRectangle real_page_area;
3662
g_assert (view->document);
3664
if (! gdk_rectangle_intersect (page_area, expose_area, &overlap))
3667
/* Render the document itself */
3668
real_page_area = *page_area;
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);
3676
if (!view->presentation) {
3679
current_page = ev_page_cache_get_current_page (view->page_cache);
3680
ev_document_misc_paint_one_page (view->layout.bin_window,
3683
page == current_page);
3686
if (gdk_rectangle_intersect (&real_page_area, expose_area, &overlap)) {
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;
3693
page_surface = ev_pixbuf_cache_get_surface (view->pixbuf_cache, page);
3695
if (!page_surface) {
3696
if (!view->presentation) {
3697
draw_loading_text (view,
3702
*page_ready = FALSE;
3707
ev_page_cache_get_size (view->page_cache,
3708
page, view->rotation,
3712
page_width = cairo_image_surface_get_width (page_surface);
3713
page_height = cairo_image_surface_get_height (page_surface);
3716
cairo_translate (cr, overlap.x, overlap.y);
3718
if (width != page_width || height != page_height) {
3719
cairo_pattern_set_filter (cairo_get_source (cr),
3722
(gdouble)width / page_width,
3723
(gdouble)height / page_height);
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);
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) {
3737
ev_pixbuf_cache_get_selection_surface (view->pixbuf_cache,
3743
if (!selection_surface) {
3747
selection_width = cairo_image_surface_get_width (selection_surface);
3748
selection_height = cairo_image_surface_get_height (selection_surface);
3751
cairo_translate (cr, overlap.x, overlap.y);
3753
if (width != selection_width || height != selection_height) {
3754
cairo_pattern_set_filter (cairo_get_source (cr),
3757
(gdouble)width / selection_width,
3758
(gdouble)height / selection_height);
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);
3770
/*** GObject functions ***/
3773
ev_view_finalize (GObject *object)
3775
EvView *view = EV_VIEW (object);
3777
clear_selection (view);
3778
clear_link_selected (view);
3780
if (view->image_dnd_info.image)
3781
g_object_unref (view->image_dnd_info.image);
3782
view->image_dnd_info.image = NULL;
3784
G_OBJECT_CLASS (ev_view_parent_class)->finalize (object);
3788
ev_view_destroy (GtkObject *object)
3790
EvView *view = EV_VIEW (object);
3792
if (view->document) {
3793
g_object_unref (view->document);
3794
view->document = NULL;
3797
if (view->pixbuf_cache) {
3798
g_object_unref (view->pixbuf_cache);
3799
view->pixbuf_cache = NULL;
3802
if (view->goto_window) {
3803
gtk_widget_destroy (view->goto_window);
3804
view->goto_window = NULL;
3805
view->goto_entry = NULL;
3808
if (view->selection_scroll_id) {
3809
g_source_remove (view->selection_scroll_id);
3810
view->selection_scroll_id = 0;
3813
if (view->selection_update_id) {
3814
g_source_remove (view->selection_update_id);
3815
view->selection_update_id = 0;
3818
if (view->loading_text) {
3819
cairo_surface_destroy (view->loading_text);
3820
view->loading_text = NULL;
3823
if (view->scroll_info.timeout_id) {
3824
g_source_remove (view->scroll_info.timeout_id);
3825
view->scroll_info.timeout_id = 0;
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;
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;
3838
ev_view_presentation_transition_stop (view);
3840
ev_view_set_scroll_adjustments (GTK_LAYOUT (view), NULL, NULL);
3842
GTK_OBJECT_CLASS (ev_view_parent_class)->destroy (object);
3846
ev_view_set_property (GObject *object,
3848
const GValue *value,
3851
EvView *view = EV_VIEW (object);
3854
case PROP_CONTINUOUS:
3855
ev_view_set_continuous (view, g_value_get_boolean (value));
3857
case PROP_DUAL_PAGE:
3858
ev_view_set_dual_page (view, g_value_get_boolean (value));
3860
case PROP_FULLSCREEN:
3861
ev_view_set_fullscreen (view, g_value_get_boolean (value));
3863
case PROP_PRESENTATION:
3864
ev_view_set_presentation (view, g_value_get_boolean (value));
3866
case PROP_SIZING_MODE:
3867
ev_view_set_sizing_mode (view, g_value_get_enum (value));
3870
ev_view_set_zoom (view, g_value_get_double (value), FALSE);
3873
ev_view_set_rotation (view, g_value_get_int (value));
3876
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3881
ev_view_get_accessible (GtkWidget *widget)
3883
static gboolean first_time = TRUE;
3886
AtkObjectFactory *factory;
3887
AtkRegistry *registry;
3889
GType derived_atk_type;
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.
3896
derived_type = g_type_parent (EV_TYPE_VIEW);
3898
registry = atk_get_default_registry ();
3899
factory = atk_registry_get_factory (registry,
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,
3905
ev_view_accessible_factory_get_type ());
3908
return GTK_WIDGET_CLASS (ev_view_parent_class)->get_accessible (widget);
3912
ev_view_get_property (GObject *object,
3917
EvView *view = EV_VIEW (object);
3920
case PROP_CONTINUOUS:
3921
g_value_set_boolean (value, view->continuous);
3923
case PROP_DUAL_PAGE:
3924
g_value_set_boolean (value, view->dual_page);
3926
case PROP_FULLSCREEN:
3927
g_value_set_boolean (value, view->fullscreen);
3929
case PROP_PRESENTATION:
3930
g_value_set_boolean (value, view->presentation);
3932
case PROP_SIZING_MODE:
3933
g_value_set_enum (value, view->sizing_mode);
3936
g_value_set_double (value, view->scale);
3939
g_value_set_int (value, view->rotation);
3941
case PROP_HAS_SELECTION:
3942
g_value_set_boolean (value,
3943
view->selection_info.selections != NULL);
3946
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3951
ev_view_class_init (EvViewClass *class)
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;
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;
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;
3984
gtk_object_class->destroy = ev_view_destroy;
3986
layout_class->set_scroll_adjustments = ev_view_set_scroll_adjustments;
3988
class->binding_activated = ev_view_scroll;
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),
3995
ev_marshal_VOID__ENUM_BOOLEAN,
3997
GTK_TYPE_SCROLL_TYPE,
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),
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),
4012
g_cclosure_marshal_VOID__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),
4020
g_cclosure_marshal_VOID__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),
4028
g_cclosure_marshal_VOID__OBJECT,
4033
g_object_class_install_property (object_class,
4035
g_param_spec_boolean ("continuous",
4037
"Continuous scrolling mode",
4039
G_PARAM_READWRITE));
4041
g_object_class_install_property (object_class,
4043
g_param_spec_boolean ("dual-page",
4045
"Two pages visible at once",
4047
G_PARAM_READWRITE));
4048
g_object_class_install_property (object_class,
4050
g_param_spec_boolean ("fullscreen",
4052
"Draw page in a fullscreen fashion",
4054
G_PARAM_READWRITE));
4055
g_object_class_install_property (object_class,
4057
g_param_spec_boolean ("presentation",
4059
"Draw page in presentation mode",
4061
G_PARAM_READWRITE));
4063
g_object_class_install_property (object_class,
4065
g_param_spec_enum ("sizing-mode",
4068
EV_TYPE_SIZING_MODE,
4069
EV_SIZING_FIT_WIDTH,
4070
G_PARAM_READWRITE));
4072
g_object_class_install_property (object_class,
4074
g_param_spec_double ("zoom",
4080
G_PARAM_READWRITE));
4081
g_object_class_install_property (object_class,
4083
g_param_spec_double ("rotation",
4089
G_PARAM_READWRITE));
4090
g_object_class_install_property (object_class,
4092
g_param_spec_boolean ("has-selection",
4094
"The view has selections",
4098
binding_set = gtk_binding_set_by_class (class);
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);
4120
ev_view_init (EvView *view)
4122
GTK_WIDGET_SET_FLAGS (view, GTK_CAN_FOCUS);
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;
4145
gtk_layout_set_hadjustment (GTK_LAYOUT (view), NULL);
4146
gtk_layout_set_vadjustment (GTK_LAYOUT (view), NULL);
4148
gtk_drag_dest_set (GTK_WIDGET (view),
4149
GTK_DEST_DEFAULT_ALL,
4151
G_N_ELEMENTS (view_drop_targets),
4158
ev_view_change_page (EvView *view,
4160
gboolean start_transition)
4164
view->current_page = new_page;
4165
view->pending_scroll = SCROLL_TO_PAGE_POSITION;
4167
if (view->presentation && start_transition)
4168
ev_view_presentation_transition_start (view);
4170
gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
4171
ev_view_handle_cursor_over_xy (view, x, y);
4173
gtk_widget_queue_resize (GTK_WIDGET (view));
4177
ev_view_transition_animation_finish (EvTransitionAnimation *animation,
4180
g_object_unref (view->animation);
4181
view->animation = NULL;
4182
ev_view_change_page (view, view->current_page, TRUE);
4186
* ev_view_transition_animation_cancel:
4187
* @animation: Animation to finish
4190
* Does almost the same as cancel, but without scheduling the transition.
4194
ev_view_transition_animation_cancel (EvTransitionAnimation *animation,
4197
g_object_unref (view->animation);
4198
view->animation = NULL;
4199
ev_view_change_page (view, view->current_page, FALSE);
4203
ev_view_transition_animation_frame (EvTransitionAnimation *animation,
4207
gtk_widget_queue_draw (GTK_WIDGET (view));
4211
ev_view_presentation_animation_start (EvView *view,
4214
EvTransitionEffect *effect = NULL;
4215
cairo_surface_t *surface;
4217
if (EV_IS_DOCUMENT_TRANSITION (view->document))
4218
effect = ev_document_transition_get_effect (EV_DOCUMENT_TRANSITION (view->document),
4219
view->current_page);
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);
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);
4234
job_finished_cb (EvPixbufCache *pixbuf_cache,
4238
if (view->animation) {
4239
cairo_surface_t *surface;
4241
surface = ev_pixbuf_cache_get_surface (pixbuf_cache, view->current_page);
4242
ev_transition_animation_set_dest_surface (view->animation, surface);
4246
gdk_window_invalidate_region (view->layout.bin_window,
4249
gtk_widget_queue_draw (GTK_WIDGET (view));
4254
page_changed_cb (EvPageCache *page_cache,
4258
if (view->current_page != new_page) {
4259
if (view->presentation)
4260
ev_view_presentation_animation_start (view, new_page);
4262
ev_view_change_page (view, new_page, TRUE);
4264
gtk_widget_queue_draw (GTK_WIDGET (view));
4267
view->find_result = 0;
4271
on_adjustment_value_changed (GtkAdjustment *adjustment,
4276
GList *children, *l;
4278
if (! GTK_WIDGET_REALIZED (view))
4281
if (view->hadjustment) {
4282
dx = view->scroll_x - (int) view->hadjustment->value;
4283
view->scroll_x = (int) view->hadjustment->value;
4288
if (view->vadjustment) {
4289
dy = view->scroll_y - (int) view->vadjustment->value;
4290
view->scroll_y = (int) view->vadjustment->value;
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;
4300
gtk_container_child_get (GTK_CONTAINER (view),
4305
gtk_layout_move (GTK_LAYOUT (view), child, child_x + dx, child_y + dy);
4307
g_list_free (children);
4309
if (view->pending_resize)
4310
gtk_widget_queue_draw (GTK_WIDGET (view));
4312
gdk_window_scroll (view->layout.bin_window, dx, dy);
4314
gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
4315
ev_view_handle_cursor_over_xy (view, x, y);
4318
view_update_range_and_current_page (view);
4326
view = g_object_new (EV_TYPE_VIEW, NULL);
4332
setup_caches (EvView *view)
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),
4344
clear_caches (EvView *view)
4346
if (view->pixbuf_cache) {
4347
g_object_unref (view->pixbuf_cache);
4348
view->pixbuf_cache = NULL;
4351
if (view->page_cache) {
4352
view->page_cache = NULL;
4357
ev_view_set_loading (EvView *view,
4360
view->loading = loading;
4361
gtk_widget_queue_draw (GTK_WIDGET (view));
4365
ev_view_autoscroll_cb (EvView *view)
4367
gdouble speed, value;
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;
4376
if (view->scroll_info.last_y > view->scroll_info.start_y &&
4377
(view->scroll_info.last_y < view->scroll_info.start_y))
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) */
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);
4388
speed = pow ((((gdouble)view->scroll_info.last_y - view->scroll_info.start_y) / 100), 3);
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);
4399
ev_view_autoscroll_start (EvView *view)
4403
g_return_if_fail (EV_IS_VIEW (view));
4405
if (view->scroll_info.autoscrolling)
4408
view->scroll_info.autoscrolling = TRUE;
4409
view->scroll_info.timeout_id =
4410
g_timeout_add (20, (GSourceFunc)ev_view_autoscroll_cb,
4413
gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
4414
ev_view_handle_cursor_over_xy (view, x, y);
4418
ev_view_autoscroll_stop (EvView *view)
4422
g_return_if_fail (EV_IS_VIEW (view));
4424
if (!view->scroll_info.autoscrolling)
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;
4433
gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
4434
ev_view_handle_cursor_over_xy (view, x, y);
4438
ev_view_set_document (EvView *view,
4439
EvDocument *document)
4441
g_return_if_fail (EV_IS_VIEW (view));
4443
view->loading = FALSE;
4445
if (document != view->document) {
4446
clear_caches (view);
4448
if (view->document) {
4449
g_object_unref (view->document);
4450
view->page_cache = NULL;
4453
view->document = document;
4454
view->find_result = 0;
4456
if (view->document) {
4457
g_object_ref (view->document);
4458
setup_caches (view);
4461
gtk_widget_queue_resize (GTK_WIDGET (view));
4466
ev_view_reload_page (EvView *view,
4470
ev_pixbuf_cache_reload_page (view->pixbuf_cache,
4478
ev_view_reload (EvView *view)
4480
ev_pixbuf_cache_clear (view->pixbuf_cache);
4481
view_update_range_and_current_page (view);
4484
/*** Zoom and sizing mode ***/
4486
#define EPSILON 0.0000001
4488
ev_view_set_zoom (EvView *view,
4495
scale = view->scale * factor;
4499
scale = CLAMP (scale,
4500
view->sizing_mode == EV_SIZING_FREE ? view->min_scale : 0,
4503
if (ABS (view->scale - scale) < EPSILON)
4506
if (view->loading_text) {
4507
cairo_surface_destroy (view->loading_text);
4508
view->loading_text = NULL;
4511
view->scale = scale;
4512
view->pending_resize = TRUE;
4514
gtk_widget_queue_resize (GTK_WIDGET (view));
4516
g_object_notify (G_OBJECT (view), "zoom");
4520
ev_view_get_zoom (EvView *view)
4526
ev_view_set_screen_dpi (EvView *view,
4529
g_return_if_fail (EV_IS_VIEW (view));
4530
g_return_if_fail (dpi > 0);
4533
view->min_scale = MIN_SCALE * dpi / 72.0;
4534
view->max_scale = MAX_SCALE * dpi / 72.0;
4538
ev_view_get_continuous (EvView *view)
4540
g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
4542
return view->continuous;
4546
ev_view_set_continuous (EvView *view,
4547
gboolean continuous)
4549
g_return_if_fail (EV_IS_VIEW (view));
4551
continuous = continuous != FALSE;
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));
4559
g_object_notify (G_OBJECT (view), "continuous");
4563
ev_view_get_dual_page (EvView *view)
4565
g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
4567
return view->dual_page;
4571
ev_view_set_dual_page (EvView *view,
4574
g_return_if_fail (EV_IS_VIEW (view));
4576
dual_page = dual_page != FALSE;
4578
if (view->dual_page == dual_page)
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.
4586
gtk_widget_queue_resize (GTK_WIDGET (view));
4588
g_object_notify (G_OBJECT (view), "dual-page");
4592
ev_view_set_fullscreen (EvView *view,
4593
gboolean fullscreen)
4595
g_return_if_fail (EV_IS_VIEW (view));
4597
fullscreen = fullscreen != FALSE;
4599
if (view->fullscreen == fullscreen)
4602
view->fullscreen = fullscreen;
4603
gtk_widget_queue_resize (GTK_WIDGET (view));
4605
g_object_notify (G_OBJECT (view), "fullscreen");
4609
ev_view_get_fullscreen (EvView *view)
4611
g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
4613
return view->fullscreen;
4617
ev_view_set_presentation (EvView *view,
4618
gboolean presentation)
4620
g_return_if_fail (EV_IS_VIEW (view));
4622
presentation = presentation != FALSE;
4624
if (view->presentation == presentation)
4628
view->presentation_state = EV_PRESENTATION_NORMAL;
4630
view->presentation = presentation;
4631
view->pending_scroll = SCROLL_TO_PAGE_POSITION;
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);
4638
ev_view_set_sizing_mode (view, view->sizing_mode_saved);
4639
ev_view_set_zoom (view, view->scale_saved, FALSE);
4642
gtk_widget_queue_resize (GTK_WIDGET (view));
4645
ev_view_presentation_transition_start (view);
4647
ev_view_presentation_transition_stop (view);
4649
if (view->animation) {
4650
/* stop any running animation */
4651
ev_view_transition_animation_cancel (view->animation, view);
4655
if (GTK_WIDGET_REALIZED (view)) {
4656
if (view->presentation)
4657
gdk_window_set_background (view->layout.bin_window,
4658
>K_WIDGET (view)->style->black);
4660
gdk_window_set_background (view->layout.bin_window,
4661
>K_WIDGET (view)->style->mid [GTK_STATE_NORMAL]);
4664
g_object_notify (G_OBJECT (view), "presentation");
4668
ev_view_get_presentation (EvView *view)
4670
g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
4672
return view->presentation;
4676
transition_next_page (EvView *view)
4678
ev_view_next_page (view);
4684
ev_view_presentation_transition_stop (EvView *view)
4686
if (view->trans_timeout_id > 0)
4687
g_source_remove (view->trans_timeout_id);
4688
view->trans_timeout_id = 0;
4692
ev_view_presentation_transition_start (EvView *view)
4696
if (!EV_IS_DOCUMENT_TRANSITION (view->document))
4699
ev_view_presentation_transition_stop (view);
4701
duration = ev_document_transition_get_page_duration (EV_DOCUMENT_TRANSITION (view->document),
4702
view->current_page);
4704
view->trans_timeout_id =
4705
g_timeout_add_seconds (duration,
4706
(GSourceFunc) transition_next_page,
4712
ev_view_set_sizing_mode (EvView *view,
4713
EvSizingMode sizing_mode)
4715
g_return_if_fail (EV_IS_VIEW (view));
4717
if (view->sizing_mode == sizing_mode)
4720
view->sizing_mode = sizing_mode;
4721
gtk_widget_queue_resize (GTK_WIDGET (view));
4723
g_object_notify (G_OBJECT (view), "sizing-mode");
4727
ev_view_get_sizing_mode (EvView *view)
4729
g_return_val_if_fail (EV_IS_VIEW (view), EV_SIZING_FREE);
4731
return view->sizing_mode;
4735
ev_view_can_zoom_in (EvView *view)
4737
return view->scale * ZOOM_IN_FACTOR <= view->max_scale;
4741
ev_view_can_zoom_out (EvView *view)
4743
return view->scale * ZOOM_OUT_FACTOR >= view->min_scale;
4747
ev_view_zoom_in (EvView *view)
4749
g_return_if_fail (view->sizing_mode == EV_SIZING_FREE);
4751
if (view->presentation)
4754
view->pending_scroll = SCROLL_TO_CENTER;
4755
ev_view_set_zoom (view, ZOOM_IN_FACTOR, TRUE);
4759
ev_view_zoom_out (EvView *view)
4761
g_return_if_fail (view->sizing_mode == EV_SIZING_FREE);
4763
if (view->presentation)
4766
view->pending_scroll = SCROLL_TO_CENTER;
4767
ev_view_set_zoom (view, ZOOM_OUT_FACTOR, TRUE);
4771
ev_view_rotate_right (EvView *view)
4773
int rotation = view->rotation + 90;
4775
if (rotation >= 360) {
4779
ev_view_set_rotation (view, rotation);
4783
ev_view_rotate_left (EvView *view)
4785
int rotation = view->rotation - 90;
4791
ev_view_set_rotation (view, rotation);
4795
ev_view_set_rotation (EvView *view, int rotation)
4797
view->rotation = rotation;
4799
if (view->pixbuf_cache) {
4800
ev_pixbuf_cache_clear (view->pixbuf_cache);
4801
gtk_widget_queue_resize (GTK_WIDGET (view));
4805
clear_selection (view);
4807
g_object_notify (G_OBJECT (view), "rotation");
4811
ev_view_get_rotation (EvView *view)
4813
return view->rotation;
4817
zoom_for_size_fit_width (int doc_width,
4825
scale = (double)target_width / doc_width;
4827
if (doc_height * scale > target_height)
4828
scale = (double) (target_width - vsb_width) / doc_width;
4834
zoom_for_size_fit_height (int doc_width,
4842
scale = (double)target_height / doc_height;
4844
if (doc_width * scale > target_width)
4845
scale = (double) (target_height - vsb_height) / doc_height;
4851
zoom_for_size_best_fit (int doc_width,
4861
w_scale = (double)target_width / doc_width;
4862
h_scale = (double)target_height / doc_height;
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;
4869
return MIN (w_scale, h_scale);
4874
ev_view_zoom_for_size_presentation (EvView *view,
4878
int doc_width, doc_height;
4881
ev_page_cache_get_size (view->page_cache,
4887
scale = zoom_for_size_best_fit (doc_width, doc_height, width, height, 0, 0);
4888
ev_view_set_zoom (view, scale, FALSE);
4892
ev_view_zoom_for_size_continuous_and_dual_page (EvView *view,
4898
int doc_width, doc_height;
4902
ev_page_cache_get_max_width (view->page_cache,
4906
ev_page_cache_get_max_height (view->page_cache,
4910
compute_border (view, doc_width, doc_height, &border);
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);
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);
4924
g_assert_not_reached ();
4926
ev_view_set_zoom (view, scale, FALSE);
4930
ev_view_zoom_for_size_continuous (EvView *view,
4936
int doc_width, doc_height;
4940
ev_page_cache_get_max_width (view->page_cache,
4944
ev_page_cache_get_max_height (view->page_cache,
4948
compute_border (view, doc_width, doc_height, &border);
4950
width -= (border.left + border.right + 2 * view->spacing);
4951
height -= (border.top + border.bottom + 2 * view->spacing - 1);
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);
4961
g_assert_not_reached ();
4963
ev_view_set_zoom (view, scale, FALSE);
4967
ev_view_zoom_for_size_dual_page (EvView *view,
4974
gint doc_width, doc_height;
4978
other_page = view->current_page ^ 1;
4980
/* Find the largest of the two. */
4981
ev_page_cache_get_size (view->page_cache,
4985
&doc_width, &doc_height);
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,
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;
4999
compute_border (view, doc_width, doc_height, &border);
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);
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);
5010
g_assert_not_reached ();
5012
ev_view_set_zoom (view, scale, FALSE);
5016
ev_view_zoom_for_size_single_page (EvView *view,
5022
int doc_width, doc_height;
5026
ev_page_cache_get_size (view->page_cache,
5032
/* Get an approximate border */
5033
compute_border (view, width, height, &border);
5035
width -= (border.left + border.right + 2 * view->spacing);
5036
height -= (border.top + border.bottom + 2 * view->spacing);
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);
5043
g_assert_not_reached ();
5045
ev_view_set_zoom (view, scale, FALSE);
5049
ev_view_set_zoom_for_size (EvView *view,
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);
5061
if (view->document == NULL)
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);
5073
ev_view_zoom_for_size_single_page (view, width, height, vsb_width, hsb_height);
5078
ev_view_find_get_n_results (EvView *view, gint page)
5080
return view->find_pages ? g_list_length (view->find_pages[page]) : 0;
5083
static EvRectangle *
5084
ev_view_find_get_result (EvView *view, gint page, gint result)
5086
return view->find_pages ? (EvRectangle *) g_list_nth_data (view->find_pages[page], result) : NULL;
5090
jump_to_find_result (EvView *view)
5093
gint page = view->current_page;
5095
n_results = ev_view_find_get_n_results (view, page);
5097
if (n_results > 0 && view->find_result < n_results) {
5099
GdkRectangle view_rect;
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;
5110
* @view: #EvView instance
5111
* @direction: Direction to look
5112
* @shift: Shift from current page
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.
5119
jump_to_find_page (EvView *view, EvViewFindDirection direction, gint shift)
5123
n_pages = ev_page_cache_get_n_pages (view->page_cache);
5125
for (i = 0; i < n_pages; i++) {
5128
if (direction == EV_VIEW_FIND_NEXT)
5129
page = view->current_page + i;
5131
page = view->current_page - i;
5134
if (page >= n_pages) {
5135
page = page - n_pages;
5136
} else if (page < 0)
5137
page = page + n_pages;
5139
if (ev_view_find_get_n_results (view, page) > 0) {
5140
ev_page_cache_set_current_page (view->page_cache, page);
5147
ev_view_find_changed (EvView *view, GList **results, gint page)
5149
view->find_pages = results;
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);
5156
if (view->current_page == page)
5157
gtk_widget_queue_draw (GTK_WIDGET (view));
5161
ev_view_find_next (EvView *view)
5165
n_results = ev_view_find_get_n_results (view, view->current_page);
5166
view->find_result++;
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);
5173
jump_to_find_result (view);
5174
gtk_widget_queue_draw (GTK_WIDGET (view));
5179
ev_view_find_previous (EvView *view)
5181
view->find_result--;
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);
5188
jump_to_find_result (view);
5189
gtk_widget_queue_draw (GTK_WIDGET (view));
5194
ev_view_find_search_changed (EvView *view)
5196
/* search string has changed, focus on new search result */
5197
view->jump_to_find_result = TRUE;
5198
view->find_pages = NULL;
5202
ev_view_find_set_highlight_search (EvView *view, gboolean value)
5204
view->highlight_find_results = value;
5205
gtk_widget_queue_draw (GTK_WIDGET (view));
5209
ev_view_find_cancel (EvView *view)
5211
view->find_pages = NULL;
5214
/*** Selections ***/
5216
/* compute_new_selection_rect/text calculates the area currently selected by
5217
* view_rect. each handles a different mode;
5220
compute_new_selection_rect (EvView *view,
5224
GdkRectangle view_rect;
5228
g_assert (view->selection_mode == EV_VIEW_SELECTION_RECTANGLE);
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;
5235
n_pages = ev_page_cache_get_n_pages (view->page_cache);
5237
for (i = 0; i < n_pages; i++) {
5238
GdkRectangle page_area;
5241
if (get_page_extents (view, i, &page_area, &border)) {
5242
GdkRectangle overlap;
5244
if (gdk_rectangle_intersect (&page_area, &view_rect, &overlap)) {
5245
EvViewSelection *selection;
5247
selection = g_new0 (EvViewSelection, 1);
5248
selection->page = i;
5249
view_rect_to_doc_rect (view, &overlap, &page_area,
5250
&(selection->rect));
5252
list = g_list_append (list, selection);
5261
gdk_rectangle_point_in (GdkRectangle *rectangle,
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;
5271
compute_new_selection_text (EvView *view,
5272
EvSelectionStyle style,
5276
int n_pages, i, first, last;
5278
EvViewSelection *selection;
5280
int start_page, end_page;
5282
g_assert (view->selection_mode == EV_VIEW_SELECTION_TEXT);
5284
n_pages = ev_page_cache_get_n_pages (view->page_cache);
5286
/* First figure out the range of pages the selection
5290
if (view->continuous) {
5293
} else if (view->dual_page) {
5294
start_page = view->start_page;
5295
end_page = view->end_page + 1;
5297
start_page = view->current_page;
5298
end_page = view->current_page + 1;
5301
for (i = start_page; i < end_page; i++) {
5302
GdkRectangle page_area;
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)
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;
5323
ev_page_cache_get_size (view->page_cache, i,
5325
1.0, &width, &height);
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;
5334
get_page_extents (view, i, &page_area, &border);
5336
if (gdk_rectangle_point_in (&page_area, start))
5342
view_point_to_doc_point (view, point, &page_area,
5343
&selection->rect.x1,
5344
&selection->rect.y1);
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. */
5353
view_point_to_doc_point (view, point, &page_area,
5354
&selection->rect.x2,
5355
&selection->rect.y2);
5357
list = g_list_append (list, selection);
5363
/* This function takes the newly calculated list, and figures out which regions
5364
* have changed. It then queues a redraw approporiately.
5367
merge_selection_region (EvView *view,
5371
GList *new_list_ptr, *old_list_ptr;
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");
5381
new_list_ptr = new_list;
5382
old_list_ptr = old_list;
5384
while (new_list_ptr || old_list_ptr) {
5385
EvViewSelection *old_sel, *new_sel;
5387
GdkRegion *region = NULL;
5389
new_sel = (new_list_ptr) ? (new_list_ptr->data) : NULL;
5390
old_sel = (old_list_ptr) ? (old_list_ptr->data) : NULL;
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;
5399
} else if (new_sel->page > old_sel->page) {
5400
old_list_ptr = old_list_ptr->next;
5403
new_list_ptr = new_list_ptr->next;
5404
old_list_ptr = old_list_ptr->next;
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;
5412
g_assert (new_sel || old_sel);
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)
5419
/* seed the cache with a new page. We are going to need the new
5422
GdkRegion *tmp_region = NULL;
5424
ev_pixbuf_cache_get_selection_surface (view->pixbuf_cache,
5430
new_sel->covered_region = gdk_region_copy (tmp_region);
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);
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);
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);
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);
5460
g_assert_not_reached ();
5463
/* Redraw the damaged region! */
5465
GdkRectangle page_area;
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
5472
gdk_region_shrink (region, -5, -5);
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);
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);
5489
compute_selections (EvView *view,
5490
EvSelectionStyle style,
5496
if (view->selection_mode == EV_VIEW_SELECTION_RECTANGLE)
5497
list = compute_new_selection_rect (view, start, stop);
5499
list = compute_new_selection_text (view, style, start, stop);
5500
merge_selection_region (view, list);
5503
/* Free's the selection. It's up to the caller to queue redraws if needed.
5506
selection_free (EvViewSelection *selection)
5508
if (selection->covered_region)
5509
gdk_region_destroy (selection->covered_region);
5514
clear_selection (EvView *view)
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");
5526
ev_view_select_all (EvView *view)
5528
GList *selections = NULL;
5531
/* Disable selection on rotated pages for the 0.4.0 series */
5532
if (view->rotation != 0)
5535
clear_selection (view);
5537
n_pages = ev_page_cache_get_n_pages (view->page_cache);
5538
for (i = 0; i < n_pages; i++) {
5540
EvViewSelection *selection;
5542
ev_page_cache_get_size (view->page_cache,
5545
1.0, &width, &height);
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;
5554
selections = g_list_append (selections, selection);
5557
merge_selection_region (view, selections);
5558
gtk_widget_queue_draw (GTK_WIDGET (view));
5562
ev_view_get_has_selection (EvView *view)
5564
return view->selection_info.selections != NULL;
5568
get_selected_text (EvView *view)
5572
gchar *normalized_text;
5573
EvRenderContext *rc;
5575
text = g_string_new (NULL);
5576
rc = ev_render_context_new (NULL, view->rotation, view->scale);
5578
ev_document_doc_mutex_lock ();
5580
for (l = view->selection_info.selections; l != NULL; l = l->next) {
5581
EvViewSelection *selection = (EvViewSelection *)l->data;
5585
page = ev_document_get_page (view->document, selection->page);
5586
ev_render_context_set_page (rc, page);
5587
g_object_unref (page);
5589
tmp = ev_selection_get_selected_text (EV_SELECTION (view->document),
5590
rc, selection->style,
5591
&(selection->rect));
5593
g_string_append (text, tmp);
5597
g_object_unref (rc);
5599
ev_document_doc_mutex_unlock ();
5601
normalized_text = g_utf8_normalize (text->str, text->len, G_NORMALIZE_NFKC);
5602
g_string_free (text, TRUE);
5603
return normalized_text;
5607
ev_view_clipboard_copy (EvView *view,
5610
GtkClipboard *clipboard;
5612
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view),
5613
GDK_SELECTION_CLIPBOARD);
5614
gtk_clipboard_set_text (clipboard, text, -1);
5618
ev_view_copy (EvView *ev_view)
5622
if (!EV_IS_SELECTION (ev_view->document))
5625
text = get_selected_text (ev_view);
5626
ev_view_clipboard_copy (ev_view, text);
5631
ev_view_primary_get_cb (GtkClipboard *clipboard,
5632
GtkSelectionData *selection_data,
5636
EvView *ev_view = EV_VIEW (data);
5638
if (ev_view->link_selected) {
5639
gtk_selection_data_set_text (selection_data,
5640
ev_link_action_get_uri (ev_view->link_selected),
5642
} else if (EV_IS_SELECTION (ev_view->document) &&
5643
ev_view->selection_info.selections) {
5646
text = get_selected_text (ev_view);
5648
gtk_selection_data_set_text (selection_data, text, -1);
5655
ev_view_primary_clear_cb (GtkClipboard *clipboard,
5658
EvView *view = EV_VIEW (data);
5660
clear_selection (view);
5661
clear_link_selected (view);
5665
ev_view_update_primary_selection (EvView *ev_view)
5667
GtkClipboard *clipboard;
5669
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (ev_view),
5670
GDK_SELECTION_PRIMARY);
5672
if (ev_view->selection_info.selections || ev_view->link_selected) {
5673
if (!gtk_clipboard_set_with_owner (clipboard,
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);
5681
if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (ev_view))
5682
gtk_clipboard_clear (clipboard);
5687
clear_link_selected (EvView *view)
5689
if (view->link_selected) {
5690
g_object_unref (view->link_selected);
5691
view->link_selected = NULL;
5696
ev_view_copy_link_address (EvView *view,
5697
EvLinkAction *action)
5699
clear_link_selected (view);
5701
ev_view_clipboard_copy (view, ev_link_action_get_uri (action));
5703
view->link_selected = g_object_ref (action);
5704
ev_view_update_primary_selection (view);
5707
/*** Cursor operations ***/
5710
ev_view_create_invisible_cursor(void)
5713
GdkColor black = { 0, 0, 0, 0 };
5714
static char bits[] = { 0x00 };
5716
empty = gdk_bitmap_create_from_data (NULL, bits, 1, 1);
5718
return gdk_cursor_new_from_pixmap (empty, empty, &black, &black, 0, 0);
5722
ev_view_set_cursor (EvView *view, EvViewCursor new_cursor)
5724
GdkCursor *cursor = NULL;
5725
GdkDisplay *display;
5728
if (view->cursor == new_cursor) {
5732
widget = gtk_widget_get_toplevel (GTK_WIDGET (view));
5733
display = gtk_widget_get_display (widget);
5734
view->cursor = new_cursor;
5736
switch (new_cursor) {
5737
case EV_VIEW_CURSOR_NORMAL:
5738
gdk_window_set_cursor (view->layout.bin_window, NULL);
5740
case EV_VIEW_CURSOR_IBEAM:
5741
cursor = gdk_cursor_new_for_display (display, GDK_XTERM);
5743
case EV_VIEW_CURSOR_LINK:
5744
cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
5746
case EV_VIEW_CURSOR_WAIT:
5747
cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
5749
case EV_VIEW_CURSOR_HIDDEN:
5750
cursor = ev_view_create_invisible_cursor ();
5752
case EV_VIEW_CURSOR_DRAG:
5753
cursor = gdk_cursor_new_for_display (display, GDK_FLEUR);
5755
case EV_VIEW_CURSOR_AUTOSCROLL:
5756
cursor = gdk_cursor_new_for_display (display, GDK_DOUBLE_ARROW);
5761
gdk_window_set_cursor (view->layout.bin_window, cursor);
5762
gdk_cursor_unref (cursor);
5768
ev_view_hide_cursor (EvView *view)
5770
ev_view_set_cursor (view, EV_VIEW_CURSOR_HIDDEN);
5774
ev_view_show_cursor (EvView *view)
5776
ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
5780
ev_view_reset_presentation_state (EvView *view)
5782
if (!view->presentation ||
5783
view->presentation_state == EV_PRESENTATION_NORMAL)
5786
view->presentation_state = EV_PRESENTATION_NORMAL;
5787
gdk_window_set_background (view->layout.bin_window,
5788
>K_WIDGET (view)->style->black);
5789
gtk_widget_queue_draw (GTK_WIDGET (view));
5793
ev_view_next_page (EvView *view)
5797
g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
5799
if (!view->page_cache)
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);
5809
if (view->animation) {
5810
ev_view_transition_animation_cancel (view->animation, view);
5813
ev_view_presentation_transition_stop (view);
5814
ev_view_reset_presentation_state (view);
5816
page = ev_page_cache_get_current_page (view->page_cache);
5817
n_pages = ev_page_cache_get_n_pages (view->page_cache);
5819
if (view->dual_page && !view->presentation)
5824
if (page < n_pages) {
5825
ev_page_cache_set_current_page (view->page_cache, page);
5827
} else if (view->presentation && page == n_pages) {
5828
view->presentation_state = EV_PRESENTATION_END;
5829
gtk_widget_queue_draw (GTK_WIDGET (view));
5831
} else if (view->dual_page && page == n_pages) {
5832
ev_page_cache_set_current_page (view->page_cache, page - 1);
5840
ev_view_previous_page (EvView *view)
5844
g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
5846
if (!view->page_cache)
5849
if (view->presentation &&
5850
view->presentation_state == EV_PRESENTATION_END) {
5851
ev_view_reset_presentation_state (view);
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);
5862
if (view->animation) {
5863
ev_view_transition_animation_cancel (view->animation, view);
5866
ev_view_reset_presentation_state (view);
5868
page = ev_page_cache_get_current_page (view->page_cache);
5870
if (view->dual_page && !view->presentation)
5876
ev_page_cache_set_current_page (view->page_cache, page);
5878
} else if (ev_view_get_dual_page (view) && page == -1) {
5879
ev_page_cache_set_current_page (view->page_cache, 0);
5886
/*** Enum description for usage in signal ***/
5889
ev_sizing_mode_get_type (void)
5891
static GType 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" },
5899
etype = g_enum_register_static ("EvSizingMode", values);
5905
ev_view_update_view_size (EvView *view, GtkScrolledWindow * scrolled_window)
5908
GtkRequisition vsb_requisition;
5909
GtkRequisition hsb_requisition;
5910
int scrollbar_spacing;
5912
/* Calculate the width available for the content */
5913
width = GTK_WIDGET (scrolled_window)->allocation.width;
5914
height = GTK_WIDGET (scrolled_window)->allocation.height;
5916
if (gtk_scrolled_window_get_shadow_type (scrolled_window) == GTK_SHADOW_IN
5918
width -= 2 * GTK_WIDGET(view)->style->xthickness;
5919
height -= 2 * GTK_WIDGET(view)->style->ythickness;
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",
5929
if (EV_IS_VIEW(view)) {
5930
ev_view_set_zoom_for_size (EV_VIEW (view),
5933
vsb_requisition.width + scrollbar_spacing,
5934
hsb_requisition.height + scrollbar_spacing);