Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ev-view.c
Go to the documentation of this file.
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /* this file is part of evince, a gnome document viewer
3  *
4  * Copyright (C) 2004 Red Hat, Inc
5  *
6  * Evince is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Evince is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20 
21 #include "config.h"
22 
23 #include <stdlib.h>
24 #include <math.h>
25 #include <string.h>
26 
27 #include <glib/gi18n-lib.h>
28 #include <gtk/gtk.h>
29 #include <gdk/gdkkeysyms.h>
30 
31 #include "ev-mapping-list.h"
32 #include "ev-document-forms.h"
33 #include "ev-document-images.h"
34 #include "ev-document-links.h"
35 #include "ev-document-layers.h"
36 #include "ev-document-media.h"
37 #include "ev-document-misc.h"
38 #include "ev-pixbuf-cache.h"
39 #include "ev-page-cache.h"
40 #include "ev-view-marshal.h"
42 #include "ev-annotation-window.h"
43 #include "ev-view.h"
44 #include "ev-view-accessible.h"
45 #include "ev-view-private.h"
46 #include "ev-view-type-builtins.h"
47 #include "ev-debug.h"
48 
49 #ifdef ENABLE_MULTIMEDIA
50 #include "ev-media-player.h"
51 #endif
52 
53 enum {
67 };
68 
69 enum {
73 };
74 
75 enum {
84 };
85 
86 static guint signals[N_SIGNALS];
87 
88 typedef enum {
92 
93 typedef struct {
94  GtkWidget *widget;
95 
96  /* View coords */
97  gint x;
98  gint y;
99 
100  /* Document */
101  guint page;
103 } EvViewChild;
104 
105 #define MIN_SCALE 0.2
106 #define ZOOM_IN_FACTOR 1.2
107 #define ZOOM_OUT_FACTOR (1.0/ZOOM_IN_FACTOR)
108 
109 #define SCROLL_TIME 150
110 
111 #define DEFAULT_PIXBUF_CACHE_SIZE 52428800 /* 50MB */
112 
113 #define EV_STYLE_CLASS_DOCUMENT_PAGE "document-page"
114 #define EV_STYLE_CLASS_INVERTED "inverted"
115 
116 #define ANNOT_POPUP_WINDOW_DEFAULT_WIDTH 200
117 #define ANNOT_POPUP_WINDOW_DEFAULT_HEIGHT 150
118 #define ANNOTATION_ICON_SIZE 24
119 
120 /*** Scrolling ***/
121 static void view_update_range_and_current_page (EvView *view);
122 static void ensure_rectangle_is_visible (EvView *view,
123  GdkRectangle *rect);
124 
125 /*** Geometry computations ***/
126 static void compute_border (EvView *view,
127  GtkBorder *border);
128 static void get_page_y_offset (EvView *view,
129  int page,
130  int *y_offset);
131 static void find_page_at_location (EvView *view,
132  gdouble x,
133  gdouble y,
134  gint *page,
135  gint *x_offset,
136  gint *y_offset);
137 /*** Hyperrefs ***/
139  gdouble x,
140  gdouble y);
141 static char* tip_from_link (EvView *view,
142  EvLink *link);
143 /*** Forms ***/
145  gdouble x,
146  gdouble y);
147 /*** Media ***/
149  gdouble x,
150  gdouble y);
151 static gboolean ev_view_find_player_for_media (EvView *view,
152  EvMedia *media);
153 /*** Annotations ***/
154 static GtkWidget *get_window_for_annot (EvView *view,
155  EvAnnotation *annot);
156 static void map_annot_to_window (EvView *view,
157  EvAnnotation *annot,
158  GtkWidget *window);
160  gdouble x,
161  gdouble y);
162 static void show_annotation_windows (EvView *view,
163  gint page);
164 static void hide_annotation_windows (EvView *view,
165  gint page);
166 /*** GtkWidget implementation ***/
168  GtkRequisition *requisition);
169 static void ev_view_size_request_continuous (EvView *view,
170  GtkRequisition *requisition);
171 static void ev_view_size_request_dual_page (EvView *view,
172  GtkRequisition *requisition);
173 static void ev_view_size_request_single_page (EvView *view,
174  GtkRequisition *requisition);
175 static void ev_view_size_request (GtkWidget *widget,
176  GtkRequisition *requisition);
177 static void ev_view_size_allocate (GtkWidget *widget,
178  GtkAllocation *allocation);
179 static gboolean ev_view_scroll_event (GtkWidget *widget,
180  GdkEventScroll *event);
181 static gboolean ev_view_draw (GtkWidget *widget,
182  cairo_t *cr);
183 static gboolean ev_view_popup_menu (GtkWidget *widget);
184 static gboolean ev_view_button_press_event (GtkWidget *widget,
185  GdkEventButton *event);
186 static gboolean ev_view_motion_notify_event (GtkWidget *widget,
187  GdkEventMotion *event);
188 static gboolean ev_view_button_release_event (GtkWidget *widget,
189  GdkEventButton *event);
190 static gboolean ev_view_enter_notify_event (GtkWidget *widget,
191  GdkEventCrossing *event);
192 static gboolean ev_view_leave_notify_event (GtkWidget *widget,
193  GdkEventCrossing *event);
194 static void ev_view_style_updated (GtkWidget *widget);
195 static void ev_view_remove_all (EvView *view);
196 static void ev_view_remove_all_form_fields (EvView *view);
197 
198 static AtkObject *ev_view_get_accessible (GtkWidget *widget);
199 
200 /*** Drawing ***/
201 static void highlight_find_results (EvView *view,
202  cairo_t *cr,
203  int page);
204 static void highlight_forward_search_results (EvView *view,
205  cairo_t *cr,
206  int page);
207 static void draw_one_page (EvView *view,
208  gint page,
209  cairo_t *cr,
210  GdkRectangle *page_area,
211  GtkBorder *border,
212  GdkRectangle *expose_area,
213  gboolean *page_ready);
214 static void ev_view_reload_page (EvView *view,
215  gint page,
216  cairo_region_t *region);
217 /*** Callbacks ***/
218 static void ev_view_change_page (EvView *view,
219  gint new_page);
220 static void job_finished_cb (EvPixbufCache *pixbuf_cache,
221  cairo_region_t *region,
222  EvView *view);
223 static void ev_view_page_changed_cb (EvDocumentModel *model,
224  gint old_page,
225  gint new_page,
226  EvView *view);
227 static void on_adjustment_value_changed (GtkAdjustment *adjustment,
228  EvView *view);
229 /*** GObject ***/
230 static void ev_view_finalize (GObject *object);
231 static void ev_view_dispose (GObject *object);
232 static void ev_view_class_init (EvViewClass *class);
233 static void ev_view_init (EvView *view);
234 
235 /*** Zoom and sizing ***/
236 static double zoom_for_size_fit_width (gdouble doc_width,
237  gdouble doc_height,
238  int target_width,
239  int target_height);
240 static double zoom_for_size_fit_height (gdouble doc_width,
241  gdouble doc_height,
242  int target_width,
243  int target_height);
244 static double zoom_for_size_fit_page (gdouble doc_width,
245  gdouble doc_height,
246  int target_width,
247  int target_height);
248 static double zoom_for_size_automatic (GdkScreen *screen,
249  gdouble doc_width,
250  gdouble doc_height,
251  int target_width,
252  int target_height);
253 static void ev_view_zoom (EvView *view,
254  gdouble factor);
255 static void ev_view_zoom_for_size (EvView *view,
256  int width,
257  int height);
259  int width,
260  int height);
261 static void ev_view_zoom_for_size_continuous (EvView *view,
262  int width,
263  int height);
264 static void ev_view_zoom_for_size_dual_page (EvView *view,
265  int width,
266  int height);
267 static void ev_view_zoom_for_size_single_page (EvView *view,
268  int width,
269  int height);
270 static gboolean ev_view_page_fits (EvView *view,
271  GtkOrientation orientation);
272 /*** Cursors ***/
273 static void ev_view_set_cursor (EvView *view,
274  EvViewCursor new_cursor);
275 static void ev_view_handle_cursor_over_xy (EvView *view,
276  gint x,
277  gint y);
278 
279 /*** Find ***/
280 static gint ev_view_find_get_n_results (EvView *view,
281  gint page);
283  gint page,
284  gint result);
285 static void jump_to_find_result (EvView *view);
286 static void jump_to_find_page (EvView *view,
287  EvViewFindDirection direction,
288  gint shift);
289 /*** Selection ***/
290 static void compute_selections (EvView *view,
291  EvSelectionStyle style,
292  GdkPoint *start,
293  GdkPoint *stop);
294 static void extend_selection (EvView *view,
295  GdkPoint *start,
296  GdkPoint *stop);
297 static void clear_selection (EvView *view);
298 static void clear_link_selected (EvView *view);
299 static void selection_free (EvViewSelection *selection);
300 static char* get_selected_text (EvView *ev_view);
301 static void ev_view_primary_get_cb (GtkClipboard *clipboard,
302  GtkSelectionData *selection_data,
303  guint info,
304  gpointer data);
305 static void ev_view_primary_clear_cb (GtkClipboard *clipboard,
306  gpointer data);
307 static void ev_view_update_primary_selection (EvView *ev_view);
308 
309 /*** Caret navigation ***/
310 static void ev_view_check_cursor_blink (EvView *ev_view);
311 
312 G_DEFINE_TYPE_WITH_CODE (EvView, ev_view, GTK_TYPE_CONTAINER,
313  G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
314 
315 /* HeightToPage cache */
316 #define EV_HEIGHT_TO_PAGE_CACHE_KEY "ev-height-to-page-cache"
317 
318 static void
319 ev_view_build_height_to_page_cache (EvView *view,
320  EvHeightToPageCache *cache)
321 {
322  gboolean swap, uniform;
323  int i;
324  double uniform_height, page_height, next_page_height;
325  double saved_height;
326  gdouble u_width, u_height;
327  gint n_pages;
328  EvDocument *document = view->document;
329 
330  swap = (view->rotation == 90 || view->rotation == 270);
331 
332  uniform = ev_document_is_page_size_uniform (document);
333  n_pages = ev_document_get_n_pages (document);
334 
335  g_free (cache->height_to_page);
336  g_free (cache->dual_height_to_page);
337 
338  cache->rotation = view->rotation;
339  cache->dual_even_left = view->dual_even_left;
340  cache->height_to_page = g_new0 (gdouble, n_pages + 1);
341  cache->dual_height_to_page = g_new0 (gdouble, n_pages + 2);
342 
343  if (uniform)
344  ev_document_get_page_size (document, 0, &u_width, &u_height);
345 
346  saved_height = 0;
347  for (i = 0; i <= n_pages; i++) {
348  if (uniform) {
349  uniform_height = swap ? u_width : u_height;
350  cache->height_to_page[i] = i * uniform_height;
351  } else {
352  if (i < n_pages) {
353  gdouble w, h;
354 
355  ev_document_get_page_size (document, i, &w, &h);
356  page_height = swap ? w : h;
357  } else {
358  page_height = 0;
359  }
360  cache->height_to_page[i] = saved_height;
361  saved_height += page_height;
362  }
363  }
364 
365  if (cache->dual_even_left && !uniform) {
366  gdouble w, h;
367 
368  ev_document_get_page_size (document, 0, &w, &h);
369  saved_height = swap ? w : h;
370  } else {
371  saved_height = 0;
372  }
373 
374  for (i = cache->dual_even_left; i < n_pages + 2; i += 2) {
375  if (uniform) {
376  uniform_height = swap ? u_width : u_height;
377  cache->dual_height_to_page[i] = ((i + cache->dual_even_left) / 2) * uniform_height;
378  if (i + 1 < n_pages + 2)
379  cache->dual_height_to_page[i + 1] = ((i + cache->dual_even_left) / 2) * uniform_height;
380  } else {
381  if (i + 1 < n_pages) {
382  gdouble w, h;
383 
384  ev_document_get_page_size (document, i + 1, &w, &h);
385  next_page_height = swap ? w : h;
386  } else {
387  next_page_height = 0;
388  }
389 
390  if (i < n_pages) {
391  gdouble w, h;
392 
393  ev_document_get_page_size (document, i, &w, &h);
394  page_height = swap ? w : h;
395  } else {
396  page_height = 0;
397  }
398 
399  if (i + 1 < n_pages + 2) {
400  cache->dual_height_to_page[i] = saved_height;
401  cache->dual_height_to_page[i + 1] = saved_height;
402  saved_height += MAX(page_height, next_page_height);
403  } else {
404  cache->dual_height_to_page[i] = saved_height;
405  }
406  }
407  }
408 }
409 
410 static void
412 {
413  if (cache->height_to_page) {
414  g_free (cache->height_to_page);
415  cache->height_to_page = NULL;
416  }
417 
418  if (cache->dual_height_to_page) {
419  g_free (cache->dual_height_to_page);
420  cache->dual_height_to_page = NULL;
421  }
422  g_free (cache);
423 }
424 
425 static EvHeightToPageCache *
427 {
428  EvHeightToPageCache *cache;
429 
430  if (!view->document)
431  return NULL;
432 
433  cache = g_object_get_data (G_OBJECT (view->document), EV_HEIGHT_TO_PAGE_CACHE_KEY);
434  if (!cache) {
435  cache = g_new0 (EvHeightToPageCache, 1);
436  ev_view_build_height_to_page_cache (view, cache);
437  g_object_set_data_full (G_OBJECT (view->document),
439  cache,
440  (GDestroyNotify)ev_height_to_page_cache_free);
441  }
442 
443  return cache;
444 }
445 
446 static void
448  gint page,
449  gint *height,
450  gint *dual_height)
451 {
452  EvHeightToPageCache *cache = NULL;
453  gdouble h, dh;
454 
455  if (!view->height_to_page_cache)
456  return;
457 
458  cache = view->height_to_page_cache;
459  if (cache->rotation != view->rotation ||
460  cache->dual_even_left != view->dual_even_left) {
461  ev_view_build_height_to_page_cache (view, cache);
462  }
463 
464  if (height) {
465  h = cache->height_to_page[page];
466  *height = (gint)(h * view->scale + 0.5);
467  }
468 
469  if (dual_height) {
470  dh = cache->dual_height_to_page[page];
471  *dual_height = (gint)(dh * view->scale + 0.5);
472  }
473 }
474 
475 static gint
477  GtkOrientation orientation)
478 {
479  GtkWidget *widget = GTK_WIDGET (view);
480  GtkWidget *sb;
481  GtkWidget *swindow = gtk_widget_get_parent (GTK_WIDGET (view));
482  GtkAllocation allocation;
483  GtkRequisition req;
484  gint spacing;
485 
486  if (!GTK_IS_SCROLLED_WINDOW (swindow))
487  return 0;
488 
489  gtk_widget_get_allocation (widget, &allocation);
490 
491  if (orientation == GTK_ORIENTATION_VERTICAL) {
492  if (allocation.height >= view->requisition.height)
493  sb = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (swindow));
494  else
495  return 0;
496  } else {
497  if (allocation.width >= view->requisition.width)
498  sb = gtk_scrolled_window_get_hscrollbar (GTK_SCROLLED_WINDOW (swindow));
499  else
500  return 0;
501  }
502 
503  gtk_widget_style_get (swindow, "scrollbar_spacing", &spacing, NULL);
504  gtk_widget_get_preferred_size (sb, &req, NULL);
505 
506  return (orientation == GTK_ORIENTATION_VERTICAL ? req.width : req.height) + spacing;
507 }
508 
509 static gboolean
511  gboolean *odd_left_out)
512 {
513  gboolean dual = FALSE;
514  gboolean odd_left = FALSE;
515 
516  switch (view->page_layout) {
518  GdkScreen *screen;
519  double scale;
520  double doc_width;
521  double doc_height;
522  GtkAllocation allocation;
523 
524  screen = gtk_widget_get_screen (GTK_WIDGET (view));
525  scale = ev_document_misc_get_screen_dpi (screen) / 72.0;
526 
527  ev_document_get_max_page_size (view->document, &doc_width, &doc_height);
528  gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
529 
530  /* If the width is ok and the height is pretty close, try to fit it in */
531  if (ev_document_get_n_pages (view->document) > 1 &&
532  doc_width < doc_height &&
533  allocation.width > (2 * doc_width * scale) &&
534  allocation.height > (doc_height * scale * 0.9)) {
535  odd_left = !view->dual_even_left;
536  dual = TRUE;
537  }
538  }
539  break;
540  case EV_PAGE_LAYOUT_DUAL:
541  odd_left = !view->dual_even_left;
542  dual = TRUE;
543  break;
545  break;
546  default:
547  g_assert_not_reached ();
548  }
549 
550  if (odd_left_out)
551  *odd_left_out = odd_left;
552 
553  return dual;
554 }
555 
556 static void
558  gdouble x,
559  gdouble y,
560  GtkOrientation orientation)
561 {
562  gdouble page_size;
563  gdouble upper, lower;
564 
565  if (orientation == GTK_ORIENTATION_VERTICAL) {
566  page_size = gtk_adjustment_get_page_size (view->vadjustment);
567  upper = gtk_adjustment_get_upper (view->vadjustment);
568  lower = gtk_adjustment_get_lower (view->vadjustment);
569 
570  if (view->continuous) {
571  gtk_adjustment_clamp_page (view->vadjustment,
572  y, y + page_size);
573  } else {
574  gtk_adjustment_set_value (view->vadjustment,
575  CLAMP (y, lower, upper - page_size));
576  }
577  } else {
578  page_size = gtk_adjustment_get_page_size (view->hadjustment);
579  upper = gtk_adjustment_get_upper (view->hadjustment);
580  lower = gtk_adjustment_get_lower (view->hadjustment);
581 
582  if (is_dual_page (view, NULL)) {
583  gtk_adjustment_clamp_page (view->hadjustment, x,
584  x + page_size);
585  } else {
586  gtk_adjustment_set_value (view->hadjustment,
587  CLAMP (x, lower, upper - page_size));
588  }
589  }
590 }
591 
592 static void
593 ev_view_scroll_to_page_position (EvView *view, GtkOrientation orientation)
594 {
595  gdouble x, y;
596 
597  if (!view->document)
598  return;
599 
600  if ((orientation == GTK_ORIENTATION_VERTICAL && view->pending_point.y == 0) ||
601  (orientation == GTK_ORIENTATION_HORIZONTAL && view->pending_point.x == 0)) {
602  GdkRectangle page_area;
603  GtkBorder border;
604 
605  ev_view_get_page_extents (view, view->current_page, &page_area, &border);
606  x = page_area.x;
607  y = page_area.y;
608  } else {
609  GdkPoint view_point;
610 
612  &view->pending_point, &view_point);
613  x = view_point.x;
614  y = view_point.y;
615  }
616 
617  scroll_to_point (view, x, y, orientation);
618 }
619 
620 static void
622  GtkOrientation orientation)
623 {
624  GtkWidget *widget = GTK_WIDGET (view);
625  GtkAdjustment *adjustment;
626  GtkAllocation allocation;
627  int req_size;
628  int alloc_size;
629  gdouble page_size;
630  gdouble value;
631  gdouble upper;
632  double factor;
633  gint new_value;
634  gdouble zoom_center;
635 
636  gtk_widget_get_allocation (widget, &allocation);
637 
638  if (orientation == GTK_ORIENTATION_HORIZONTAL) {
639  req_size = view->requisition.width;
640  alloc_size = allocation.width;
641  adjustment = view->hadjustment;
642  zoom_center = view->zoom_center_x;
643  } else {
644  req_size = view->requisition.height;
645  alloc_size = allocation.height;
646  adjustment = view->vadjustment;
647  zoom_center = view->zoom_center_y;
648  }
649 
650  if (!adjustment)
651  return;
652 
653  factor = 1.0;
654  value = gtk_adjustment_get_value (adjustment);
655  upper = gtk_adjustment_get_upper (adjustment);
656  page_size = gtk_adjustment_get_page_size (adjustment);
657  if (zoom_center < 0)
658  zoom_center = page_size * 0.5;
659 
660  if (upper != .0) {
661  switch (view->pending_scroll) {
664  factor = value / upper;
665  break;
667  break;
668  case SCROLL_TO_CENTER:
669  factor = (value + zoom_center) / upper;
670  break;
671  }
672  }
673 
674  upper = MAX (alloc_size, req_size);
675  page_size = alloc_size;
676 
677  gtk_adjustment_set_page_size (adjustment, page_size);
678  gtk_adjustment_set_step_increment (adjustment, alloc_size * 0.1);
679  gtk_adjustment_set_page_increment (adjustment, alloc_size * 0.9);
680  gtk_adjustment_set_lower (adjustment, 0);
681  gtk_adjustment_set_upper (adjustment, upper);
682 
683  /*
684  * We add 0.5 to the values before to average out our rounding errors.
685  */
686  switch (view->pending_scroll) {
689  new_value = CLAMP (upper * factor + 0.5, 0, upper - page_size);
690  gtk_adjustment_set_value (adjustment, (int)new_value);
691  break;
693  ev_view_scroll_to_page_position (view, orientation);
694  break;
695  case SCROLL_TO_CENTER:
696  new_value = CLAMP (upper * factor - zoom_center + 0.5, 0, upper - page_size);
697  if (orientation == GTK_ORIENTATION_HORIZONTAL)
698  view->zoom_center_x = -1.0;
699  else
700  view->zoom_center_y = -1.0;
701  gtk_adjustment_set_value (adjustment, (int)new_value);
702  break;
703  }
704 
705  gtk_adjustment_changed (adjustment);
706 }
707 
708 static void
710 {
711  gint start = view->start_page;
712  gint end = view->end_page;
713  gboolean odd_left;
714 
715  if (ev_document_get_n_pages (view->document) <= 0 ||
717  return;
718 
719  if (view->continuous) {
720  GdkRectangle current_area, unused, page_area;
721  GtkBorder border;
722  gboolean found = FALSE;
723  gint area_max = -1, area;
724  gint best_current_page = -1;
725  int i, j = 0;
726 
727  if (!(view->vadjustment && view->hadjustment))
728  return;
729 
730  current_area.x = gtk_adjustment_get_value (view->hadjustment);
731  current_area.width = gtk_adjustment_get_page_size (view->hadjustment);
732  current_area.y = gtk_adjustment_get_value (view->vadjustment);
733  current_area.height = gtk_adjustment_get_page_size (view->vadjustment);
734 
735  for (i = 0; i < ev_document_get_n_pages (view->document); i++) {
736 
737  ev_view_get_page_extents (view, i, &page_area, &border);
738 
739  if (gdk_rectangle_intersect (&current_area, &page_area, &unused)) {
740  area = unused.width * unused.height;
741 
742  if (!found) {
743  area_max = area;
744  view->start_page = i;
745  found = TRUE;
746  best_current_page = i;
747  }
748  if (area > area_max) {
749  best_current_page = (area == area_max) ? MIN (i, best_current_page) : i;
750  area_max = area;
751  }
752 
753  view->end_page = i;
754  j = 0;
755  } else if (found && view->current_page <= view->end_page) {
756  if (is_dual_page (view, NULL) && j < 1) {
757  /* In dual mode we stop searching
758  * after two consecutive non-visible pages.
759  */
760  j++;
761  continue;
762  }
763  break;
764  }
765  }
766 
769  best_current_page = MAX (best_current_page, view->start_page);
770 
771  if (best_current_page >= 0 && view->current_page != best_current_page) {
772  view->current_page = best_current_page;
773  ev_view_set_loading (view, FALSE);
774  ev_document_model_set_page (view->model, best_current_page);
775  }
776  }
777  } else if (is_dual_page (view, &odd_left)) {
778  if (view->current_page % 2 == !odd_left) {
779  view->start_page = view->current_page;
780  if (view->current_page + 1 < ev_document_get_n_pages (view->document))
781  view->end_page = view->start_page + 1;
782  else
783  view->end_page = view->start_page;
784  } else {
785  if (view->current_page < 1)
786  view->start_page = view->current_page;
787  else
788  view->start_page = view->current_page - 1;
789  view->end_page = view->current_page;
790  }
791  } else {
792  view->start_page = view->current_page;
793  view->end_page = view->current_page;
794  }
795 
796  if (view->start_page == -1 || view->end_page == -1)
797  return;
798 
799  if (start != view->start_page || end != view->end_page) {
800  gint i;
801 
802  for (i = start; i < view->start_page && start != -1; i++) {
803  hide_annotation_windows (view, i);
804  }
805 
806  for (i = end; i > view->end_page && end != -1; i--) {
807  hide_annotation_windows (view, i);
808  }
809 
811  }
812 
814  view->start_page,
815  view->end_page);
817  view->start_page,
818  view->end_page,
819  view->selection_info.selections);
820  if (view->accessible)
822  view->start_page,
823  view->end_page);
824 
826  gtk_widget_queue_draw (GTK_WIDGET (view));
827 }
828 
829 static void
831  GtkOrientation orientation,
832  GtkAdjustment *adjustment)
833 {
834  GtkAdjustment **to_set;
835  const gchar *prop_name;
836 
837  if (orientation == GTK_ORIENTATION_HORIZONTAL) {
838  to_set = &view->hadjustment;
839  prop_name = "hadjustment";
840  } else {
841  to_set = &view->vadjustment;
842  prop_name = "vadjustment";
843  }
844 
845  if (adjustment && adjustment == *to_set)
846  return;
847 
848  if (*to_set) {
849  g_signal_handlers_disconnect_by_func (*to_set,
850  (gpointer) on_adjustment_value_changed,
851  view);
852  g_object_unref (*to_set);
853  }
854 
855  if (!adjustment)
856  adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
857  g_signal_connect (adjustment, "value_changed",
858  G_CALLBACK (on_adjustment_value_changed),
859  view);
860  *to_set = g_object_ref_sink (adjustment);
861  ev_view_set_adjustment_values (view, orientation);
862 
863  g_object_notify (G_OBJECT (view), prop_name);
864 }
865 
866 static void
867 add_scroll_binding_keypad (GtkBindingSet *binding_set,
868  guint keyval,
869  GdkModifierType modifiers,
870  GtkScrollType scroll,
871  GtkOrientation orientation)
872 {
873  guint keypad_keyval = keyval - GDK_KEY_Left + GDK_KEY_KP_Left;
874 
875  gtk_binding_entry_add_signal (binding_set, keyval, modifiers,
876  "scroll", 2,
877  GTK_TYPE_SCROLL_TYPE, scroll,
878  GTK_TYPE_ORIENTATION, orientation);
879  gtk_binding_entry_add_signal (binding_set, keypad_keyval, modifiers,
880  "scroll", 2,
881  GTK_TYPE_SCROLL_TYPE, scroll,
882  GTK_TYPE_ORIENTATION, orientation);
883 }
884 
885 static gdouble
887  GtkScrollType scroll)
888 {
889  GtkWidget *widget = GTK_WIDGET (view);
890  GtkAdjustment *adjustment = view->vadjustment;
891  cairo_region_t *text_region, *region;
892  GtkAllocation allocation;
893  gint page;
894  GdkRectangle rect;
895  EvRectangle doc_rect;
896  GdkRectangle page_area;
897  GtkBorder border;
898  gdouble fraction = 1.0;
899 
900  if (scroll != GTK_SCROLL_PAGE_BACKWARD && scroll != GTK_SCROLL_PAGE_FORWARD)
901  return gtk_adjustment_get_page_size (adjustment);
902 
903  page = scroll == GTK_SCROLL_PAGE_BACKWARD ? view->start_page : view->end_page;
904 
905  text_region = ev_page_cache_get_text_mapping (view->page_cache, page);
906  if (!text_region || cairo_region_is_empty (text_region))
907  return gtk_adjustment_get_page_size (adjustment);
908 
909  gtk_widget_get_allocation (widget, &allocation);
910  ev_view_get_page_extents (view, page, &page_area, &border);
911  rect.x = page_area.x + view->scroll_x;
912  rect.y = view->scroll_y + (scroll == GTK_SCROLL_PAGE_BACKWARD ? 5 : allocation.height - 5);
913  rect.width = page_area.width;
914  rect.height = 1;
915  _ev_view_transform_view_rect_to_doc_rect (view, &rect, &page_area, &border, &doc_rect);
916 
917  /* Convert the doc rectangle into a GdkRectangle */
918  rect.x = doc_rect.x1;
919  rect.y = doc_rect.y1;
920  rect.width = doc_rect.x2 - doc_rect.x1;
921  rect.height = MAX (1, doc_rect.y2 - doc_rect.y1);
922  region = cairo_region_create_rectangle (&rect);
923 
924  cairo_region_intersect (region, text_region);
925  if (cairo_region_num_rectangles (region)) {
926  EvRenderContext *rc;
927  EvPage *ev_page;
928  cairo_region_t *sel_region;
929 
930  cairo_region_get_rectangle (region, 0, &rect);
931  ev_page = ev_document_get_page (view->document, page);
932  rc = ev_render_context_new (ev_page, view->rotation, 0.);
934  page_area.width - (border.left + border.right),
935  page_area.height - (border.left + border.right));
936  g_object_unref (ev_page);
937  /* Get the selection region to know the height of the line */
938  doc_rect.x1 = doc_rect.x2 = rect.x + 0.5;
939  doc_rect.y1 = doc_rect.y2 = rect.y + 0.5;
940 
944  &doc_rect);
946 
947  g_object_unref (rc);
948 
949  if (cairo_region_num_rectangles (sel_region) > 0) {
950  cairo_region_get_rectangle (sel_region, 0, &rect);
951  fraction = 1 - (rect.height / gtk_adjustment_get_page_size (adjustment));
952  }
953  cairo_region_destroy (sel_region);
954  }
955  cairo_region_destroy (region);
956 
957  return gtk_adjustment_get_page_size (adjustment) * fraction;
958 
959 }
960 
961 static void
963 {
965 }
966 
967 static void
969 {
970  gint n_pages;
971 
972  if (!view->document)
973  return;
974 
975  n_pages = ev_document_get_n_pages (view->document);
976  if (n_pages <= 1)
977  return;
978 
979  ev_document_model_set_page (view->model, n_pages - 1);
980 }
981 
990 void
992  GtkScrollType scroll,
993  gboolean horizontal)
994 {
995  GtkAdjustment *adjustment;
996  double value, increment;
997  gdouble upper, lower;
998  gdouble page_size;
999  gdouble step_increment;
1000  gboolean first_page = FALSE;
1001  gboolean last_page = FALSE;
1002 
1003  if (view->key_binding_handled)
1004  return;
1005 
1006  view->jump_to_find_result = FALSE;
1007 
1008  if ((!horizontal && ev_view_page_fits (view, GTK_ORIENTATION_VERTICAL)) ||
1009  (horizontal && ev_view_page_fits (view, GTK_ORIENTATION_HORIZONTAL))) {
1010  switch (scroll) {
1011  case GTK_SCROLL_PAGE_BACKWARD:
1012  case GTK_SCROLL_STEP_BACKWARD:
1013  ev_view_previous_page (view);
1014  break;
1015  case GTK_SCROLL_PAGE_FORWARD:
1016  case GTK_SCROLL_STEP_FORWARD:
1017  ev_view_next_page (view);
1018  break;
1019  case GTK_SCROLL_START:
1020  ev_view_first_page (view);
1021  break;
1022  case GTK_SCROLL_END:
1023  ev_view_last_page (view);
1024  break;
1025  default:
1026  break;
1027  }
1028  return;
1029  }
1030 
1031  /* Assign values for increment and vertical adjustment */
1032  adjustment = horizontal ? view->hadjustment : view->vadjustment;
1033  value = gtk_adjustment_get_value (adjustment);
1034  upper = gtk_adjustment_get_upper (adjustment);
1035  lower = gtk_adjustment_get_lower (adjustment);
1036  page_size = gtk_adjustment_get_page_size (adjustment);
1037  step_increment = gtk_adjustment_get_step_increment (adjustment);
1038 
1039  /* Assign boolean for first and last page */
1040  if (view->current_page == 0)
1041  first_page = TRUE;
1042  if (view->current_page == ev_document_get_n_pages (view->document) - 1)
1043  last_page = TRUE;
1044 
1045  switch (scroll) {
1046  case GTK_SCROLL_PAGE_BACKWARD:
1047  /* Do not jump backwards if at the first page */
1048  if (value == lower && first_page) {
1049  /* Do nothing */
1050  /* At the top of a page, assign the upper bound limit of previous page */
1051  } else if (value == lower) {
1052  value = upper - page_size;
1053  ev_view_previous_page (view);
1054  /* Jump to the top */
1055  } else {
1056  increment = compute_scroll_increment (view, GTK_SCROLL_PAGE_BACKWARD);
1057  value = MAX (value - increment, lower);
1058  }
1059  break;
1060  case GTK_SCROLL_PAGE_FORWARD:
1061  /* Do not jump forward if at the last page */
1062  if (value == (upper - page_size) && last_page) {
1063  /* Do nothing */
1064  /* At the bottom of a page, assign the lower bound limit of next page */
1065  } else if (value == (upper - page_size)) {
1066  value = 0;
1067  ev_view_next_page (view);
1068  /* Jump to the bottom */
1069  } else {
1070  increment = compute_scroll_increment (view, GTK_SCROLL_PAGE_FORWARD);
1071  value = MIN (value + increment, upper - page_size);
1072  }
1073  break;
1074  case GTK_SCROLL_STEP_BACKWARD:
1075  value -= step_increment;
1076  break;
1077  case GTK_SCROLL_STEP_FORWARD:
1078  value += step_increment;
1079  break;
1080  case GTK_SCROLL_STEP_DOWN:
1081  value -= step_increment / 10;
1082  break;
1083  case GTK_SCROLL_STEP_UP:
1084  value += step_increment / 10;
1085  break;
1086  case GTK_SCROLL_START:
1087  value = lower;
1088  if (!first_page)
1089  ev_view_first_page (view);
1090  break;
1091  case GTK_SCROLL_END:
1092  value = upper - page_size;
1093  if (!last_page)
1094  ev_view_last_page (view);
1095  /* Changing pages causes the top to be shown. Here we want the bottom shown. */
1096  view->pending_point.y = value;
1097  break;
1098  default:
1099  break;
1100  }
1101 
1102  value = CLAMP (value, lower, upper - page_size);
1103 
1104  gtk_adjustment_set_value (adjustment, value);
1105 }
1106 
1107 static void
1109  GtkScrollType scroll,
1110  GtkOrientation orientation)
1111 {
1112  ev_view_scroll (view, scroll, orientation == GTK_ORIENTATION_HORIZONTAL);
1113 }
1114 
1115 #define MARGIN 5
1116 
1117 static void
1118 ensure_rectangle_is_visible (EvView *view, GdkRectangle *rect)
1119 {
1120  GtkWidget *widget = GTK_WIDGET (view);
1121  GtkAdjustment *adjustment;
1122  GtkAllocation allocation;
1123  gdouble adj_value;
1124  int value;
1125 
1127 
1128  gtk_widget_get_allocation (widget, &allocation);
1129 
1130  adjustment = view->vadjustment;
1131  adj_value = gtk_adjustment_get_value (adjustment);
1132 
1133  if (rect->y < adj_value) {
1134  value = MAX (gtk_adjustment_get_lower (adjustment), rect->y - MARGIN);
1135  gtk_adjustment_set_value (view->vadjustment, value);
1136  } else if (rect->y + rect->height > adj_value + allocation.height) {
1137  value = MIN (gtk_adjustment_get_upper (adjustment), rect->y + rect->height -
1138  allocation.height + MARGIN);
1139  gtk_adjustment_set_value (view->vadjustment, value);
1140  }
1141 
1142  adjustment = view->hadjustment;
1143  adj_value = gtk_adjustment_get_value (adjustment);
1144 
1145  if (rect->x < adj_value) {
1146  value = MAX (gtk_adjustment_get_lower (adjustment), rect->x - MARGIN);
1147  gtk_adjustment_set_value (view->hadjustment, value);
1148  } else if (rect->x + rect->height > adj_value + allocation.width) {
1149  value = MIN (gtk_adjustment_get_upper (adjustment), rect->x + rect->width -
1150  allocation.width + MARGIN);
1151  gtk_adjustment_set_value (view->hadjustment, value);
1152  }
1153 }
1154 
1155 /*** Geometry computations ***/
1156 
1157 static void
1158 compute_border (EvView *view, GtkBorder *border)
1159 {
1160  GtkWidget *widget = GTK_WIDGET (view);
1161  GtkStyleContext *context = gtk_widget_get_style_context (widget);
1162  GtkStateFlags state = gtk_widget_get_state_flags (widget);
1163 
1164  gtk_style_context_save (context);
1165  gtk_style_context_add_class (context, EV_STYLE_CLASS_DOCUMENT_PAGE);
1166  gtk_style_context_get_border (context, state, border);
1167  gtk_style_context_restore (context);
1168 }
1169 
1170 void
1172  gint page,
1173  gdouble scale,
1174  gint rotation,
1175  gint *page_width,
1176  gint *page_height)
1177 {
1178  gdouble w, h;
1179  gint width, height;
1180 
1181  ev_document_get_page_size (document, page, &w, &h);
1182 
1183  width = (gint)(w * scale + 0.5);
1184  height = (gint)(h * scale + 0.5);
1185 
1186  if (page_width)
1187  *page_width = (rotation == 0 || rotation == 180) ? width : height;
1188  if (page_height)
1189  *page_height = (rotation == 0 || rotation == 180) ? height : width;
1190 }
1191 
1192 static void
1194  gint page,
1195  gint *page_width,
1196  gint *page_height)
1197 {
1199  page,
1200  view->scale,
1201  view->rotation,
1202  page_width,
1203  page_height);
1204 }
1205 
1206 static void
1208  gint *max_width,
1209  gint *max_height)
1210 {
1211  double w, h;
1212  gint width, height;
1213 
1214  ev_document_get_max_page_size (view->document, &w, &h);
1215 
1216  width = (gint)(w * view->scale + 0.5);
1217  height = (gint)(h * view->scale + 0.5);
1218 
1219  if (max_width)
1220  *max_width = (view->rotation == 0 || view->rotation == 180) ? width : height;
1221  if (max_height)
1222  *max_height = (view->rotation == 0 || view->rotation == 180) ? height : width;
1223 }
1224 
1225 static void
1226 get_page_y_offset (EvView *view, int page, int *y_offset)
1227 {
1228  int offset = 0;
1229  GtkBorder border;
1230  gboolean odd_left;
1231 
1232  g_return_if_fail (y_offset != NULL);
1233 
1234  compute_border (view, &border);
1235 
1236  if (is_dual_page (view, &odd_left)) {
1237  ev_view_get_height_to_page (view, page, NULL, &offset);
1238  offset += ((page + !odd_left) / 2 + 1) * view->spacing +
1239  ((page + !odd_left) / 2 ) * (border.top + border.bottom);
1240  } else {
1241  ev_view_get_height_to_page (view, page, &offset, NULL);
1242  offset += (page + 1) * view->spacing + page * (border.top + border.bottom);
1243  }
1244 
1245  *y_offset = offset;
1246  return;
1247 }
1248 
1249 gboolean
1251  gint page,
1252  GdkRectangle *page_area,
1253  GtkBorder *border)
1254 {
1255  GtkWidget *widget;
1256  int width, height;
1257  GtkAllocation allocation;
1258 
1259  widget = GTK_WIDGET (view);
1260  gtk_widget_get_allocation (widget, &allocation);
1261 
1262  /* Get the size of the page */
1263  ev_view_get_page_size (view, page, &width, &height);
1264  compute_border (view, border);
1265  page_area->width = width + border->left + border->right;
1266  page_area->height = height + border->top + border->bottom;
1267 
1268  if (view->continuous) {
1269  gint max_width;
1270  gint x, y;
1271  gboolean odd_left;
1272 
1273  ev_view_get_max_page_size (view, &max_width, NULL);
1274  max_width = max_width + border->left + border->right;
1275  /* Get the location of the bounding box */
1276  if (is_dual_page (view, &odd_left)) {
1277  x = view->spacing + ((page % 2 == !odd_left) ? 0 : 1) * (max_width + view->spacing);
1278  x = x + MAX (0, allocation.width - (max_width * 2 + view->spacing * 3)) / 2;
1279  if (page % 2 == !odd_left)
1280  x = x + (max_width - width - border->left - border->right);
1281  } else {
1282  x = view->spacing;
1283  x = x + MAX (0, allocation.width - (width + border->left + border->right + view->spacing * 2)) / 2;
1284  }
1285 
1286  get_page_y_offset (view, page, &y);
1287 
1288  page_area->x = x;
1289  page_area->y = y;
1290  } else {
1291  gint x, y;
1292  gboolean odd_left;
1293 
1294  if (is_dual_page (view, &odd_left)) {
1295  gint width_2, height_2;
1296  gint max_width = width;
1297  gint max_height = height;
1298  GtkBorder overall_border;
1299  gint other_page;
1300 
1301  other_page = (page % 2 == !odd_left) ? page + 1: page - 1;
1302 
1303  /* First, we get the bounding box of the two pages */
1304  if (other_page < ev_document_get_n_pages (view->document)
1305  && (0 <= other_page)) {
1306  ev_view_get_page_size (view, other_page,
1307  &width_2, &height_2);
1308  if (width_2 > width)
1309  max_width = width_2;
1310  if (height_2 > height)
1311  max_height = height_2;
1312  }
1313  compute_border (view, &overall_border);
1314 
1315  /* Find the offsets */
1316  x = view->spacing;
1317  y = view->spacing;
1318 
1319  /* Adjust for being the left or right page */
1320  if (page % 2 == !odd_left)
1321  x = x + max_width - width;
1322  else
1323  x = x + (max_width + overall_border.left + overall_border.right) + view->spacing;
1324 
1325  y = y + (max_height - height)/2;
1326 
1327  /* Adjust for extra allocation */
1328  x = x + MAX (0, allocation.width -
1329  ((max_width + overall_border.left + overall_border.right) * 2 + view->spacing * 3))/2;
1330  y = y + MAX (0, allocation.height - (height + view->spacing * 2))/2;
1331  } else {
1332  x = view->spacing;
1333  y = view->spacing;
1334 
1335  /* Adjust for extra allocation */
1336  x = x + MAX (0, allocation.width - (width + border->left + border->right + view->spacing * 2))/2;
1337  y = y + MAX (0, allocation.height - (height + border->top + border->bottom + view->spacing * 2))/2;
1338  }
1339 
1340  page_area->x = x;
1341  page_area->y = y;
1342  }
1343 
1344  return TRUE;
1345 }
1346 
1347 static void
1349  gint page,
1350  gdouble *width,
1351  gdouble *height)
1352 {
1353  double w, h;
1354 
1355  ev_document_get_page_size (view->document, page, &w, &h);
1356  if (view->rotation == 0 || view->rotation == 180) {
1357  if (width) *width = w;
1358  if (height) *height = h;
1359  } else {
1360  if (width) *width = h;
1361  if (height) *height = w;
1362  }
1363 }
1364 
1365 void
1367  GdkPoint *view_point,
1368  GdkRectangle *page_area,
1369  GtkBorder *border,
1370  double *doc_point_x,
1371  double *doc_point_y)
1372 {
1373  *doc_point_x = MAX ((double) (view_point->x - page_area->x - border->left) / view->scale, 0);
1374  *doc_point_y = MAX ((double) (view_point->y - page_area->y - border->right) / view->scale, 0);
1375 }
1376 
1377 void
1379  GdkRectangle *view_rect,
1380  GdkRectangle *page_area,
1381  GtkBorder *border,
1382  EvRectangle *doc_rect)
1383 {
1384  doc_rect->x1 = MAX ((double) (view_rect->x - page_area->x - border->left) / view->scale, 0);
1385  doc_rect->y1 = MAX ((double) (view_rect->y - page_area->y - border->right) / view->scale, 0);
1386  doc_rect->x2 = doc_rect->x1 + (double) view_rect->width / view->scale;
1387  doc_rect->y2 = doc_rect->y1 + (double) view_rect->height / view->scale;
1388 }
1389 
1390 void
1392  int page,
1393  EvPoint *doc_point,
1394  GdkPoint *view_point)
1395 {
1396  GdkRectangle page_area;
1397  GtkBorder border;
1398  double x, y, view_x, view_y;
1399 
1400  switch (view->rotation) {
1401  case 0:
1402  x = doc_point->x;
1403  y = doc_point->y;
1404 
1405  break;
1406  case 90: {
1407  gdouble width;
1408 
1409  get_doc_page_size (view, page, &width, NULL);
1410  x = width - doc_point->y;
1411  y = doc_point->x;
1412  }
1413  break;
1414  case 180: {
1415  gdouble width, height;
1416 
1417  get_doc_page_size (view, page, &width, &height);
1418  x = width - doc_point->x;
1419  y = height - doc_point->y;
1420  }
1421  break;
1422  case 270: {
1423  gdouble height;
1424 
1425  get_doc_page_size (view, page, NULL, &height);
1426  x = doc_point->y;
1427  y = height - doc_point->x;
1428  }
1429  break;
1430  default:
1431  g_assert_not_reached ();
1432  }
1433 
1434  ev_view_get_page_extents (view, page, &page_area, &border);
1435 
1436  view_x = CLAMP ((gint)(x * view->scale + 0.5), 0, page_area.width);
1437  view_y = CLAMP ((gint)(y * view->scale + 0.5), 0, page_area.height);
1438  view_point->x = view_x + page_area.x + border.left;
1439  view_point->y = view_y + page_area.y + border.top;
1440 }
1441 
1442 void
1444  int page,
1445  EvRectangle *doc_rect,
1446  GdkRectangle *view_rect)
1447 {
1448  GdkRectangle page_area;
1449  GtkBorder border;
1450  double x, y, w, h;
1451 
1452  switch (view->rotation) {
1453  case 0:
1454  x = doc_rect->x1;
1455  y = doc_rect->y1;
1456  w = doc_rect->x2 - doc_rect->x1;
1457  h = doc_rect->y2 - doc_rect->y1;
1458 
1459  break;
1460  case 90: {
1461  gdouble width;
1462 
1463  get_doc_page_size (view, page, &width, NULL);
1464  x = width - doc_rect->y2;
1465  y = doc_rect->x1;
1466  w = doc_rect->y2 - doc_rect->y1;
1467  h = doc_rect->x2 - doc_rect->x1;
1468  }
1469  break;
1470  case 180: {
1471  gdouble width, height;
1472 
1473  get_doc_page_size (view, page, &width, &height);
1474  x = width - doc_rect->x2;
1475  y = height - doc_rect->y2;
1476  w = doc_rect->x2 - doc_rect->x1;
1477  h = doc_rect->y2 - doc_rect->y1;
1478  }
1479  break;
1480  case 270: {
1481  gdouble height;
1482 
1483  get_doc_page_size (view, page, NULL, &height);
1484  x = doc_rect->y1;
1485  y = height - doc_rect->x2;
1486  w = doc_rect->y2 - doc_rect->y1;
1487  h = doc_rect->x2 - doc_rect->x1;
1488  }
1489  break;
1490  default:
1491  g_assert_not_reached ();
1492  }
1493 
1494  ev_view_get_page_extents (view, page, &page_area, &border);
1495 
1496  view_rect->x = (gint)(x * view->scale + 0.5) + page_area.x + border.left;
1497  view_rect->y = (gint)(y * view->scale + 0.5) + page_area.y + border.top;
1498  view_rect->width = (gint)(w * view->scale + 0.5);
1499  view_rect->height = (gint)(h * view->scale + 0.5);
1500 }
1501 
1502 static void
1504  gdouble x,
1505  gdouble y,
1506  gint *page,
1507  gint *x_offset,
1508  gint *y_offset)
1509 {
1510  int i;
1511 
1512  if (view->document == NULL)
1513  return;
1514 
1515  g_assert (page);
1516  g_assert (x_offset);
1517  g_assert (y_offset);
1518 
1519  for (i = view->start_page; i >= 0 && i <= view->end_page; i++) {
1520  GdkRectangle page_area;
1521  GtkBorder border;
1522 
1523  if (! ev_view_get_page_extents (view, i, &page_area, &border))
1524  continue;
1525 
1526  if ((x >= page_area.x + border.left) &&
1527  (x < page_area.x + page_area.width - border.right) &&
1528  (y >= page_area.y + border.top) &&
1529  (y < page_area.y + page_area.height - border.bottom)) {
1530  *page = i;
1531  *x_offset = x - (page_area.x + border.left);
1532  *y_offset = y - (page_area.y + border.top);
1533  return;
1534  }
1535  }
1536 
1537  *page = -1;
1538 }
1539 
1540 static gboolean
1542  gdouble x,
1543  gdouble y)
1544 {
1545  cairo_region_t *region;
1546  gint page = -1;
1547  gint x_offset = 0, y_offset = 0;
1548 
1549  find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
1550 
1551  if (page == -1)
1552  return FALSE;
1553 
1554  region = ev_page_cache_get_text_mapping (view->page_cache, page);
1555 
1556  if (region)
1557  return cairo_region_contains_point (region, x_offset / view->scale, y_offset / view->scale);
1558  else
1559  return FALSE;
1560 }
1561 
1562 static gboolean
1564  gdouble x,
1565  gdouble y)
1566 {
1567  cairo_region_t *region;
1568  gint page = -1;
1569  gint x_offset = 0, y_offset = 0;
1570 
1571  find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
1572 
1573  if (page == -1)
1574  return FALSE;
1575 
1576  region = ev_pixbuf_cache_get_selection_region (view->pixbuf_cache, page, view->scale);
1577 
1578  if (region)
1579  return cairo_region_contains_point (region, x_offset, y_offset);
1580  else
1581  return FALSE;
1582 }
1583 
1584 static gboolean
1586  gint page,
1587  gint x_offset,
1588  gint y_offset,
1589  gint *x_new,
1590  gint *y_new)
1591 {
1592  gdouble width, height;
1593  double x, y;
1594 
1595  get_doc_page_size (view, page, &width, &height);
1596 
1597  x_offset = x_offset / view->scale;
1598  y_offset = y_offset / view->scale;
1599 
1600  if (view->rotation == 0) {
1601  x = x_offset;
1602  y = y_offset;
1603  } else if (view->rotation == 90) {
1604  x = y_offset;
1605  y = width - x_offset;
1606  } else if (view->rotation == 180) {
1607  x = width - x_offset;
1608  y = height - y_offset;
1609  } else if (view->rotation == 270) {
1610  x = height - y_offset;
1611  y = x_offset;
1612  } else {
1613  g_assert_not_reached ();
1614  }
1615 
1616  *x_new = x;
1617  *y_new = y;
1618 
1619  return TRUE;
1620 }
1621 
1622 static gboolean
1624  gdouble x,
1625  gdouble y,
1626  gint *page,
1627  gint *x_new,
1628  gint *y_new)
1629 {
1630  gint x_offset = 0, y_offset = 0;
1631 
1632  x += view->scroll_x;
1633  y += view->scroll_y;
1634  find_page_at_location (view, x, y, page, &x_offset, &y_offset);
1635  if (*page == -1)
1636  return FALSE;
1637 
1638  return get_doc_point_from_offset (view, *page, x_offset, y_offset, x_new, y_new);
1639 }
1640 
1641 static void
1643  guint page,
1644  EvMappingList *mapping_list,
1645  gconstpointer data,
1646  GdkRectangle *area)
1647 {
1648  EvMapping *mapping;
1649 
1650  mapping = ev_mapping_list_find (mapping_list, data);
1651  _ev_view_transform_doc_rect_to_view_rect (view, page, &mapping->area, area);
1652  area->x -= view->scroll_x;
1653  area->y -= view->scroll_y;
1654 }
1655 
1656 static void
1658  GtkWidget *child_widget,
1659  gint x,
1660  gint y,
1661  guint page,
1662  EvRectangle *doc_rect)
1663 {
1664  EvViewChild *child;
1665 
1666  child = g_slice_new (EvViewChild);
1667 
1668  child->widget = child_widget;
1669  child->x = x;
1670  child->y = y;
1671  child->page = page;
1672  child->doc_rect = *doc_rect;
1673 
1674  gtk_widget_set_parent (child_widget, GTK_WIDGET (view));
1675  view->children = g_list_append (view->children, child);
1676 }
1677 
1678 static void
1680  GtkWidget *child_widget,
1681  guint page,
1682  EvRectangle *doc_rect)
1683 {
1684  GdkRectangle area;
1685 
1686  _ev_view_transform_doc_rect_to_view_rect (view, page, doc_rect, &area);
1687  area.x -= view->scroll_x;
1688  area.y -= view->scroll_y;
1689  ev_view_put (view, child_widget, area.x, area.y, page, doc_rect);
1690 }
1691 
1692 /*** Hyperref ***/
1693 static EvMapping *
1695  gdouble x,
1696  gdouble y,
1697  gint *page)
1698 {
1699  gint x_new = 0, y_new = 0;
1700  EvMappingList *link_mapping;
1701 
1702  if (!EV_IS_DOCUMENT_LINKS (view->document))
1703  return NULL;
1704 
1705  if (!get_doc_point_from_location (view, x, y, page, &x_new, &y_new))
1706  return NULL;
1707 
1708  link_mapping = ev_page_cache_get_link_mapping (view->page_cache, *page);
1709  if (link_mapping)
1710  return ev_mapping_list_get (link_mapping, x_new, y_new);
1711 
1712  return NULL;
1713 }
1714 
1715 static EvLink *
1717  gdouble x,
1718  gdouble y)
1719 {
1720  EvMapping *mapping;
1721  gint page;
1722 
1723  mapping = get_link_mapping_at_location (view, x, y, &page);
1724 
1725  return mapping ? mapping->data : NULL;
1726 }
1727 
1728 static void
1730 {
1731  EvPoint doc_point;
1732  gdouble left, top;
1733  gboolean change_left, change_top;
1734 
1735  left = ev_link_dest_get_left (dest, &change_left);
1736  top = ev_link_dest_get_top (dest, &change_top);
1737 
1738  if (view->allow_links_change_zoom) {
1739  gdouble doc_width, doc_height;
1740  gdouble zoom;
1741  GtkAllocation allocation;
1742 
1743  gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
1744 
1745  doc_width = ev_link_dest_get_right (dest) - left;
1746  doc_height = ev_link_dest_get_bottom (dest) - top;
1747 
1748  zoom = zoom_for_size_fit_page (doc_width,
1749  doc_height,
1750  allocation.width,
1751  allocation.height);
1752 
1754  ev_document_model_set_scale (view->model, zoom);
1755 
1756  /* center the target box within the view */
1757  left -= (allocation.width / zoom - doc_width) / 2;
1758  top -= (allocation.height / zoom - doc_height) / 2;
1759  }
1760 
1761  doc_point.x = change_left ? left : 0;
1762  doc_point.y = change_top ? top : 0;
1763  view->pending_point = doc_point;
1764 
1766 }
1767 
1768 static void
1770 {
1771  EvPoint doc_point;
1772  gint page;
1773  double left;
1774  gboolean change_left;
1775 
1776  page = ev_link_dest_get_page (dest);
1777 
1778  left = ev_link_dest_get_left (dest, &change_left);
1779  doc_point.x = change_left ? left : 0;
1780  doc_point.y = 0;
1781 
1782  if (view->allow_links_change_zoom) {
1783  GtkAllocation allocation;
1784  gdouble doc_width, doc_height;
1785  double zoom;
1786 
1787  gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
1788 
1789  ev_document_get_page_size (view->document, page, &doc_width, &doc_height);
1790 
1791  zoom = zoom_for_size_fit_height (doc_width - doc_point.x, doc_height,
1792  allocation.width,
1793  allocation.height);
1794 
1796  ev_document_model_set_scale (view->model, zoom);
1797  }
1798 
1799  view->pending_point = doc_point;
1800 
1801  ev_view_change_page (view, page);
1802 }
1803 
1804 static void
1806 {
1807  EvPoint doc_point;
1808  gint page;
1809  gdouble top;
1810  gboolean change_top;
1811 
1812  page = ev_link_dest_get_page (dest);
1813 
1814  top = ev_link_dest_get_top (dest, &change_top);
1815  doc_point.x = 0;
1816  doc_point.y = change_top ? top : 0;
1817 
1818  if (view->allow_links_change_zoom) {
1819  GtkAllocation allocation;
1820  gdouble doc_width;
1821  gdouble zoom;
1822 
1823  gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
1824 
1825  ev_document_get_page_size (view->document, page, &doc_width, NULL);
1826 
1827  zoom = zoom_for_size_fit_width (doc_width, top,
1828  allocation.width,
1829  allocation.height);
1830 
1832  ev_document_model_set_scale (view->model, zoom);
1833  }
1834 
1835  view->pending_point = doc_point;
1836 
1837  ev_view_change_page (view, page);
1838 }
1839 
1840 static void
1842 {
1843  int page;
1844 
1845  page = ev_link_dest_get_page (dest);
1846 
1847  if (view->allow_links_change_zoom) {
1848  double zoom;
1849  gdouble doc_width, doc_height;
1850  GtkAllocation allocation;
1851 
1852  gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
1853 
1854  ev_document_get_page_size (view->document, page, &doc_width, &doc_height);
1855 
1856  zoom = zoom_for_size_fit_page (doc_width, doc_height,
1857  allocation.width,
1858  allocation.height);
1859 
1861  ev_document_model_set_scale (view->model, zoom);
1862  }
1863 
1864  ev_view_change_page (view, page);
1865 }
1866 
1867 static void
1869 {
1870  EvPoint doc_point;
1871  gint page;
1872  gdouble zoom, left, top;
1873  gboolean change_zoom, change_left, change_top;
1874 
1875  zoom = ev_link_dest_get_zoom (dest, &change_zoom);
1876  page = ev_link_dest_get_page (dest);
1877 
1878  if (view->allow_links_change_zoom && change_zoom && zoom > 1) {
1880  ev_document_model_set_scale (view->model, zoom);
1881  }
1882 
1883  left = ev_link_dest_get_left (dest, &change_left);
1884  top = ev_link_dest_get_top (dest, &change_top);
1885 
1886  doc_point.x = change_left ? left : 0;
1887  doc_point.y = change_top ? top : 0;
1888  view->pending_point = doc_point;
1889 
1890  ev_view_change_page (view, page);
1891 }
1892 
1893 static void
1895 {
1896  EvLinkDestType type;
1897  int page, n_pages, current_page;
1898 
1899  page = ev_link_dest_get_page (dest);
1900  n_pages = ev_document_get_n_pages (view->document);
1901 
1902  if (page < 0 || page >= n_pages)
1903  return;
1904 
1905  current_page = view->current_page;
1906 
1907  type = ev_link_dest_get_dest_type (dest);
1908 
1909  switch (type) {
1911  ev_document_model_set_page (view->model, page);
1912  break;
1913  case EV_LINK_DEST_TYPE_FIT:
1914  goto_fit_dest (view, dest);
1915  break;
1917  goto_fith_dest (view, dest);
1918  break;
1920  goto_fitv_dest (view, dest);
1921  break;
1923  goto_fitr_dest (view, dest);
1924  break;
1925  case EV_LINK_DEST_TYPE_XYZ:
1926  goto_xyz_dest (view, dest);
1927  break;
1930  break;
1931  default:
1932  g_assert_not_reached ();
1933  }
1934 
1935  if (current_page != view->current_page)
1937 }
1938 
1939 static void
1941 {
1942  EvLinkDestType type;
1943 
1944  type = ev_link_dest_get_dest_type (dest);
1945 
1946  if (type == EV_LINK_DEST_TYPE_NAMED) {
1947  EvLinkDest *dest2;
1948  const gchar *named_dest;
1949 
1950  named_dest = ev_link_dest_get_named_dest (dest);
1952  named_dest);
1953  if (dest2) {
1954  goto_dest (view, dest2);
1955  g_object_unref (dest2);
1956  }
1957 
1958  return;
1959  }
1960 
1961  goto_dest (view, dest);
1962 }
1963 
1964 void
1966 {
1967  EvLinkAction *action = NULL;
1968  EvLinkActionType type;
1969 
1970  action = ev_link_get_action (link);
1971  if (!action)
1972  return;
1973 
1974  type = ev_link_action_get_action_type (action);
1975 
1976  switch (type) {
1978  EvLinkDest *dest;
1979 
1980  g_signal_emit (view, signals[SIGNAL_HANDLE_LINK], 0, link);
1981 
1982  dest = ev_link_action_get_dest (action);
1983  ev_view_goto_dest (view, dest);
1984  }
1985  break;
1987  GList *show, *hide, *toggle;
1988  GList *l;
1989  EvDocumentLayers *document_layers;
1990 
1991  document_layers = EV_DOCUMENT_LAYERS (view->document);
1992 
1993  show = ev_link_action_get_show_list (action);
1994  for (l = show; l; l = g_list_next (l)) {
1995  ev_document_layers_show_layer (document_layers, EV_LAYER (l->data));
1996  }
1997 
1998  hide = ev_link_action_get_hide_list (action);
1999  for (l = hide; l; l = g_list_next (l)) {
2000  ev_document_layers_hide_layer (document_layers, EV_LAYER (l->data));
2001  }
2002 
2003  toggle = ev_link_action_get_toggle_list (action);
2004  for (l = toggle; l; l = g_list_next (l)) {
2005  EvLayer *layer = EV_LAYER (l->data);
2006 
2007  if (ev_document_layers_layer_is_visible (document_layers, layer)) {
2008  ev_document_layers_hide_layer (document_layers, layer);
2009  } else {
2010  ev_document_layers_show_layer (document_layers, layer);
2011  }
2012  }
2013 
2014  g_signal_emit (view, signals[SIGNAL_LAYERS_CHANGED], 0);
2015  ev_view_reload (view);
2016  }
2017  break;
2022  g_signal_emit (view, signals[SIGNAL_EXTERNAL_LINK], 0, action);
2023  break;
2024  }
2025 }
2026 
2027 static char *
2029 {
2030  const gchar *name = ev_link_action_get_name (action);
2031 
2032  if (g_ascii_strcasecmp (name, "FirstPage") == 0) {
2033  return g_strdup (_("Go to first page"));
2034  } else if (g_ascii_strcasecmp (name, "PrevPage") == 0) {
2035  return g_strdup (_("Go to previous page"));
2036  } else if (g_ascii_strcasecmp (name, "NextPage") == 0) {
2037  return g_strdup (_("Go to next page"));
2038  } else if (g_ascii_strcasecmp (name, "LastPage") == 0) {
2039  return g_strdup (_("Go to last page"));
2040  } else if (g_ascii_strcasecmp (name, "GoToPage") == 0) {
2041  return g_strdup (_("Go to page"));
2042  } else if (g_ascii_strcasecmp (name, "Find") == 0) {
2043  return g_strdup (_("Find"));
2044  }
2045 
2046  return NULL;
2047 }
2048 
2049 static char *
2051 {
2052  EvLinkAction *action;
2053  EvLinkActionType type;
2054  char *msg = NULL;
2055  char *page_label;
2056  const char *title;
2057 
2058  action = ev_link_get_action (link);
2059  title = ev_link_get_title (link);
2060 
2061  if (!action)
2062  return title ? g_strdup (title) : NULL;
2063 
2064  type = ev_link_action_get_action_type (action);
2065 
2066  switch (type) {
2069  ev_link_action_get_dest (action));
2070  if (page_label) {
2071  msg = g_strdup_printf (_("Go to page %s"), page_label);
2072  g_free (page_label);
2073  }
2074  break;
2076  if (title) {
2077  msg = g_strdup_printf (_("Go to %s on file “%s”"), title,
2078  ev_link_action_get_filename (action));
2079  } else {
2080  msg = g_strdup_printf (_("Go to file “%s”"),
2081  ev_link_action_get_filename (action));
2082  }
2083  break;
2085  msg = g_strdup (ev_link_action_get_uri (action));
2086  break;
2088  msg = g_strdup_printf (_("Launch %s"),
2089  ev_link_action_get_filename (action));
2090  break;
2092  msg = tip_from_action_named (action);
2093  break;
2094  default:
2095  if (title)
2096  msg = g_strdup (title);
2097  break;
2098  }
2099 
2100  return msg;
2101 }
2102 
2103 static void
2104 ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y)
2105 {
2106  EvLink *link;
2107  EvFormField *field;
2108  EvAnnotation *annot = NULL;
2109  EvMedia *media;
2110 
2111  if (view->cursor == EV_VIEW_CURSOR_HIDDEN)
2112  return;
2113 
2114  if (view->adding_annot_info.adding_annot) {
2117  } else if (!view->adding_annot_info.annot) {
2119  }
2120  return;
2121  }
2122 
2123  if (view->drag_info.in_drag) {
2124  if (view->cursor != EV_VIEW_CURSOR_DRAG)
2126  return;
2127  }
2128 
2129  if (view->scroll_info.autoscrolling) {
2130  if (view->cursor != EV_VIEW_CURSOR_AUTOSCROLL)
2132  return;
2133  }
2134 
2135  link = ev_view_get_link_at_location (view, x, y);
2136  if (link) {
2138  } else if ((field = ev_view_get_form_field_at_location (view, x, y))) {
2139  if (field->is_read_only) {
2140  if (view->cursor == EV_VIEW_CURSOR_LINK ||
2141  view->cursor == EV_VIEW_CURSOR_IBEAM ||
2142  view->cursor == EV_VIEW_CURSOR_DRAG)
2144  } else if (EV_IS_FORM_FIELD_TEXT (field)) {
2146  } else {
2148  }
2149  } else if ((media = ev_view_get_media_at_location (view, x, y))) {
2150  if (!ev_view_find_player_for_media (view, media))
2152  else
2154  } else if ((annot = ev_view_get_annotation_at_location (view, x, y))) {
2156  } else if (location_in_text (view, x + view->scroll_x, y + view->scroll_y)) {
2158  } else {
2159  if (view->cursor == EV_VIEW_CURSOR_LINK ||
2160  view->cursor == EV_VIEW_CURSOR_IBEAM ||
2161  view->cursor == EV_VIEW_CURSOR_DRAG ||
2162  view->cursor == EV_VIEW_CURSOR_AUTOSCROLL ||
2163  view->cursor == EV_VIEW_CURSOR_ADD)
2165  }
2166 
2167  if (link || annot)
2168  g_object_set (view, "has-tooltip", TRUE, NULL);
2169 }
2170 
2171 /*** Images ***/
2172 static EvImage *
2174  gdouble x,
2175  gdouble y)
2176 {
2177  gint page = -1;
2178  gint x_new = 0, y_new = 0;
2179  EvMappingList *image_mapping;
2180 
2181  if (!EV_IS_DOCUMENT_IMAGES (view->document))
2182  return NULL;
2183 
2184  if (!get_doc_point_from_location (view, x, y, &page, &x_new, &y_new))
2185  return NULL;
2186 
2187  image_mapping = ev_page_cache_get_image_mapping (view->page_cache, page);
2188 
2189  if (image_mapping)
2190  return ev_mapping_list_get_data (image_mapping, x_new, y_new);
2191  else
2192  return NULL;
2193 }
2194 
2195 /*** Focus ***/
2196 static gboolean
2198  GdkRectangle *area)
2199 {
2200  if (!view->focused_element)
2201  return FALSE;
2202 
2204  view->focused_element_page,
2205  &view->focused_element->area,
2206  area);
2207  area->x -= view->scroll_x + 1;
2208  area->y -= view->scroll_y + 1;
2209  area->width += 1;
2210  area->height += 1;
2211 
2212  return TRUE;
2213 }
2214 
2215 void
2217  EvMapping *element_mapping,
2218  gint page)
2219 {
2220  GdkRectangle view_rect;
2221  cairo_region_t *region = NULL;
2222 
2223  if (view->focused_element == element_mapping)
2224  return;
2225 
2226  if (view->accessible)
2227  ev_view_accessible_set_focused_element (EV_VIEW_ACCESSIBLE (view->accessible), element_mapping, page);
2228 
2229  if (ev_view_get_focused_area (view, &view_rect))
2230  region = cairo_region_create_rectangle (&view_rect);
2231 
2232  view->focused_element = element_mapping;
2233  view->focused_element_page = page;
2234 
2235  if (ev_view_get_focused_area (view, &view_rect)) {
2236  if (!region)
2237  region = cairo_region_create_rectangle (&view_rect);
2238  else
2239  cairo_region_union_rectangle (region, &view_rect);
2240 
2241  ev_document_model_set_page (view->model, page);
2242  view_rect.x += view->scroll_x;
2243  view_rect.y += view->scroll_y;
2244  ensure_rectangle_is_visible (view, &view_rect);
2245  }
2246 
2247  if (region) {
2248  gdk_window_invalidate_region (gtk_widget_get_window (GTK_WIDGET (view)),
2249  region, TRUE);
2250  cairo_region_destroy (region);
2251  }
2252 }
2253 
2254 /*** Forms ***/
2255 static EvMapping *
2257  gdouble x,
2258  gdouble y,
2259  gint *page)
2260 {
2261  gint x_new = 0, y_new = 0;
2262  EvMappingList *forms_mapping;
2263 
2264  if (!EV_IS_DOCUMENT_FORMS (view->document))
2265  return NULL;
2266 
2267  if (!get_doc_point_from_location (view, x, y, page, &x_new, &y_new))
2268  return NULL;
2269 
2270  forms_mapping = ev_page_cache_get_form_field_mapping (view->page_cache, *page);
2271 
2272  if (forms_mapping)
2273  return ev_mapping_list_get (forms_mapping, x_new, y_new);
2274 
2275  return NULL;
2276 }
2277 
2278 static EvFormField *
2280  gdouble x,
2281  gdouble y)
2282 {
2283  EvMapping *field_mapping;
2284  gint page;
2285 
2286  field_mapping = get_form_field_mapping_at_location (view, x, y, &page);
2287 
2288  return field_mapping ? field_mapping->data : NULL;
2289 }
2290 
2291 static cairo_region_t *
2293  EvFormField *field)
2294 {
2295  GdkRectangle view_area;
2296  EvMappingList *forms_mapping;
2297 
2298  forms_mapping = ev_page_cache_get_form_field_mapping (view->page_cache,
2299  field->page->index);
2300  ev_view_get_area_from_mapping (view, field->page->index,
2301  forms_mapping,
2302  field, &view_area);
2303 
2304  return cairo_region_create_rectangle (&view_area);
2305 }
2306 
2307 static gboolean
2309 {
2311 
2312  return FALSE;
2313 }
2314 
2315 static void
2316 ev_view_form_field_destroy (GtkWidget *widget,
2317  EvView *view)
2318 {
2319  g_idle_add ((GSourceFunc)ev_view_forms_remove_widgets, view);
2320 }
2321 
2322 static void
2324  EvFormField *field)
2325 {
2326  EvMappingList *forms_mapping;
2327  cairo_region_t *region;
2328  gboolean state;
2329  GList *l;
2330  EvFormFieldButton *field_button = EV_FORM_FIELD_BUTTON (field);
2331 
2332  if (field_button->type == EV_FORM_FIELD_BUTTON_PUSH)
2333  return;
2334 
2336  field);
2337 
2338  /* FIXME: it actually depends on NoToggleToOff flags */
2339  if (field_button->type == EV_FORM_FIELD_BUTTON_RADIO && state && field_button->state)
2340  return;
2341 
2342  region = ev_view_form_field_get_region (view, field);
2343 
2344  /* For radio buttons and checkbox buttons that are in a set
2345  * we need to update also the region for the current selected item
2346  */
2347  forms_mapping = ev_page_cache_get_form_field_mapping (view->page_cache,
2348  field->page->index);
2349 
2350  for (l = ev_mapping_list_get_list (forms_mapping); l; l = g_list_next (l)) {
2351  EvFormField *button = ((EvMapping *)(l->data))->data;
2352  cairo_region_t *button_region;
2353 
2354  if (button->id == field->id)
2355  continue;
2356 
2357  /* FIXME: only buttons in the same group should be updated */
2358  if (!EV_IS_FORM_FIELD_BUTTON (button) ||
2359  EV_FORM_FIELD_BUTTON (button)->type != field_button->type ||
2360  EV_FORM_FIELD_BUTTON (button)->state != TRUE)
2361  continue;
2362 
2363  button_region = ev_view_form_field_get_region (view, button);
2364  cairo_region_union (region, button_region);
2365  cairo_region_destroy (button_region);
2366  }
2367 
2368  /* Update state */
2370  field,
2371  !state);
2372  field_button->state = !state;
2373 
2374  if (view->accessible)
2376  ev_mapping_list_find (forms_mapping, field),
2377  field->page->index);
2378 
2379  ev_view_reload_page (view, field->page->index, region);
2380  cairo_region_destroy (region);
2381 }
2382 
2383 static GtkWidget *
2385  EvFormField *field)
2386 {
2387  EvMappingList *form_mapping;
2388  EvMapping *mapping;
2389 
2390  /* We need to do this focus grab prior to setting the focused element for accessibility */
2391  if (!gtk_widget_has_focus (GTK_WIDGET (view)))
2392  gtk_widget_grab_focus (GTK_WIDGET (view));
2393 
2394  form_mapping = ev_page_cache_get_form_field_mapping (view->page_cache,
2395  field->page->index);
2396  mapping = ev_mapping_list_find (form_mapping, field);
2397  _ev_view_set_focused_element (view, mapping, field->page->index);
2398 
2399  return NULL;
2400 }
2401 
2402 static void
2404  GtkWidget *widget)
2405 {
2406  EvFormField *field;
2407 
2408  if (!view->document)
2409  return;
2410 
2411  field = g_object_get_data (G_OBJECT (widget), "form-field");
2412 
2413  if (field->changed) {
2414  EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field);
2415  cairo_region_t *field_region;
2416 
2417  field_region = ev_view_form_field_get_region (view, field);
2418 
2420  field, field_text->text);
2421  field->changed = FALSE;
2422  ev_view_reload_page (view, field->page->index, field_region);
2423  cairo_region_destroy (field_region);
2424  }
2425 }
2426 
2427 static void
2429  EvFormField *field)
2430 {
2431  EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field);
2432  gchar *text = NULL;
2433 
2434  if (GTK_IS_ENTRY (widget)) {
2435  text = g_strdup (gtk_entry_get_text (GTK_ENTRY (widget)));
2436  } else if (GTK_IS_TEXT_BUFFER (widget)) {
2437  GtkTextIter start, end;
2438 
2439  gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (widget), &start, &end);
2440  text = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (widget),
2441  &start, &end, FALSE);
2442  }
2443 
2444  if (!field_text->text ||
2445  (field_text->text && g_ascii_strcasecmp (field_text->text, text) != 0)) {
2446  g_free (field_text->text);
2447  field_text->text = text;
2448  field->changed = TRUE;
2449  }
2450 }
2451 
2452 static gboolean
2454  GdkEventFocus *event,
2455  EvView *view)
2456 {
2457  ev_view_form_field_text_save (view, widget);
2458 
2459  return FALSE;
2460 }
2461 
2462 static GtkWidget *
2464  EvFormField *field)
2465 {
2466  EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field);
2467  GtkWidget *text = NULL;
2468  gchar *txt;
2469 
2471  field);
2472 
2473  switch (field_text->type) {
2475  /* TODO */
2477  text = gtk_entry_new ();
2478  gtk_entry_set_has_frame (GTK_ENTRY (text), FALSE);
2479  gtk_entry_set_max_length (GTK_ENTRY (text), field_text->max_len);
2480  gtk_entry_set_visibility (GTK_ENTRY (text), !field_text->is_password);
2481 
2482  if (txt) {
2483  gtk_entry_set_text (GTK_ENTRY (text), txt);
2484  g_free (txt);
2485  }
2486 
2487  g_signal_connect (text, "focus-out-event",
2488  G_CALLBACK (ev_view_form_field_text_focus_out),
2489  view);
2490  g_signal_connect (text, "changed",
2491  G_CALLBACK (ev_view_form_field_text_changed),
2492  field);
2493  g_signal_connect_after (text, "activate",
2494  G_CALLBACK (ev_view_form_field_destroy),
2495  view);
2496  break;
2498  GtkTextBuffer *buffer;
2499 
2500  text = gtk_text_view_new ();
2501  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text));
2502 
2503  if (txt) {
2504  gtk_text_buffer_set_text (buffer, txt, -1);
2505  g_free (txt);
2506  }
2507 
2508  g_signal_connect (text, "focus-out-event",
2509  G_CALLBACK (ev_view_form_field_text_focus_out),
2510  view);
2511  g_signal_connect (buffer, "changed",
2512  G_CALLBACK (ev_view_form_field_text_changed),
2513  field);
2514  }
2515  break;
2516  }
2517 
2518  g_object_weak_ref (G_OBJECT (text),
2519  (GWeakNotify)ev_view_form_field_text_save,
2520  view);
2521 
2522  return text;
2523 }
2524 
2525 static void
2527  GtkWidget *widget)
2528 {
2529  EvFormField *field;
2530 
2531  if (!view->document)
2532  return;
2533 
2534  field = g_object_get_data (G_OBJECT (widget), "form-field");
2535 
2536  if (field->changed) {
2537  GList *l;
2538  EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field);
2539  cairo_region_t *field_region;
2540 
2541  field_region = ev_view_form_field_get_region (view, field);
2542 
2543  if (field_choice->is_editable) {
2545  field, field_choice->text);
2546  } else {
2548  for (l = field_choice->selected_items; l; l = g_list_next (l)) {
2550  field,
2551  GPOINTER_TO_INT (l->data));
2552  }
2553  }
2554  field->changed = FALSE;
2555  ev_view_reload_page (view, field->page->index, field_region);
2556  cairo_region_destroy (field_region);
2557  }
2558 }
2559 
2560 static void
2562  EvFormField *field)
2563 {
2564  EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field);
2565 
2566  if (GTK_IS_COMBO_BOX (widget)) {
2567  gint item;
2568 
2569  item = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
2570  if (!field_choice->selected_items ||
2571  GPOINTER_TO_INT (field_choice->selected_items->data) != item) {
2572  g_list_free (field_choice->selected_items);
2573  field_choice->selected_items = NULL;
2574  field_choice->selected_items = g_list_prepend (field_choice->selected_items,
2575  GINT_TO_POINTER (item));
2576  field->changed = TRUE;
2577  }
2578 
2579  if (gtk_combo_box_get_has_entry (GTK_COMBO_BOX (widget))) {
2580  const gchar *text;
2581 
2582  text = gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (widget))));
2583  if (!field_choice->text ||
2584  (field_choice->text && g_ascii_strcasecmp (field_choice->text, text) != 0)) {
2585  g_free (field_choice->text);
2586  field_choice->text = g_strdup (text);
2587  field->changed = TRUE;
2588  }
2589  }
2590  } else if (GTK_IS_TREE_SELECTION (widget)) {
2591  GtkTreeSelection *selection = GTK_TREE_SELECTION (widget);
2592  GtkTreeModel *model;
2593  GList *items, *l;
2594 
2595  items = gtk_tree_selection_get_selected_rows (selection, &model);
2596  g_list_free (field_choice->selected_items);
2597  field_choice->selected_items = NULL;
2598 
2599  for (l = items; l && l->data; l = g_list_next (l)) {
2600  GtkTreeIter iter;
2601  GtkTreePath *path = (GtkTreePath *)l->data;
2602  gint item;
2603 
2604  gtk_tree_model_get_iter (model, &iter, path);
2605  gtk_tree_model_get (model, &iter, 1, &item, -1);
2606 
2607  field_choice->selected_items = g_list_prepend (field_choice->selected_items,
2608  GINT_TO_POINTER (item));
2609 
2610  gtk_tree_path_free (path);
2611  }
2612 
2613  g_list_free (items);
2614 
2615  field->changed = TRUE;
2616  }
2617 }
2618 
2619 static GtkWidget *
2621  EvFormField *field)
2622 {
2623  EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field);
2624  GtkWidget *choice;
2625  GtkTreeModel *model;
2626  gint n_items, i;
2627  gint selected_item = 0;
2628 
2630  field);
2631  model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT));
2632  for (i = 0; i < n_items; i++) {
2633  GtkTreeIter iter;
2634  gchar *item;
2635 
2637  field, i);
2639  EV_DOCUMENT_FORMS (view->document), field, i)) {
2640  selected_item = i;
2641  /* FIXME: we need a get_selected_items function in poppler */
2642  field_choice->selected_items = g_list_prepend (field_choice->selected_items,
2643  GINT_TO_POINTER (i));
2644  }
2645 
2646  if (item) {
2647  gtk_list_store_append (GTK_LIST_STORE (model), &iter);
2648  gtk_list_store_set (GTK_LIST_STORE (model), &iter,
2649  0, item,
2650  1, i,
2651  -1);
2652  g_free (item);
2653  }
2654  }
2655 
2656  if (field_choice->type == EV_FORM_FIELD_CHOICE_LIST) {
2657  GtkCellRenderer *renderer;
2658  GtkWidget *tree_view;
2659  GtkTreeSelection *selection;
2660 
2661  tree_view = gtk_tree_view_new_with_model (model);
2662  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
2663 
2664  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
2665  if (field_choice->multi_select) {
2666  gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
2667  }
2668 
2669  /* TODO: set selected items */
2670 
2671  renderer = gtk_cell_renderer_text_new ();
2672  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
2673  0,
2674  "choix", renderer,
2675  "text", 0,
2676  NULL);
2677 
2678  choice = gtk_scrolled_window_new (NULL, NULL);
2679  gtk_container_add (GTK_CONTAINER (choice), tree_view);
2680  gtk_widget_show (tree_view);
2681 
2682  g_signal_connect (selection, "changed",
2683  G_CALLBACK (ev_view_form_field_choice_changed),
2684  field);
2685  g_signal_connect_after (selection, "changed",
2686  G_CALLBACK (ev_view_form_field_destroy),
2687  view);
2688  } else if (field_choice->is_editable) { /* ComboBoxEntry */
2689  gchar *text;
2690 
2691  choice = gtk_combo_box_new_with_model_and_entry (model);
2692  gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (choice), 0);
2693 
2695  if (text) {
2696  gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (choice))), text);
2697  g_free (text);
2698  }
2699 
2700  g_signal_connect (choice, "changed",
2701  G_CALLBACK (ev_view_form_field_choice_changed),
2702  field);
2703  g_signal_connect_after (gtk_bin_get_child (GTK_BIN (choice)),
2704  "activate",
2705  G_CALLBACK (ev_view_form_field_destroy),
2706  view);
2707  } else { /* ComboBoxText */
2708  GtkCellRenderer *renderer;
2709 
2710  choice = gtk_combo_box_new_with_model (model);
2711  renderer = gtk_cell_renderer_text_new ();
2712  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (choice),
2713  renderer, TRUE);
2714  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (choice),
2715  renderer,
2716  "text", 0,
2717  NULL);
2718  gtk_combo_box_set_active (GTK_COMBO_BOX (choice), selected_item);
2719  gtk_combo_box_popup (GTK_COMBO_BOX (choice));
2720 
2721  g_signal_connect (choice, "changed",
2722  G_CALLBACK (ev_view_form_field_choice_changed),
2723  field);
2724  g_signal_connect_after (choice, "changed",
2725  G_CALLBACK (ev_view_form_field_destroy),
2726  view);
2727  }
2728 
2729  g_object_unref (model);
2730 
2731  g_object_weak_ref (G_OBJECT (choice),
2732  (GWeakNotify)ev_view_form_field_choice_save,
2733  view);
2734 
2735  return choice;
2736 }
2737 
2738 void
2740  EvFormField *field)
2741 {
2742  GtkWidget *field_widget = NULL;
2743  EvMappingList *form_field_mapping;
2744  EvMapping *mapping;
2745 
2746  _ev_view_set_focused_element (view, NULL, -1);
2747 
2748  if (field->is_read_only)
2749  return;
2750 
2751  if (EV_IS_FORM_FIELD_BUTTON (field)) {
2752  field_widget = ev_view_form_field_button_create_widget (view, field);
2753  } else if (EV_IS_FORM_FIELD_TEXT (field)) {
2754  field_widget = ev_view_form_field_text_create_widget (view, field);
2755  } else if (EV_IS_FORM_FIELD_CHOICE (field)) {
2756  field_widget = ev_view_form_field_choice_create_widget (view, field);
2757  } else if (EV_IS_FORM_FIELD_SIGNATURE (field)) {
2758  /* TODO */
2759  }
2760 
2761  /* Form field doesn't require a widget */
2762  if (!field_widget) {
2763  if (!gtk_widget_has_focus (GTK_WIDGET (view)))
2764  gtk_widget_grab_focus (GTK_WIDGET (view));
2765  return;
2766  }
2767 
2768  g_object_set_data_full (G_OBJECT (field_widget), "form-field",
2769  g_object_ref (field),
2770  (GDestroyNotify)g_object_unref);
2771 
2772  form_field_mapping = ev_page_cache_get_form_field_mapping (view->page_cache,
2773  field->page->index);
2774  mapping = ev_mapping_list_find (form_field_mapping, field);
2775  _ev_view_set_focused_element (view, mapping, field->page->index);
2776  ev_view_put_to_doc_rect (view, field_widget, field->page->index, &mapping->area);
2777  gtk_widget_show (field_widget);
2778  gtk_widget_grab_focus (field_widget);
2779 }
2780 
2781 static void
2783  EvFormField *field)
2784 {
2785  if (field->is_read_only)
2786  return;
2787 
2788  _ev_view_focus_form_field (view, field);
2789 
2790  if (field->activation_link)
2791  ev_view_handle_link (view, field->activation_link);
2792 
2793  if (EV_IS_FORM_FIELD_BUTTON (field))
2794  ev_view_form_field_button_toggle (view, field);
2795 
2796 }
2797 
2798 /* Media */
2799 static EvMapping *
2801  gdouble x,
2802  gdouble y,
2803  gint *page)
2804 {
2805 #ifdef ENABLE_MULTIMEDIA
2806  gint x_new = 0, y_new = 0;
2807  EvMappingList *media_mapping;
2808 
2809  if (!EV_IS_DOCUMENT_MEDIA (view->document))
2810  return NULL;
2811 
2812  if (!get_doc_point_from_location (view, x, y, page, &x_new, &y_new))
2813  return NULL;
2814 
2815  media_mapping = ev_page_cache_get_media_mapping (view->page_cache, *page);
2816 
2817  return media_mapping ? ev_mapping_list_get (media_mapping, x_new, y_new) : NULL;
2818 #else
2819  return NULL;
2820 #endif
2821 }
2822 
2823 static EvMedia *
2825  gdouble x,
2826  gdouble y)
2827 {
2828  EvMapping *media_mapping;
2829  gint page;
2830 
2831  media_mapping = get_media_mapping_at_location (view, x, y, &page);
2832 
2833  return media_mapping ? media_mapping->data : NULL;
2834 }
2835 
2836 static gboolean
2838  EvMedia *media)
2839 {
2840 #ifdef ENABLE_MULTIMEDIA
2841  GList *l;
2842 
2843  for (l = view->children; l; l = g_list_next (l)) {
2844  EvViewChild *child = (EvViewChild *)l->data;
2845 
2846  if (!EV_IS_MEDIA_PLAYER (child->widget))
2847  continue;
2848 
2849  if (ev_media_player_get_media (EV_MEDIA_PLAYER (child->widget)) == media)
2850  return TRUE;
2851  }
2852 #endif
2853 
2854  return FALSE;
2855 }
2856 
2857 static void
2859  EvMedia *media)
2860 {
2861 #ifdef ENABLE_MULTIMEDIA
2862  GtkWidget *player;
2863  EvMappingList *media_mapping;
2864  EvMapping *mapping;
2865  GdkRectangle render_area;
2866  guint page;
2867 
2868  page = ev_media_get_page_index (media);
2869  media_mapping = ev_page_cache_get_media_mapping (view->page_cache, page);
2870 
2871  /* TODO: focus? */
2872 
2873  if (ev_view_find_player_for_media (view, media))
2874  return;
2875 
2876  player = ev_media_player_new (media);
2877 
2878  mapping = ev_mapping_list_find (media_mapping, media);
2879  _ev_view_transform_doc_rect_to_view_rect (view, page, &mapping->area, &render_area);
2880  render_area.x -= view->scroll_x;
2881  render_area.y -= view->scroll_y;
2882 
2883  ev_view_put (view, player, render_area.x, render_area.y, page, &mapping->area);
2884  gtk_widget_show (player);
2885 #endif /* ENABLE_MULTIMEDIA */
2886 }
2887 
2888 /* Annotations */
2889 static GtkWidget *
2891  EvAnnotation *annot)
2892 {
2893  if (view->annot_window_map == NULL)
2894  return NULL;
2895 
2896  return g_hash_table_lookup (view->annot_window_map, annot);
2897 }
2898 
2899 static void
2901  EvAnnotation *annot,
2902  GtkWidget *window)
2903 {
2904  if (view->annot_window_map == NULL)
2905  view->annot_window_map = g_hash_table_new (g_direct_hash, NULL);
2906 
2907  g_hash_table_insert (view->annot_window_map, annot, window);
2908 }
2909 
2910 static EvViewWindowChild *
2912  GtkWidget *window)
2913 {
2914  GList *children = view->window_children;
2915 
2916  while (children) {
2917  EvViewWindowChild *child;
2918 
2919  child = (EvViewWindowChild *)children->data;
2920  children = children->next;
2921 
2922  if (child->window == window)
2923  return child;
2924  }
2925 
2926  return NULL;
2927 }
2928 
2929 static void
2931  EvViewWindowChild *child,
2932  gint x,
2933  gint y)
2934 {
2935  GtkAllocation allocation;
2936  gint width, height;
2937 
2938  gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
2939  gtk_window_get_size (GTK_WINDOW (child->window), &width, &height);
2940 
2941  child->x = x;
2942  child->y = y;
2943  gtk_window_move (GTK_WINDOW (child->window),
2944  CLAMP (x, child->parent_x,
2945  child->parent_x + allocation.width - width),
2946  CLAMP (y, child->parent_y,
2947  child->parent_y + allocation.height - height));
2948 }
2949 
2950 static void
2952  GtkWidget *window)
2953 {
2954  EvViewWindowChild *child;
2955  gint root_x, root_y;
2956 
2957  child = ev_view_get_window_child (view, window);
2958  gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (view)),
2959  &root_x, &root_y);
2960  if (root_x != child->parent_x || root_y != child->parent_y) {
2961  gint dest_x, dest_y;
2962 
2963  dest_x = child->x + (root_x - child->parent_x);
2964  dest_y = child->y + (root_y - child->parent_y);
2965  child->parent_x = root_x;
2966  child->parent_y = root_y;
2967  ev_view_window_child_move (view, child, dest_x, dest_y);
2968  }
2969 
2970  if (child->visible && !gtk_widget_get_visible (window))
2971  gtk_widget_show (window);
2972 }
2973 
2974 static void
2976  GtkWidget *window,
2977  guint page,
2978  gint x,
2979  gint y,
2980  gdouble orig_x,
2981  gdouble orig_y)
2982 {
2983  EvViewWindowChild *child;
2984  gint root_x, root_y;
2985 
2986  gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (view)),
2987  &root_x, &root_y);
2988 
2989  child = g_new0 (EvViewWindowChild, 1);
2990  child->window = window;
2991  child->page = page;
2992  child->orig_x = orig_x;
2993  child->orig_y = orig_y;
2994  child->parent_x = root_x;
2995  child->parent_y = root_y;
2997  ev_view_window_child_move (view, child, x + root_x, y + root_y);
2998 
2999  if (child->visible)
3000  gtk_widget_show (window);
3001  else
3002  gtk_widget_hide (window);
3003 
3004  view->window_children = g_list_append (view->window_children, child);
3005 }
3006 
3007 static void
3009  guint page,
3010  EvAnnotation *annot)
3011 {
3012  GList *children = view->window_children;
3013 
3014  while (children) {
3015  EvViewWindowChild *child;
3016  EvAnnotation *wannot;
3017 
3018  child = (EvViewWindowChild *)children->data;
3019 
3020  if (child->page != page)
3021  continue;
3022 
3024  if (ev_annotation_equal (wannot, annot)) {
3025  gtk_widget_destroy (child->window);
3026  view->window_children = g_list_delete_link (view->window_children, children);
3027  break;
3028  }
3029  children = children->next;
3030  }
3031 }
3032 
3033 static void
3035 {
3036  GList *l;
3037 
3038  if (!view->window_children)
3039  return;
3040 
3041  for (l = view->window_children; l && l->data; l = g_list_next (l)) {
3042  EvViewWindowChild *child;
3043 
3044  child = (EvViewWindowChild *)l->data;
3045  gtk_widget_destroy (GTK_WIDGET (child->window));
3046  g_free (child);
3047  }
3048  g_list_free (view->window_children);
3049  view->window_children = NULL;
3050  view->window_child_focus = NULL;
3051 }
3052 
3053 static void
3054 annotation_window_grab_focus (GtkWidget *widget,
3055  EvView *view)
3056 {
3057  if (view->window_child_focus)
3059  view->window_child_focus = ev_view_get_window_child (view, widget);
3060 }
3061 
3062 static void
3064  EvView *view)
3065 {
3066  EvViewWindowChild *child;
3067 
3068  child = ev_view_get_window_child (view, GTK_WIDGET (window));
3069  child->visible = FALSE;
3070 }
3071 
3072 static void
3074  gint x,
3075  gint y,
3076  EvView *view)
3077 {
3078  EvViewWindowChild *child;
3079  GdkRectangle page_area;
3080  GtkBorder border;
3081  GdkRectangle view_rect;
3082  EvRectangle doc_rect;
3083  gint width, height;
3084 
3085  child = ev_view_get_window_child (view, GTK_WIDGET (window));
3086  if (child->x == x && child->y == y)
3087  return;
3088 
3089  child->moved = TRUE;
3090  child->x = x;
3091  child->y = y;
3092 
3093  /* Window has been moved by the user,
3094  * we have to set a new origin in doc coords
3095  */
3096  gtk_window_get_size (GTK_WINDOW (window), &width, &height);
3097  view_rect.x = (x - child->parent_x) + view->scroll_x;
3098  view_rect.y = (y - child->parent_y) + view->scroll_y;
3099  view_rect.width = width;
3100  view_rect.height = height;
3101 
3102  ev_view_get_page_extents (view, child->page, &page_area, &border);
3103  _ev_view_transform_view_rect_to_doc_rect (view, &view_rect, &page_area, &border, &doc_rect);
3104  child->orig_x = doc_rect.x1;
3105  child->orig_y = doc_rect.y1;
3106 }
3107 
3108 static void
3110  GParamSpec *pspec,
3111  EvAnnotation *annot)
3112 {
3113  if (!view->document)
3114  return;
3115 
3120 }
3121 
3122 static GtkWidget *
3124  EvAnnotation *annot,
3125  GtkWindow *parent)
3126 {
3127  GtkWidget *window;
3128  EvRectangle doc_rect;
3129  GdkRectangle view_rect;
3130  guint page;
3131 
3132  window = ev_annotation_window_new (annot, parent);
3133  g_signal_connect (window, "grab_focus",
3134  G_CALLBACK (annotation_window_grab_focus),
3135  view);
3136  g_signal_connect (window, "closed",
3137  G_CALLBACK (annotation_window_closed),
3138  view);
3139  g_signal_connect (window, "moved",
3140  G_CALLBACK (annotation_window_moved),
3141  view);
3142  g_signal_connect_swapped (annot, "notify::contents",
3143  G_CALLBACK (ev_view_annotation_save_contents),
3144  view);
3145  map_annot_to_window (view, annot, window);
3146 
3147  page = ev_annotation_get_page_index (annot);
3149  _ev_view_transform_doc_rect_to_view_rect (view, page, &doc_rect, &view_rect);
3150  view_rect.x -= view->scroll_x;
3151  view_rect.y -= view->scroll_y;
3152 
3153  ev_view_window_child_put (view, window, page,
3154  view_rect.x, view_rect.y,
3155  doc_rect.x1, doc_rect.y1);
3156 
3157  return window;
3158 }
3159 
3160 static void
3162  gint page)
3163 {
3164  EvMappingList *annots;
3165  GList *l;
3166  GtkWindow *parent;
3167 
3168  parent = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view)));
3169 
3170  annots = ev_page_cache_get_annot_mapping (view->page_cache, page);
3171 
3172  for (l = ev_mapping_list_get_list (annots); l && l->data; l = g_list_next (l)) {
3173  EvAnnotation *annot;
3174  GtkWidget *window;
3175 
3176  annot = ((EvMapping *)(l->data))->data;
3177 
3178  if (!EV_IS_ANNOTATION_MARKUP (annot))
3179  continue;
3180 
3182  continue;
3183 
3184  window = get_window_for_annot (view, annot);
3185  if (window) {
3187  } else {
3188  ev_view_create_annotation_window (view, annot, parent);
3189  }
3190  }
3191 }
3192 
3193 static void
3195  gint page)
3196 {
3197  EvMappingList *annots;
3198  GList *l;
3199 
3200  annots = ev_page_cache_get_annot_mapping (view->page_cache, page);
3201 
3202  for (l = ev_mapping_list_get_list (annots); l && l->data; l = g_list_next (l)) {
3203  EvAnnotation *annot;
3204  GtkWidget *window;
3205 
3206  annot = ((EvMapping *)(l->data))->data;
3207 
3208  if (!EV_IS_ANNOTATION_MARKUP (annot))
3209  continue;
3210 
3211  window = get_window_for_annot (view, annot);
3212  if (window)
3213  gtk_widget_hide (window);
3214  }
3215 }
3216 
3217 static EvMapping *
3219  gdouble x,
3220  gdouble y,
3221  gint *page)
3222 {
3223  gint x_new = 0, y_new = 0;
3224  EvMappingList *annotations_mapping;
3225 
3226  if (!EV_IS_DOCUMENT_ANNOTATIONS (view->document))
3227  return NULL;
3228 
3229  if (!get_doc_point_from_location (view, x, y, page, &x_new, &y_new))
3230  return NULL;
3231 
3232  annotations_mapping = ev_page_cache_get_annot_mapping (view->page_cache, *page);
3233 
3234  if (annotations_mapping)
3235  return ev_mapping_list_get (annotations_mapping, x_new, y_new);
3236 
3237  return NULL;
3238 }
3239 
3240 static EvAnnotation *
3242  gdouble x,
3243  gdouble y)
3244 {
3245  EvMapping *annotation_mapping;
3246  gint page;
3247 
3248  annotation_mapping = get_annotation_mapping_at_location (view, x, y, &page);
3249 
3250  return annotation_mapping ? annotation_mapping->data : NULL;
3251 }
3252 
3253 static void
3255  GtkWidget *window)
3256 {
3257  EvViewWindowChild *child;
3258 
3259  if (!window)
3260  return;
3261 
3262  child = ev_view_get_window_child (view, window);
3263  if (!child->visible) {
3264  child->visible = TRUE;
3265  ev_view_window_child_move (view, child, child->x, child->y);
3266  gtk_widget_show (window);
3267  }
3268 }
3269 
3270 static void
3272  EvAnnotation *annot,
3273  gdouble x,
3274  gdouble y,
3275  guint32 timestamp)
3276 {
3277  if (EV_IS_ANNOTATION_MARKUP (annot)) {
3278  GtkWidget *window;
3279 
3280  window = get_window_for_annot (view, annot);
3281  if (!window && ev_annotation_markup_can_have_popup (EV_ANNOTATION_MARKUP (annot))) {
3282  EvRectangle popup_rect;
3283  GtkWindow *parent;
3284  EvMappingList *annots;
3285  EvMapping *mapping;
3286 
3289  mapping = ev_mapping_list_find (annots, annot);
3290 
3291  popup_rect.x1 = mapping->area.x2;
3292  popup_rect.y1 = mapping->area.y2;
3293  popup_rect.x2 = popup_rect.x1 + ANNOT_POPUP_WINDOW_DEFAULT_WIDTH;
3294  popup_rect.y2 = popup_rect.y1 + ANNOT_POPUP_WINDOW_DEFAULT_HEIGHT;
3295  g_object_set (annot,
3296  "rectangle", &popup_rect,
3297  "has_popup", TRUE,
3298  "popup_is_open", TRUE,
3299  NULL);
3300 
3301  parent = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view)));
3302  window = ev_view_create_annotation_window (view, annot, parent);
3303  }
3304  ev_view_annotation_show_popup_window (view, window);
3305  }
3306 
3307  if (EV_IS_ANNOTATION_ATTACHMENT (annot)) {
3308  EvAttachment *attachment;
3309 
3311  if (attachment) {
3312  GError *error = NULL;
3313 
3314  ev_attachment_open (attachment,
3315  gtk_widget_get_screen (GTK_WIDGET (view)),
3316  timestamp,
3317  &error);
3318 
3319  if (error) {
3320  g_warning ("%s", error->message);
3321  g_error_free (error);
3322  }
3323  }
3324  }
3325 }
3326 
3327 static void
3329 {
3330  EvAnnotation *annot;
3331  EvPoint start;
3332  EvPoint end;
3333  gint annot_page;
3334  gint offset;
3335  GdkRectangle page_area;
3336  GtkBorder border;
3337  EvRectangle doc_rect, popup_rect;
3338  EvPage *page;
3339  GdkColor color = { 0, 65535, 65535, 0 };
3340  GdkRectangle view_rect;
3341  cairo_region_t *region;
3342 
3343  find_page_at_location (view, view->adding_annot_info.start.x, view->adding_annot_info.start.y, &annot_page, &offset, &offset);
3344  if (annot_page == -1) {
3346  return;
3347  }
3348 
3349  ev_view_get_page_extents (view, annot_page, &page_area, &border);
3350  _ev_view_transform_view_point_to_doc_point (view, &view->adding_annot_info.start, &page_area, &border,
3351  &start.x, &start.y);
3352  _ev_view_transform_view_point_to_doc_point (view, &view->adding_annot_info.stop, &page_area, &border,
3353  &end.x, &end.y);
3354 
3356  page = ev_document_get_page (view->document, annot_page);
3357  switch (view->adding_annot_info.type) {
3359  doc_rect.x1 = end.x;
3360  doc_rect.y1 = end.y;
3361  doc_rect.x2 = doc_rect.x1 + ANNOTATION_ICON_SIZE;
3362  doc_rect.y2 = doc_rect.y1 + ANNOTATION_ICON_SIZE;
3363  annot = ev_annotation_text_new (page);
3364  break;
3366  doc_rect.x1 = start.x;
3367  doc_rect.y1 = start.y;
3368  doc_rect.x2 = end.x;
3369  doc_rect.y2 = end.y;
3371  break;
3373  /* TODO */
3374  g_object_unref (page);
3376  return;
3377  default:
3378  g_assert_not_reached ();
3379  }
3380  g_object_unref (page);
3381 
3382  ev_annotation_set_area (annot, &doc_rect);
3383  ev_annotation_set_color (annot, &color);
3384 
3385  if (EV_IS_ANNOTATION_MARKUP (annot)) {
3386  popup_rect.x1 = doc_rect.x2;
3387  popup_rect.x2 = popup_rect.x1 + ANNOT_POPUP_WINDOW_DEFAULT_WIDTH;
3388  popup_rect.y1 = doc_rect.y2;
3389  popup_rect.y2 = popup_rect.y1 + ANNOT_POPUP_WINDOW_DEFAULT_HEIGHT;
3390  g_object_set (annot,
3391  "rectangle", &popup_rect,
3392  "has_popup", TRUE,
3393  "popup_is_open", FALSE,
3394  "label", g_get_real_name (),
3395  "opacity", 1.0,
3396  NULL);
3397  }
3399  annot, &doc_rect);
3401 
3402  /* If the page didn't have annots, mark the cache as dirty */
3403  if (!ev_page_cache_get_annot_mapping (view->page_cache, annot_page))
3405 
3406  _ev_view_transform_doc_rect_to_view_rect (view, annot_page, &doc_rect, &view_rect);
3407  view_rect.x -= view->scroll_x;
3408  view_rect.y -= view->scroll_y;
3409  region = cairo_region_create_rectangle (&view_rect);
3410  ev_view_reload_page (view, annot_page, region);
3411  cairo_region_destroy (region);
3412 
3413  view->adding_annot_info.annot = annot;
3414 }
3415 
3416 void
3418  EvMapping *annot_mapping)
3419 {
3420 
3421  if (!EV_IS_DOCUMENT_ANNOTATIONS (view->document))
3422  return;
3423 
3424  _ev_view_set_focused_element (view, annot_mapping,
3425  ev_annotation_get_page_index (EV_ANNOTATION (annot_mapping->data)));
3426 }
3427 
3428 void
3430  EvAnnotationType annot_type)
3431 {
3432  if (annot_type == EV_ANNOTATION_TYPE_UNKNOWN)
3433  return;
3434 
3435  if (view->adding_annot_info.adding_annot)
3436  return;
3437 
3439  view->adding_annot_info.type = annot_type;
3441 }
3442 
3443 void
3445 {
3446  gint x, y;
3447 
3448  if (!view->adding_annot_info.adding_annot)
3449  return;
3450 
3452  g_assert(!view->adding_annot_info.annot);
3453  ev_document_misc_get_pointer_position (GTK_WIDGET (view), &x, &y);
3454  ev_view_handle_cursor_over_xy (view, x, y);
3455 }
3456 
3457 void
3459  EvAnnotation *annot)
3460 {
3461  guint page;
3462 
3463  g_return_if_fail (EV_IS_VIEW (view));
3464  g_return_if_fail (EV_IS_ANNOTATION (annot));
3465 
3466  g_object_ref (annot);
3467 
3468  page = ev_annotation_get_page_index (annot);
3469 
3470  if (EV_IS_ANNOTATION_MARKUP (annot))
3471  ev_view_remove_window_child_for_annot (view, page, annot);
3472  if (view->annot_window_map != NULL)
3473  g_hash_table_remove (view->annot_window_map, annot);
3474 
3475  _ev_view_set_focused_element (view, NULL, -1);
3476 
3479  annot);
3481 
3483 
3484  /* FIXME: only redraw the annot area */
3485  ev_view_reload_page (view, page, NULL);
3486 
3487  g_signal_emit (view, signals[SIGNAL_ANNOT_REMOVED], 0, annot);
3488  g_object_unref (annot);
3489 }
3490 
3491 static gboolean
3493  gdouble x,
3494  gdouble y)
3495 {
3496  gint page = -1;
3497  gint x_new = 0, y_new = 0;
3498  EvSourceLink *link;
3499 
3500  if (!ev_document_has_synctex (view->document))
3501  return FALSE;
3502 
3503  if (!get_doc_point_from_location (view, x, y, &page, &x_new, &y_new))
3504  return FALSE;
3505 
3506  link = ev_document_synctex_backward_search (view->document, page, x_new, y_new);
3507  if (link) {
3508  g_signal_emit (view, signals[SIGNAL_SYNC_SOURCE], 0, link);
3509  ev_source_link_free (link);
3510 
3511  return TRUE;
3512  }
3513 
3514  return FALSE;
3515 }
3516 
3517 /* Caret navigation */
3518 #define CURSOR_ON_MULTIPLIER 2
3519 #define CURSOR_OFF_MULTIPLIER 1
3520 #define CURSOR_PEND_MULTIPLIER 3
3521 #define CURSOR_DIVIDER 3
3522 
3523 static inline gboolean
3525 {
3526  return (view->cursor_page == view->current_page ||
3527  (view->cursor_page >= view->start_page &&
3528  view->cursor_page <= view->end_page));
3529 }
3530 
3531 static gboolean
3533 {
3534  if (view->caret_enabled &&
3535  view->rotation == 0 &&
3536  cursor_is_in_visible_page (view) &&
3537  gtk_widget_has_focus (GTK_WIDGET (view)) &&
3538  view->pixbuf_cache &&
3540  GtkSettings *settings;
3541  gboolean blink;
3542 
3543  settings = gtk_widget_get_settings (GTK_WIDGET (view));
3544  g_object_get (settings, "gtk-cursor-blink", &blink, NULL);
3545 
3546  return blink;
3547  }
3548 
3549  return FALSE;
3550 }
3551 
3552 static gint
3554 {
3555  GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (view));
3556  gint time;
3557 
3558  g_object_get (settings, "gtk-cursor-blink-time", &time, NULL);
3559 
3560  return time;
3561 }
3562 
3563 static gint
3565 {
3566  GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (view));
3567  gint timeout;
3568 
3569  g_object_get (settings, "gtk-cursor-blink-timeout", &timeout, NULL);
3570 
3571  return timeout;
3572 }
3573 
3574 static gboolean
3576  gint page,
3577  gint offset,
3578  GdkRectangle *area)
3579 {
3580  EvRectangle *areas = NULL;
3581  EvRectangle *doc_rect;
3582  guint n_areas = 0;
3583  gfloat cursor_aspect_ratio;
3584  gint stem_width;
3585 
3586  if (!view->caret_enabled || view->rotation != 0)
3587  return FALSE;
3588 
3589  if (!view->page_cache)
3590  return FALSE;
3591 
3592  ev_page_cache_get_text_layout (view->page_cache, page, &areas, &n_areas);
3593  if (!areas)
3594  return FALSE;
3595 
3596  if (offset > n_areas)
3597  return FALSE;
3598 
3599  doc_rect = areas + offset;
3600  if (offset == n_areas ||
3601  ((doc_rect->x1 == doc_rect->x2 || doc_rect->y1 == doc_rect->y2) && offset > 0)) {
3602  EvRectangle *prev;
3603  EvRectangle last_rect;
3604 
3605  /* Special characters like \n have an empty bounding box
3606  * and the end of a page doesn't have any bounding box,
3607  * use the size of the previous area.
3608  */
3609  prev = areas + offset - 1;
3610  last_rect.x1 = prev->x2;
3611  last_rect.y1 = prev->y1;
3612  last_rect.x2 = prev->x2 + (prev->x2 - prev->x1);
3613  last_rect.y2 = prev->y2;
3614 
3615  _ev_view_transform_doc_rect_to_view_rect (view, page, &last_rect, area);
3616  } else {
3617  _ev_view_transform_doc_rect_to_view_rect (view, page, doc_rect, area);
3618  }
3619 
3620  area->x -= view->scroll_x;
3621  area->y -= view->scroll_y;
3622 
3623  gtk_style_context_get_style (gtk_widget_get_style_context (GTK_WIDGET (view)),
3624  "cursor-aspect-ratio", &cursor_aspect_ratio,
3625  NULL);
3626  stem_width = area->height * cursor_aspect_ratio + 1;
3627  area->x -= (stem_width / 2);
3628  area->width = stem_width;
3629 
3630  return TRUE;
3631 }
3632 
3633 static void
3635 {
3636  GtkWidget *widget;
3637  GdkRectangle view_rect;
3638 
3639  if (view->cursor_visible)
3640  return;
3641 
3642  widget = GTK_WIDGET (view);
3643  view->cursor_visible = TRUE;
3644  if (gtk_widget_has_focus (widget) &&
3645  get_caret_cursor_area (view, view->cursor_page, view->cursor_offset, &view_rect)) {
3646  gtk_widget_queue_draw_area (widget,
3647  view_rect.x, view_rect.y,
3648  view_rect.width, view_rect.height);
3649  }
3650 }
3651 
3652 static void
3654 {
3655  GtkWidget *widget;
3656  GdkRectangle view_rect;
3657 
3658  if (!view->cursor_visible)
3659  return;
3660 
3661  widget = GTK_WIDGET (view);
3662  view->cursor_visible = FALSE;
3663  if (gtk_widget_has_focus (widget) &&
3664  get_caret_cursor_area (view, view->cursor_page, view->cursor_offset, &view_rect)) {
3665  gtk_widget_queue_draw_area (widget,
3666  view_rect.x, view_rect.y,
3667  view_rect.width, view_rect.height);
3668  }
3669 }
3670 
3671 static gboolean
3673 {
3674  gint blink_timeout;
3675  guint blink_time;
3676 
3677  blink_timeout = get_cursor_blink_timeout_id (view);
3678  if (view->cursor_blink_time > 1000 * blink_timeout && blink_timeout < G_MAXINT / 1000) {
3679  /* We've blinked enough without the user doing anything, stop blinking */
3680  show_cursor (view);
3681  view->cursor_blink_timeout_id = 0;
3682 
3683  return FALSE;
3684  }
3685 
3686  blink_time = get_cursor_blink_time (view);
3687  if (view->cursor_visible) {
3688  hide_cursor (view);
3689  blink_time *= CURSOR_OFF_MULTIPLIER;
3690  } else {
3691  show_cursor (view);
3692  view->cursor_blink_time += blink_time;
3693  blink_time *= CURSOR_ON_MULTIPLIER;
3694  }
3695 
3696  view->cursor_blink_timeout_id = gdk_threads_add_timeout (blink_time / CURSOR_DIVIDER, (GSourceFunc)blink_cb, view);
3697 
3698  return FALSE;
3699 }
3700 
3701 static void
3703 {
3704  if (cursor_should_blink (view)) {
3705  if (view->cursor_blink_timeout_id == 0) {
3706  show_cursor (view);
3707  view->cursor_blink_timeout_id = gdk_threads_add_timeout (get_cursor_blink_time (view) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER,
3708  (GSourceFunc)blink_cb, view);
3709  }
3710 
3711  return;
3712  }
3713 
3714  if (view->cursor_blink_timeout_id > 0) {
3715  g_source_remove (view->cursor_blink_timeout_id);
3716  view->cursor_blink_timeout_id = 0;
3717  }
3718 
3719  view->cursor_visible = TRUE;
3720  view->cursor_blink_time = 0;
3721 }
3722 
3723 static void
3725 {
3726  if (!cursor_should_blink (view))
3727  return;
3728 
3729  if (view->cursor_blink_timeout_id > 0)
3730  g_source_remove (view->cursor_blink_timeout_id);
3731 
3732  show_cursor (view);
3733  view->cursor_blink_timeout_id = gdk_threads_add_timeout (get_cursor_blink_time (view) * CURSOR_PEND_MULTIPLIER / CURSOR_DIVIDER,
3734  (GSourceFunc)blink_cb, view);
3735 }
3736 
3737 static void
3739 {
3740  gint n_pages;
3741 
3742  if (!view->document)
3743  return;
3744 
3745  /* Upload to the cache the first and last pages,
3746  * this information is needed to position the cursor
3747  * in the beginning/end of the document, for example
3748  * when pressing <Ctr>Home/End
3749  */
3750  n_pages = ev_document_get_n_pages (view->document);
3751 
3752  /* For documents with at least 3 pages, those are already cached anyway */
3753  if (n_pages > 0 && n_pages <= 3)
3754  return;
3755 
3757  ev_page_cache_ensure_page (view->page_cache, n_pages - 1);
3758 }
3759 
3768 gboolean
3770 {
3771  EvDocumentTextInterface *iface;
3772 
3773  if (!view->document || !EV_IS_DOCUMENT_TEXT (view->document))
3774  return FALSE;
3775 
3776  iface = EV_DOCUMENT_TEXT_GET_IFACE (view->document);
3777  if (!iface->get_text_layout || !iface->get_text)
3778  return FALSE;
3779 
3780  return TRUE;
3781 }
3782 
3792 void
3794  gboolean enabled)
3795 {
3796  g_return_if_fail (EV_IS_VIEW (view));
3797 
3798  if (view->caret_enabled != enabled) {
3799  view->caret_enabled = enabled;
3800  if (view->caret_enabled)
3802 
3804 
3805  if (cursor_is_in_visible_page (view))
3806  gtk_widget_queue_draw (GTK_WIDGET (view));
3807  }
3808 }
3809 
3818 gboolean
3820 {
3821  g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
3822 
3823  return view->caret_enabled;
3824 }
3825 
3834 void
3836  guint page,
3837  guint offset)
3838 {
3839  g_return_if_fail (EV_IS_VIEW (view));
3840  g_return_if_fail (EV_IS_DOCUMENT (view->document));
3841  g_return_if_fail (page < ev_document_get_n_pages (view->document));
3842 
3843  if (view->cursor_page != page || view->cursor_offset != offset) {
3844  view->cursor_page = page;
3845  view->cursor_offset = offset;
3846 
3847  g_signal_emit (view, signals[SIGNAL_CURSOR_MOVED], 0,
3848  view->cursor_page, view->cursor_offset);
3849 
3850  if (view->caret_enabled && cursor_is_in_visible_page (view))
3851  gtk_widget_queue_draw (GTK_WIDGET (view));
3852  }
3853 }
3854 
3855 /*** GtkWidget implementation ***/
3856 
3857 static void
3859  GtkRequisition *requisition)
3860 {
3861  gint n_pages;
3862 
3863  n_pages = ev_document_get_n_pages (view->document) + 1;
3864  get_page_y_offset (view, n_pages, &requisition->height);
3865 
3866  switch (view->sizing_mode) {
3867  case EV_SIZING_FIT_WIDTH:
3868  case EV_SIZING_FIT_PAGE:
3869  case EV_SIZING_AUTOMATIC:
3870  requisition->width = 1;
3871 
3872  break;
3873  case EV_SIZING_FREE: {
3874  gint max_width;
3875  GtkBorder border;
3876 
3877  ev_view_get_max_page_size (view, &max_width, NULL);
3878  compute_border (view, &border);
3879  requisition->width = (max_width + border.left + border.right) * 2 + (view->spacing * 3);
3880  }
3881  break;
3882  default:
3883  g_assert_not_reached ();
3884  }
3885 }
3886 
3887 static void
3889  GtkRequisition *requisition)
3890 {
3891  gint n_pages;
3892 
3893  n_pages = ev_document_get_n_pages (view->document);
3894  get_page_y_offset (view, n_pages, &requisition->height);
3895 
3896  switch (view->sizing_mode) {
3897  case EV_SIZING_FIT_WIDTH:
3898  case EV_SIZING_FIT_PAGE:
3899  case EV_SIZING_AUTOMATIC:
3900  requisition->width = 1;
3901 
3902  break;
3903  case EV_SIZING_FREE: {
3904  gint max_width;
3905  GtkBorder border;
3906 
3907  ev_view_get_max_page_size (view, &max_width, NULL);
3908  compute_border (view, &border);
3909  requisition->width = max_width + (view->spacing * 2) + border.left + border.right;
3910  }
3911  break;
3912  default:
3913  g_assert_not_reached ();
3914  }
3915 }
3916 
3917 static void
3919  GtkRequisition *requisition)
3920 {
3921  GtkBorder border;
3922  gint width, height;
3923 
3924  if (view->sizing_mode == EV_SIZING_FIT_PAGE) {
3925  requisition->width = 1;
3926  requisition->height = 1;
3927 
3928  return;
3929  }
3930 
3931  /* Find the largest of the two. */
3932  ev_view_get_page_size (view,
3933  view->current_page,
3934  &width, &height);
3935  if (view->current_page + 1 < ev_document_get_n_pages (view->document)) {
3936  gint width_2, height_2;
3937  ev_view_get_page_size (view,
3938  view->current_page + 1,
3939  &width_2, &height_2);
3940  if (width_2 > width) {
3941  width = width_2;
3942  height = height_2;
3943  }
3944  }
3945  compute_border (view, &border);
3946 
3947  requisition->width = view->sizing_mode == EV_SIZING_FIT_WIDTH ? 1 :
3948  ((width + border.left + border.right) * 2) + (view->spacing * 3);
3949  requisition->height = (height + border.top + border.bottom) + (view->spacing * 2);
3950 }
3951 
3952 static void
3954  GtkRequisition *requisition)
3955 {
3956  GtkBorder border;
3957  gint width, height;
3958 
3959  if (view->sizing_mode == EV_SIZING_FIT_PAGE) {
3960  requisition->width = 1;
3961  requisition->height = 1;
3962 
3963  return;
3964  }
3965 
3966  ev_view_get_page_size (view, view->current_page, &width, &height);
3967  compute_border (view, &border);
3968 
3969  requisition->width = view->sizing_mode == EV_SIZING_FIT_WIDTH ? 1 :
3970  width + border.left + border.right + (2 * view->spacing);
3971  requisition->height = height + border.top + border.bottom + (2 * view->spacing);
3972 }
3973 
3974 static void
3975 ev_view_size_request (GtkWidget *widget,
3976  GtkRequisition *requisition)
3977 {
3978  EvView *view = EV_VIEW (widget);
3979  gboolean dual_page;
3980 
3981  if (view->document == NULL) {
3982  view->requisition.width = 1;
3983  view->requisition.height = 1;
3984 
3985  *requisition = view->requisition;
3986 
3987  return;
3988  }
3989 
3990  /* Get zoom for size here when not called from
3991  * ev_view_size_allocate()
3992  */
3993  if (!view->internal_size_request &&
3994  (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
3995  view->sizing_mode == EV_SIZING_FIT_PAGE ||
3996  view->sizing_mode == EV_SIZING_AUTOMATIC)) {
3997  GtkAllocation allocation;
3998 
3999  gtk_widget_get_allocation (widget, &allocation);
4000  ev_view_zoom_for_size (view,
4001  allocation.width,
4002  allocation.height);
4003  }
4004 
4005  dual_page = is_dual_page (view, NULL);
4006  if (view->continuous && dual_page)
4008  else if (view->continuous)
4010  else if (dual_page)
4012  else
4014 
4015  *requisition = view->requisition;
4016 }
4017 
4018 static void
4019 ev_view_get_preferred_width (GtkWidget *widget,
4020  gint *minimum,
4021  gint *natural)
4022 {
4023  GtkRequisition requisition;
4024 
4025  ev_view_size_request (widget, &requisition);
4026 
4027  *minimum = *natural = requisition.width;
4028 }
4029 
4030 static void
4031 ev_view_get_preferred_height (GtkWidget *widget,
4032  gint *minimum,
4033  gint *natural)
4034 {
4035  GtkRequisition requisition;
4036 
4037  ev_view_size_request (widget, &requisition);
4038 
4039  *minimum = *natural = requisition.height;
4040 }
4041 
4042 static void
4043 ev_view_size_allocate (GtkWidget *widget,
4044  GtkAllocation *allocation)
4045 {
4046  EvView *view = EV_VIEW (widget);
4047  GList *l;
4048  gint root_x, root_y;
4049 
4050  gtk_widget_set_allocation (widget, allocation);
4051 
4052  if (gtk_widget_get_realized (widget))
4053  gdk_window_move_resize (gtk_widget_get_window (widget),
4054  allocation->x,
4055  allocation->y,
4056  allocation->width,
4057  allocation->height);
4058 
4059  if (!view->document)
4060  return;
4061 
4062  if (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
4063  view->sizing_mode == EV_SIZING_FIT_PAGE ||
4064  view->sizing_mode == EV_SIZING_AUTOMATIC) {
4065  GtkRequisition req;
4066 
4067  ev_view_zoom_for_size (view,
4068  allocation->width,
4069  allocation->height);
4070  view->internal_size_request = TRUE;
4071  ev_view_size_request (widget, &req);
4072  view->internal_size_request = FALSE;
4073  }
4074 
4075  ev_view_set_adjustment_values (view, GTK_ORIENTATION_HORIZONTAL);
4076  ev_view_set_adjustment_values (view, GTK_ORIENTATION_VERTICAL);
4077 
4078  if (view->document)
4080 
4082  view->pending_resize = FALSE;
4083  view->pending_point.x = 0;
4084  view->pending_point.y = 0;
4085 
4086  for (l = view->children; l && l->data; l = g_list_next (l)) {
4087  GdkRectangle view_area;
4088  EvViewChild *child = (EvViewChild *)l->data;
4089 
4090  if (!gtk_widget_get_visible (child->widget))
4091  continue;
4092 
4093  _ev_view_transform_doc_rect_to_view_rect (view, child->page, &child->doc_rect, &view_area);
4094  view_area.x -= view->scroll_x;
4095  view_area.y -= view->scroll_y;
4096 
4097  gtk_widget_set_size_request (child->widget, view_area.width, view_area.height);
4098  gtk_widget_size_allocate (child->widget, &view_area);
4099  }
4100 
4101  if (view->window_children)
4102  gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (view)),
4103  &root_x, &root_y);
4104 
4105  for (l = view->window_children; l && l->data; l = g_list_next (l)) {
4106  EvViewWindowChild *child;
4107  EvRectangle doc_rect;
4108  GdkRectangle view_rect;
4109 
4110  child = (EvViewWindowChild *)l->data;
4111 
4113  if (child->moved) {
4114  doc_rect.x1 = child->orig_x;
4115  doc_rect.y1 = child->orig_y;
4116  }
4117  _ev_view_transform_doc_rect_to_view_rect (view, child->page, &doc_rect, &view_rect);
4118  view_rect.x -= view->scroll_x;
4119  view_rect.y -= view->scroll_y;
4120 
4121  if (view_rect.x != child->orig_x || view_rect.y != child->orig_y) {
4122  child->parent_x = root_x;
4123  child->parent_y = root_y;
4124  ev_view_window_child_move (view, child, view_rect.x + root_x, view_rect.y + root_y);
4125  }
4126  }
4127 }
4128 
4129 static gboolean
4130 ev_view_scroll_event (GtkWidget *widget, GdkEventScroll *event)
4131 {
4132  EvView *view = EV_VIEW (widget);
4133  guint state;
4134  gboolean fit_width, fit_height;
4135 
4136  state = event->state & gtk_accelerator_get_default_mod_mask ();
4137 
4138  if (state == GDK_CONTROL_MASK) {
4140  view->zoom_center_x = event->x;
4141  view->zoom_center_y = event->y;
4142 
4143  switch (event->direction) {
4144  case GDK_SCROLL_DOWN:
4145  case GDK_SCROLL_RIGHT:
4146  if (ev_view_can_zoom_out (view))
4147  ev_view_zoom_out (view);
4148  break;
4149  case GDK_SCROLL_UP:
4150  case GDK_SCROLL_LEFT:
4151  if (ev_view_can_zoom_in (view))
4152  ev_view_zoom_in (view);
4153  break;
4154  case GDK_SCROLL_SMOOTH: {
4155  gdouble delta = event->delta_x + event->delta_y;
4156  gdouble factor = pow (delta < 0 ? ZOOM_IN_FACTOR : ZOOM_OUT_FACTOR, fabs (delta));
4157 
4158  if ((factor < 1.0 && ev_view_can_zoom_out (view)) ||
4159  (factor >= 1.0 && ev_view_can_zoom_in (view)))
4160  ev_view_zoom (view, factor);
4161  }
4162  break;
4163  }
4164 
4165  return TRUE;
4166  }
4167 
4168  view->jump_to_find_result = FALSE;
4169 
4170  /* Shift+Wheel scrolls the in the perpendicular direction */
4171  if (state & GDK_SHIFT_MASK) {
4172  if (event->direction == GDK_SCROLL_UP)
4173  event->direction = GDK_SCROLL_LEFT;
4174  else if (event->direction == GDK_SCROLL_LEFT)
4175  event->direction = GDK_SCROLL_UP;
4176  else if (event->direction == GDK_SCROLL_DOWN)
4177  event->direction = GDK_SCROLL_RIGHT;
4178  else if (event->direction == GDK_SCROLL_RIGHT)
4179  event->direction = GDK_SCROLL_DOWN;
4180  else if (event->direction == GDK_SCROLL_SMOOTH) {
4181  /* Swap the deltas for perpendicular direction */
4182  gdouble tmp_delta = event->delta_x;
4183 
4184  event->delta_x = event->delta_y;
4185  event->delta_y = tmp_delta;
4186  }
4187 
4188  event->state &= ~GDK_SHIFT_MASK;
4189  state &= ~GDK_SHIFT_MASK;
4190  }
4191 
4192  fit_width = ev_view_page_fits (view, GTK_ORIENTATION_HORIZONTAL);
4193  fit_height = ev_view_page_fits (view, GTK_ORIENTATION_VERTICAL);
4194  if (state == 0 && !view->continuous && (fit_width || fit_height)) {
4195  switch (event->direction) {
4196  case GDK_SCROLL_DOWN:
4197  if (fit_height) {
4198  ev_view_next_page (view);
4199  return TRUE;
4200  }
4201  break;
4202  case GDK_SCROLL_RIGHT:
4203  if (fit_width) {
4204  ev_view_next_page (view);
4205  return TRUE;
4206  }
4207  break;
4208  case GDK_SCROLL_UP:
4209  if (fit_height) {
4210  ev_view_previous_page (view);
4211  return TRUE;
4212  }
4213  break;
4214  case GDK_SCROLL_LEFT:
4215  if (fit_width) {
4216  ev_view_previous_page (view);
4217  return TRUE;
4218  }
4219  break;
4220  case GDK_SCROLL_SMOOTH: {
4221  gdouble decrement;
4222  if ((fit_width && fit_height) ||
4223  ((fit_height && event->delta_x == 0.0) ||
4224  (fit_width && event->delta_y == 0.0))) {
4225  /* Emulate normal scrolling by summing the deltas */
4226  view->total_delta += event->delta_x + event->delta_y;
4227 
4228  decrement = view->total_delta < 0 ? -1.0 : 1.0;
4229  for (; fabs (view->total_delta) >= 1.0; view->total_delta -= decrement) {
4230  if (decrement < 0)
4231  ev_view_previous_page (view);
4232  else
4233  ev_view_next_page (view);
4234  }
4235 
4236  return TRUE;
4237  }
4238  }
4239  break;
4240  }
4241 
4242  return FALSE;
4243  }
4244 
4245  return FALSE;
4246 }
4247 
4248 static EvViewSelection *
4250  gint page)
4251 {
4252  GList *list;
4253 
4254  for (list = view->selection_info.selections; list != NULL; list = list->next) {
4255  EvViewSelection *selection;
4256 
4257  selection = (EvViewSelection *) list->data;
4258 
4259  if (selection->page == page)
4260  return selection;
4261  }
4262 
4263  return NULL;
4264 }
4265 
4266 static void
4267 ev_view_realize (GtkWidget *widget)
4268 {
4269  GtkAllocation allocation;
4270  GdkWindow *window;
4271  GdkWindowAttr attributes;
4272  gint attributes_mask;
4273 
4274  gtk_widget_set_realized (widget, TRUE);
4275 
4276  gtk_widget_get_allocation (widget, &allocation);
4277 
4278  attributes.window_type = GDK_WINDOW_CHILD;
4279  attributes.x = allocation.x;
4280  attributes.y = allocation.y;
4281  attributes.width = allocation.width;
4282  attributes.height = allocation.height;
4283  attributes.wclass = GDK_INPUT_OUTPUT;
4284  attributes.visual = gtk_widget_get_visual (widget);
4285  attributes.event_mask = gtk_widget_get_events (widget);
4286 
4287  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
4288 
4289  window = gdk_window_new (gtk_widget_get_parent_window (widget),
4290  &attributes, attributes_mask);
4291  gtk_widget_set_window (widget, window);
4292  gdk_window_set_user_data (window, widget);
4293 
4294  gtk_style_context_set_background (gtk_widget_get_style_context (widget),
4295  window);
4296 }
4297 
4298 static void
4299 get_cursor_color (GtkStyleContext *context,
4300  GdkRGBA *color)
4301 {
4302  GdkColor *style_color;
4303 
4304  gtk_style_context_get_style (context,
4305  "cursor-color",
4306  &style_color,
4307  NULL);
4308 
4309  if (style_color) {
4310  color->red = style_color->red / 65535.0;
4311  color->green = style_color->green / 65535.0;
4312  color->blue = style_color->blue / 65535.0;
4313  color->alpha = 1;
4314 
4315  gdk_color_free (style_color);
4316  } else {
4317  gtk_style_context_save (context);
4318  gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, color);
4319  gtk_style_context_restore (context);
4320  }
4321 }
4322 
4323 /* This is based on the deprecated function gtk_draw_insertion_cursor. */
4324 static void
4326  cairo_t *cr)
4327 {
4328  GdkRectangle view_rect;
4329  GdkRGBA cursor_color;
4330 
4331  if (!get_caret_cursor_area (view, view->cursor_page, view->cursor_offset, &view_rect))
4332  return;
4333 
4334  get_cursor_color (gtk_widget_get_style_context (GTK_WIDGET (view)), &cursor_color);
4335 
4336  cairo_save (cr);
4337  gdk_cairo_set_source_rgba (cr, &cursor_color);
4338  cairo_rectangle (cr, view_rect.x, view_rect.y, view_rect.width, view_rect.height);
4339  cairo_fill (cr);
4340  cairo_restore (cr);
4341 }
4342 
4343 static gboolean
4345  gint page)
4346 {
4347  return (view->caret_enabled &&
4348  view->cursor_page == page &&
4349  view->cursor_visible &&
4350  gtk_widget_has_focus (GTK_WIDGET (view)) &&
4352 }
4353 
4354 static void
4356  cairo_t *cr,
4357  gint page,
4358  GdkRectangle *clip)
4359 {
4360  GtkWidget *widget = GTK_WIDGET (view);
4361  GdkRectangle rect;
4362  GdkRectangle intersect;
4363 
4364  if (view->focused_element_page != page)
4365  return;
4366 
4367  if (!gtk_widget_has_focus (GTK_WIDGET (view)))
4368  return;
4369 
4370  if (!ev_view_get_focused_area (view, &rect))
4371  return;
4372 
4373  if (gdk_rectangle_intersect (&rect, clip, &intersect)) {
4374  gtk_render_focus (gtk_widget_get_style_context (widget),
4375  cr,
4376  intersect.x,
4377  intersect.y,
4378  intersect.width,
4379  intersect.height);
4380  }
4381 }
4382 
4383 #ifdef EV_ENABLE_DEBUG
4384 static void
4385 stroke_view_rect (cairo_t *cr,
4386  GdkRectangle *clip,
4387  GdkRectangle *view_rect)
4388 {
4389  GdkRectangle intersect;
4390 
4391  if (gdk_rectangle_intersect (view_rect, clip, &intersect)) {
4392  cairo_rectangle (cr,
4393  intersect.x, intersect.y,
4394  intersect.width, intersect.height);
4395  cairo_stroke (cr);
4396  }
4397 }
4398 
4399 static void
4400 stroke_doc_rect (EvView *view,
4401  cairo_t *cr,
4402  gint page,
4403  GdkRectangle *clip,
4404  EvRectangle *doc_rect)
4405 {
4406  GdkRectangle view_rect;
4407 
4408  _ev_view_transform_doc_rect_to_view_rect (view, page, doc_rect, &view_rect);
4409  view_rect.x -= view->scroll_x;
4410  view_rect.y -= view->scroll_y;
4411  stroke_view_rect (cr, clip, &view_rect);
4412 }
4413 
4414 static void
4415 show_chars_border (EvView *view,
4416  cairo_t *cr,
4417  gint page,
4418  GdkRectangle *clip)
4419 {
4420  EvRectangle *areas = NULL;
4421  guint n_areas = 0;
4422  guint i;
4423 
4424  ev_page_cache_get_text_layout (view->page_cache, page, &areas, &n_areas);
4425  if (!areas)
4426  return;
4427 
4428  cairo_set_source_rgb (cr, 1., 0., 0.);
4429 
4430  for (i = 0; i < n_areas; i++) {
4431  EvRectangle *doc_rect = areas + i;
4432 
4433  stroke_doc_rect (view, cr, page, clip, doc_rect);
4434  }
4435 }
4436 
4437 static void
4438 show_mapping_list_border (EvView *view,
4439  cairo_t *cr,
4440  gint page,
4441  GdkRectangle *clip,
4442  EvMappingList *mapping_list)
4443 {
4444  GList *l;
4445 
4446  for (l = ev_mapping_list_get_list (mapping_list); l; l = g_list_next (l)) {
4447  EvMapping *mapping = (EvMapping *)l->data;
4448 
4449  stroke_doc_rect (view, cr, page, clip, &mapping->area);
4450  }
4451 }
4452 
4453 static void
4454 show_links_border (EvView *view,
4455  cairo_t *cr,
4456  gint page,
4457  GdkRectangle *clip)
4458 {
4459  cairo_set_source_rgb (cr, 0., 0., 1.);
4460  show_mapping_list_border (view,cr, page, clip,
4462 }
4463 
4464 static void
4465 show_forms_border (EvView *view,
4466  cairo_t *cr,
4467  gint page,
4468  GdkRectangle *clip)
4469 {
4470  cairo_set_source_rgb (cr, 0., 1., 0.);
4471  show_mapping_list_border (view, cr, page, clip,
4473 }
4474 
4475 static void
4476 show_annots_border (EvView *view,
4477  cairo_t *cr,
4478  gint page,
4479  GdkRectangle *clip)
4480 {
4481  cairo_set_source_rgb (cr, 0., 1., 1.);
4482  show_mapping_list_border (view, cr, page, clip,
4484 }
4485 
4486 static void
4487 show_images_border (EvView *view,
4488  cairo_t *cr,
4489  gint page,
4490  GdkRectangle *clip)
4491 {
4492  cairo_set_source_rgb (cr, 1., 0., 1.);
4493  show_mapping_list_border (view, cr, page, clip,
4495 }
4496 
4497 static void
4498 show_media_border (EvView *view,
4499  cairo_t *cr,
4500  gint page,
4501  GdkRectangle *clip)
4502 {
4503  cairo_set_source_rgb (cr, 1., 1., 0.);
4504  show_mapping_list_border (view, cr, page, clip,
4506 }
4507 
4508 
4509 static void
4510 show_selections_border (EvView *view,
4511  cairo_t *cr,
4512  gint page,
4513  GdkRectangle *clip)
4514 {
4515  cairo_region_t *region;
4516  guint i, n_rects;
4517  GdkRectangle page_area;
4518  GtkBorder border;
4519 
4520  region = ev_page_cache_get_text_mapping (view->page_cache, page);
4521  if (!region)
4522  return;
4523 
4524  cairo_set_source_rgb (cr, 0.75, 0.50, 0.25);
4525 
4526  ev_view_get_page_extents (view, page, &page_area, &border);
4527 
4528  region = cairo_region_copy (region);
4529  cairo_region_intersect_rectangle (region, clip);
4530  n_rects = cairo_region_num_rectangles (region);
4531  for (i = 0; i < n_rects; i++) {
4532  GdkRectangle view_rect;
4533 
4534  cairo_region_get_rectangle (region, i, &view_rect);
4535  view_rect.x = (gint)(view_rect.x * view->scale + 0.5);
4536  view_rect.y = (gint)(view_rect.y * view->scale + 0.5);
4537  view_rect.width = (gint)(view_rect.width * view->scale + 0.5);
4538  view_rect.height = (gint)(view_rect.height * view->scale + 0.5);
4539 
4540  view_rect.x += page_area.x + border.left - view->scroll_x;
4541  view_rect.y += page_area.y + border.right - view->scroll_y;
4542  stroke_view_rect (cr, clip, &view_rect);
4543  }
4544  cairo_region_destroy (region);
4545 }
4546 
4547 static void
4548 draw_debug_borders (EvView *view,
4549  cairo_t *cr,
4550  gint page,
4551  GdkRectangle *clip)
4552 {
4553  EvDebugBorders borders = ev_debug_get_debug_borders();
4554 
4555  cairo_save (cr);
4556  cairo_set_line_width (cr, 0.5);
4557 
4558  if (borders & EV_DEBUG_BORDER_CHARS)
4559  show_chars_border (view, cr, page, clip);
4560  if (borders & EV_DEBUG_BORDER_LINKS)
4561  show_links_border (view, cr, page, clip);
4562  if (borders & EV_DEBUG_BORDER_FORMS)
4563  show_forms_border (view, cr, page, clip);
4564  if (borders & EV_DEBUG_BORDER_ANNOTS)
4565  show_annots_border (view, cr, page, clip);
4566  if (borders & EV_DEBUG_BORDER_IMAGES)
4567  show_images_border (view, cr, page, clip);
4568  if (borders & EV_DEBUG_BORDER_MEDIA)
4569  show_media_border (view, cr, page, clip);
4570  if (borders & EV_DEBUG_BORDER_SELECTIONS)
4571  show_selections_border (view, cr, page, clip);
4572 
4573  cairo_restore (cr);
4574 }
4575 #endif
4576 
4577 static gboolean
4578 ev_view_draw (GtkWidget *widget,
4579  cairo_t *cr)
4580 {
4581  EvView *view = EV_VIEW (widget);
4582  gint i;
4583  GdkRectangle clip_rect;
4584 
4585  gtk_render_background (gtk_widget_get_style_context (widget),
4586  cr,
4587  0, 0,
4588  gtk_widget_get_allocated_width (widget),
4589  gtk_widget_get_allocated_height (widget));
4590 
4591  if (view->document == NULL)
4592  return FALSE;
4593 
4594  if (!gdk_cairo_get_clip_rectangle (cr, &clip_rect))
4595  return FALSE;
4596 
4597  for (i = view->start_page; i >= 0 && i <= view->end_page; i++) {
4598  GdkRectangle page_area;
4599  GtkBorder border;
4600  gboolean page_ready = TRUE;
4601 
4602  if (!ev_view_get_page_extents (view, i, &page_area, &border))
4603  continue;
4604 
4605  page_area.x -= view->scroll_x;
4606  page_area.y -= view->scroll_y;
4607 
4608  draw_one_page (view, i, cr, &page_area, &border, &clip_rect, &page_ready);
4609 
4610  if (page_ready && should_draw_caret_cursor (view, i))
4611  draw_caret_cursor (view, cr);
4612  if (page_ready && view->find_pages && view->highlight_find_results)
4613  highlight_find_results (view, cr, i);
4614  if (page_ready && EV_IS_DOCUMENT_ANNOTATIONS (view->document))
4615  show_annotation_windows (view, i);
4616  if (page_ready && view->focused_element)
4617  draw_focus (view, cr, i, &clip_rect);
4618  if (page_ready && view->synctex_result)
4619  highlight_forward_search_results (view, cr, i);
4620 #ifdef EV_ENABLE_DEBUG
4621  if (page_ready)
4622  draw_debug_borders (view, cr, i, &clip_rect);
4623 #endif
4624  }
4625 
4626  if (GTK_WIDGET_CLASS (ev_view_parent_class)->draw)
4627  GTK_WIDGET_CLASS (ev_view_parent_class)->draw (widget, cr);
4628 
4629  return FALSE;
4630 }
4631 
4632 static void
4634  gdouble x,
4635  gdouble y)
4636 {
4637  EvMapping *mapping;
4638  EvFormField *field;
4639  gint page;
4640 
4641  mapping = get_annotation_mapping_at_location (view, x, y, &page);
4642  if (mapping) {
4643  _ev_view_set_focused_element (view, mapping, page);
4644  return;
4645  }
4646 
4647  mapping = get_link_mapping_at_location (view, x, y, &page);
4648  if (mapping) {
4649  _ev_view_set_focused_element (view, mapping, page);
4650  return;
4651  }
4652 
4653  if ((field = ev_view_get_form_field_at_location (view, x, y))) {
4655  _ev_view_focus_form_field (view, field);
4656  return;
4657  }
4658 
4659  _ev_view_set_focused_element (view, NULL, -1);
4660 }
4661 
4662 static gboolean
4664  gdouble x,
4665  gdouble y)
4666 {
4667  GList *items = NULL;
4668  EvLink *link;
4669  EvImage *image;
4670  EvAnnotation *annot;
4671 
4672  image = ev_view_get_image_at_location (view, x, y);
4673  if (image)
4674  items = g_list_prepend (items, image);
4675 
4676  link = ev_view_get_link_at_location (view, x, y);
4677  if (link)
4678  items = g_list_prepend (items, link);
4679 
4680  annot = ev_view_get_annotation_at_location (view, x, y);
4681  if (annot)
4682  items = g_list_prepend (items, annot);
4683 
4684  g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, items);
4685 
4686  g_list_free (items);
4687 
4688  return TRUE;
4689 }
4690 
4691 static gboolean
4692 ev_view_popup_menu (GtkWidget *widget)
4693 {
4694  gint x, y;
4695 
4696  ev_document_misc_get_pointer_position (widget, &x, &y);
4697  return ev_view_do_popup_menu (EV_VIEW (widget), x, y);
4698 }
4699 
4700 static void
4702  gint x,
4703  gint y,
4704  EvLink *link,
4705  GdkRectangle *area)
4706 {
4707  EvMappingList *link_mapping;
4708  gint page;
4709  gint x_offset = 0, y_offset = 0;
4710 
4711  x += view->scroll_x;
4712  y += view->scroll_y;
4713 
4714  find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
4715 
4716  link_mapping = ev_page_cache_get_link_mapping (view->page_cache, page);
4717  ev_view_get_area_from_mapping (view, page,
4718  link_mapping,
4719  link, area);
4720 }
4721 
4722 static void
4724  gint x,
4725  gint y,
4726  EvAnnotation *annot,
4727  GdkRectangle *area)
4728 {
4729  EvMappingList *annot_mapping;
4730  gint page;
4731  gint x_offset = 0, y_offset = 0;
4732 
4733  x += view->scroll_x;
4734  y += view->scroll_y;
4735 
4736  find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
4737 
4738  annot_mapping = ev_page_cache_get_annot_mapping (view->page_cache, page);
4739  ev_view_get_area_from_mapping (view, page,
4740  annot_mapping,
4741  annot, area);
4742 }
4743 
4744 static gboolean
4745 ev_view_query_tooltip (GtkWidget *widget,
4746  gint x,
4747  gint y,
4748  gboolean keyboard_tip,
4749  GtkTooltip *tooltip)
4750 {
4751  EvView *view = EV_VIEW (widget);
4752  EvLink *link;
4753  EvAnnotation *annot;
4754  gchar *text;
4755 
4756  annot = ev_view_get_annotation_at_location (view, x, y);
4757  if (annot) {
4758  const gchar *contents;
4759 
4760  if ((contents = ev_annotation_get_contents (annot))) {
4761  GdkRectangle annot_area;
4762 
4763  get_annot_area (view, x, y, annot, &annot_area);
4764  gtk_tooltip_set_text (tooltip, contents);
4765  gtk_tooltip_set_tip_area (tooltip, &annot_area);
4766 
4767  return TRUE;
4768  }
4769  }
4770 
4771  link = ev_view_get_link_at_location (view, x, y);
4772  if (!link)
4773  return FALSE;
4774 
4775  text = tip_from_link (view, link);
4776  if (text && g_utf8_validate (text, -1, NULL)) {
4777  GdkRectangle link_area;
4778 
4779  get_link_area (view, x, y, link, &link_area);
4780  gtk_tooltip_set_text (tooltip, text);
4781  gtk_tooltip_set_tip_area (tooltip, &link_area);
4782  g_free (text);
4783 
4784  return TRUE;
4785  }
4786  g_free (text);
4787 
4788  return FALSE;
4789 }
4790 
4791 static void
4793  GdkEventButton *event)
4794 {
4795  clear_selection (view);
4796 
4797  view->selection_info.start.x = event->x + view->scroll_x;
4798  view->selection_info.start.y = event->y + view->scroll_y;
4799 
4800  switch (event->type) {
4801  case GDK_2BUTTON_PRESS:
4803  break;
4804  case GDK_3BUTTON_PRESS:
4806  break;
4807  default:
4809  return;
4810  }
4811 
4812  /* In case of WORD or LINE, compute selections now */
4813  compute_selections (view,
4814  view->selection_info.style,
4815  &(view->selection_info.start),
4816  &(view->selection_info.start));
4817 }
4818 
4819 gint
4821  gint page,
4822  gdouble doc_x,
4823  gdouble doc_y)
4824 {
4825  EvRectangle *areas = NULL;
4826  guint n_areas = 0;
4827  gint offset = -1;
4828  gint first_line_offset;
4829  gint last_line_offset = -1;
4830  EvRectangle *rect;
4831  guint i;
4832 
4833  ev_page_cache_get_text_layout (view->page_cache, page, &areas, &n_areas);
4834  if (!areas)
4835  return -1;
4836 
4837  i = 0;
4838  while (i < n_areas && offset == -1) {
4839  rect = areas + i;
4840 
4841  first_line_offset = -1;
4842  while (doc_y >= rect->y1 && doc_y <= rect->y2) {
4843  if (first_line_offset == -1) {
4844  if (doc_x <= rect->x1) {
4845  /* Location is before the start of the line */
4846  if (last_line_offset != -1) {
4847  EvRectangle *last = areas + last_line_offset;
4848  gint dx1, dx2;
4849 
4850  /* If there's a previous line, check distances */
4851 
4852  dx1 = doc_x - last->x2;
4853  dx2 = rect->x1 - doc_x;
4854 
4855  if (dx1 < dx2)
4856  offset = last_line_offset;
4857  else
4858  offset = i;
4859  } else {
4860  offset = i;
4861  }
4862 
4863  last_line_offset = i + 1;
4864  break;
4865  }
4866  first_line_offset = i;
4867  }
4868  last_line_offset = i + 1;
4869 
4870  if (doc_x >= rect->x1 && doc_x <= rect->x2) {
4871  /* Location is inside the line. Position the caret before
4872  * or after the character, depending on whether the point
4873  * falls within the left or right half of the bounding box.
4874  */
4875  if (doc_x <= rect->x1 + (rect->x2 - rect->x1) / 2)
4876  offset = i;
4877  else
4878  offset = i + 1;
4879  break;
4880  }
4881 
4882  i++;
4883  rect = areas + i;
4884  }
4885 
4886  if (first_line_offset == -1)
4887  i++;
4888  }
4889 
4890  if (last_line_offset == -1)
4891  return -1;
4892 
4893  if (offset == -1)
4894  offset = last_line_offset;
4895 
4896  return offset;
4897 }
4898 
4899 static gboolean
4901  gint page,
4902  gdouble doc_x,
4903  gdouble doc_y)
4904 {
4905  gint offset;
4906 
4907  offset = _ev_view_get_caret_cursor_offset_at_doc_point (view, page, doc_x, doc_y);
4908  if (offset == -1)
4909  return FALSE;
4910 
4911  if (view->cursor_offset != offset || view->cursor_page != page) {
4912  view->cursor_offset = offset;
4913  view->cursor_page = page;
4914 
4915  return TRUE;
4916  }
4917 
4918  return FALSE;
4919 }
4920 
4921 static gboolean
4923  gdouble x,
4924  gdouble y)
4925 {
4926  gint page;
4927  gint doc_x, doc_y;
4928 
4929  if (!view->caret_enabled || view->rotation != 0)
4930  return FALSE;
4931 
4932  if (!view->page_cache)
4933  return FALSE;
4934 
4935  /* Get the offset from the doc point */
4936  if (!get_doc_point_from_location (view, x, y, &page, &doc_x, &doc_y))
4937  return FALSE;
4938 
4939  return position_caret_cursor_at_doc_point (view, page, doc_x, doc_y);
4940 }
4941 
4942 static gboolean
4944  GdkEventButton *event,
4945  gboolean redraw)
4946 {
4947  GdkRectangle area;
4948  GdkRectangle prev_area = { 0, 0, 0, 0 };
4949 
4950  if (redraw)
4951  get_caret_cursor_area (view, view->cursor_page, view->cursor_offset, &prev_area);
4952 
4953  if (!position_caret_cursor_at_location (view, event->x, event->y))
4954  return FALSE;
4955 
4956  if (!get_caret_cursor_area (view, view->cursor_page, view->cursor_offset, &area))
4957  return FALSE;
4958 
4959  view->cursor_line_offset = area.x;
4960 
4961  g_signal_emit (view, signals[SIGNAL_CURSOR_MOVED], 0, view->cursor_page, view->cursor_offset);
4962 
4963  if (redraw) {
4964  cairo_region_t *damage_region;
4965 
4966  damage_region = cairo_region_create_rectangle (&prev_area);
4967  cairo_region_union_rectangle (damage_region, &area);
4968  gdk_window_invalidate_region (gtk_widget_get_window (GTK_WIDGET (view)),
4969  damage_region, TRUE);
4970  cairo_region_destroy (damage_region);
4971  }
4972 
4973  return TRUE;
4974 }
4975 
4976 static gboolean
4977 ev_view_button_press_event (GtkWidget *widget,
4978  GdkEventButton *event)
4979 {
4980  EvView *view = EV_VIEW (widget);
4981 
4982  if (!view->document || ev_document_get_n_pages (view->document) <= 0)
4983  return FALSE;
4984 
4985  if (gtk_gesture_is_recognized (view->zoom_gesture))
4986  return TRUE;
4987 
4988  if (!gtk_widget_has_focus (widget)) {
4989  gtk_widget_grab_focus (widget);
4990  }
4991 
4992  if (view->window_child_focus) {
4994 
4997  view->window_child_focus = NULL;
4998  }
4999 
5000  view->pressed_button = event->button;
5001  view->selection_info.in_drag = FALSE;
5002 
5003  if (view->scroll_info.autoscrolling)
5004  return TRUE;
5005 
5006  if (view->adding_annot_info.adding_annot && !view->adding_annot_info.annot) {
5007  if (event->button != 1)
5008  return TRUE;
5009 
5010  view->adding_annot_info.start.x = event->x + view->scroll_x;
5011  view->adding_annot_info.start.y = event->y + view->scroll_y;
5014 
5015  return TRUE;
5016  }
5017 
5018  switch (event->button) {
5019  case 1: {
5020  EvImage *image;
5021  EvAnnotation *annot;
5022  EvFormField *field;
5023  EvMapping *link;
5024  EvMedia *media;
5025  gint page;
5026 
5027  if (event->state & GDK_CONTROL_MASK)
5028  return ev_view_synctex_backward_search (view, event->x , event->y);
5029 
5030  if (EV_IS_SELECTION (view->document) && view->selection_info.selections) {
5031  if (event->type == GDK_3BUTTON_PRESS) {
5032  start_selection_for_event (view, event);
5033  } else if (event->state & GDK_SHIFT_MASK) {
5034  GdkPoint end_point;
5035 
5036  end_point.x = event->x + view->scroll_x;
5037  end_point.y = event->y + view->scroll_y;
5038  extend_selection (view, &view->selection_info.start, &end_point);
5039  } else if (location_in_selected_text (view,
5040  event->x + view->scroll_x,
5041  event->y + view->scroll_y)) {
5042  view->selection_info.in_drag = TRUE;
5043  } else {
5044  start_selection_for_event (view, event);
5045  if (position_caret_cursor_for_event (view, event, TRUE)) {
5046  view->cursor_blink_time = 0;
5048  }
5049  }
5050  } else if ((media = ev_view_get_media_at_location (view, event->x, event->y))) {
5051  ev_view_handle_media (view, media);
5052  } else if ((annot = ev_view_get_annotation_at_location (view, event->x, event->y))) {
5053  if (EV_IS_ANNOTATION_TEXT (annot)) {
5054  EvRectangle current_area;
5055  GdkPoint view_point;
5056  EvPoint doc_point;
5057  GdkRectangle page_area;
5058  GtkBorder border;
5059  guint annot_page;
5060 
5061  /* annot_clicked remembers that we clicked
5062  * on an annotation. We need moving_annot
5063  * to distinguish moving an annotation from
5064  * showing its popup upon button release. */
5067  view->moving_annot_info.annot = annot;
5068  ev_annotation_get_area (annot, &current_area);
5069 
5070  view_point.x = event->x + view->scroll_x;
5071  view_point.y = event->y + view->scroll_y;
5072 
5073  /* Remember the coordinates of the button press event
5074  * in order to implement a minimum threshold for moving
5075  * annotations. */
5076  view->moving_annot_info.start = view_point;
5077  annot_page = ev_annotation_get_page_index (annot);
5078  ev_view_get_page_extents (view, annot_page, &page_area, &border);
5079  _ev_view_transform_view_point_to_doc_point (view, &view_point,
5080  &page_area, &border,
5081  &doc_point.x, &doc_point.y);
5082 
5083  /* Remember the offset of the cursor with respect to
5084  * the annotation area in order to prevent the annotation from
5085  * jumping under the cursor while moving it. */
5086  view->moving_annot_info.cursor_offset.x = doc_point.x - current_area.x1;
5087  view->moving_annot_info.cursor_offset.y = doc_point.y - current_area.y1;
5088  }
5089  } else if ((field = ev_view_get_form_field_at_location (view, event->x, event->y))) {
5091  ev_view_handle_form_field (view, field);
5092  } else if ((link = get_link_mapping_at_location (view, event->x, event->y, &page))){
5093  _ev_view_set_focused_element (view, link, page);
5094  } else if (!location_in_text (view, event->x + view->scroll_x, event->y + view->scroll_y) &&
5095  (image = ev_view_get_image_at_location (view, event->x, event->y))) {
5096  if (view->image_dnd_info.image)
5097  g_object_unref (view->image_dnd_info.image);
5098  view->image_dnd_info.image = g_object_ref (image);
5099  view->image_dnd_info.in_drag = TRUE;
5100 
5101  view->image_dnd_info.start.x = event->x + view->scroll_x;
5102  view->image_dnd_info.start.y = event->y + view->scroll_y;
5103  } else {
5105  _ev_view_set_focused_element (view, NULL, -1);
5106 
5107  if (view->synctex_result) {
5108  g_free (view->synctex_result);
5109  view->synctex_result = NULL;
5110  gtk_widget_queue_draw (widget);
5111  }
5112 
5113  if (EV_IS_SELECTION (view->document))
5114  start_selection_for_event (view, event);
5115 
5116  if (position_caret_cursor_for_event (view, event, TRUE)) {
5117  view->cursor_blink_time = 0;
5119  }
5120  }
5121  }
5122  return TRUE;
5123  case 2:
5124  /* use root coordinates as reference point because
5125  * scrolling changes window relative coordinates */
5126  view->drag_info.start.x = event->x_root;
5127  view->drag_info.start.y = event->y_root;
5128  view->drag_info.hadj = gtk_adjustment_get_value (view->hadjustment);
5129  view->drag_info.vadj = gtk_adjustment_get_value (view->vadjustment);
5130 
5132  ev_view_set_focused_element_at_location (view, event->x, event->y);
5133  return TRUE;
5134  case 3:
5135  view->scroll_info.start_y = event->y;
5136  ev_view_set_focused_element_at_location (view, event->x, event->y);
5137  return ev_view_do_popup_menu (view, event->x, event->y);
5138  }
5139 
5140  return FALSE;
5141 }
5142 
5143 static void
5145 {
5146  gtk_container_foreach (GTK_CONTAINER (view), (GtkCallback) gtk_widget_destroy, NULL);
5147 }
5148 
5149 static void
5150 destroy_child_if_form_widget (GtkWidget *widget)
5151 {
5152  if (g_object_get_data (G_OBJECT (widget), "form-field"))
5153  gtk_widget_destroy (widget);
5154 }
5155 
5156 static void
5158 {
5159  gtk_container_foreach (GTK_CONTAINER (view), (GtkCallback)destroy_child_if_form_widget, NULL);
5160 }
5161 
5162 /*** Drag and Drop ***/
5163 static void
5164 ev_view_drag_data_get (GtkWidget *widget,
5165  GdkDragContext *context,
5166  GtkSelectionData *selection_data,
5167  guint info,
5168  guint time)
5169 {
5170  EvView *view = EV_VIEW (widget);
5171 
5172  switch (info) {
5173  case TARGET_DND_TEXT:
5174  if (EV_IS_SELECTION (view->document) &&
5175  view->selection_info.selections) {
5176  gchar *text;
5177 
5178  text = get_selected_text (view);
5179  gtk_selection_data_set_text (selection_data,
5180  text,
5181  strlen (text));
5182  g_free (text);
5183  }
5184  break;
5185  case TARGET_DND_IMAGE:
5186  if (view->image_dnd_info.image) {
5187  GdkPixbuf *pixbuf;
5188 
5191  view->image_dnd_info.image);
5193 
5194  gtk_selection_data_set_pixbuf (selection_data, pixbuf);
5195  g_object_unref (pixbuf);
5196  }
5197  break;
5198  case TARGET_DND_URI:
5199  if (view->image_dnd_info.image) {
5200  GdkPixbuf *pixbuf;
5201  const gchar *tmp_uri;
5202  gchar *uris[2];
5203 
5206  view->image_dnd_info.image);
5208 
5209  tmp_uri = ev_image_save_tmp (view->image_dnd_info.image, pixbuf);
5210  g_object_unref (pixbuf);
5211 
5212  uris[0] = (gchar *)tmp_uri;
5213  uris[1] = NULL;
5214  gtk_selection_data_set_uris (selection_data, uris);
5215  }
5216  }
5217 }
5218 
5219 static gboolean
5220 ev_view_drag_motion (GtkWidget *widget,
5221  GdkDragContext *context,
5222  gint x,
5223  gint y,
5224  guint time)
5225 {
5226  if (gtk_drag_get_source_widget (context) == widget)
5227  gdk_drag_status (context, 0, time);
5228  else
5229  gdk_drag_status (context, gdk_drag_context_get_suggested_action (context), time);
5230 
5231  return TRUE;
5232 }
5233 
5234 static gboolean
5236 {
5237  compute_selections (view,
5238  view->selection_info.style,
5239  &view->selection_info.start,
5240  &view->motion);
5241  view->selection_update_id = 0;
5242  return FALSE;
5243 }
5244 
5245 static gboolean
5247 {
5248  gint x, y, shift = 0;
5249  GtkWidget *widget = GTK_WIDGET (view);
5250  GtkAllocation allocation;
5251 
5252  gtk_widget_get_allocation (widget, &allocation);
5253  ev_document_misc_get_pointer_position (widget, &x, &y);
5254 
5255  if (y > allocation.height) {
5256  shift = (y - allocation.height) / 2;
5257  } else if (y < 0) {
5258  shift = y / 2;
5259  }
5260 
5261  if (shift)
5262  gtk_adjustment_set_value (view->vadjustment,
5263  CLAMP (gtk_adjustment_get_value (view->vadjustment) + shift,
5264  gtk_adjustment_get_lower (view->vadjustment),
5265  gtk_adjustment_get_upper (view->vadjustment) -
5266  gtk_adjustment_get_page_size (view->vadjustment)));
5267 
5268  if (x > allocation.width) {
5269  shift = (x - allocation.width) / 2;
5270  } else if (x < 0) {
5271  shift = x / 2;
5272  }
5273 
5274  if (shift)
5275  gtk_adjustment_set_value (view->hadjustment,
5276  CLAMP (gtk_adjustment_get_value (view->hadjustment) + shift,
5277  gtk_adjustment_get_lower (view->hadjustment),
5278  gtk_adjustment_get_upper (view->hadjustment) -
5279  gtk_adjustment_get_page_size (view->hadjustment)));
5280 
5281  return TRUE;
5282 }
5283 
5284 static gboolean
5286 {
5287  int i;
5288  if (!view->drag_info.in_drag)
5289  return FALSE;
5290 
5291  for (i = DRAG_HISTORY - 1; i > 0; i--) {
5292  view->drag_info.buffer[i].x = view->drag_info.buffer[i-1].x;
5293  view->drag_info.buffer[i].y = view->drag_info.buffer[i-1].y;
5294  }
5295 
5296  /* Momentum is a moving average of 10ms granularity over
5297  * the last 100ms with each 10ms stored in buffer.
5298  */
5299 
5300  view->drag_info.momentum.x = (view->drag_info.buffer[DRAG_HISTORY - 1].x - view->drag_info.buffer[0].x);
5301  view->drag_info.momentum.y = (view->drag_info.buffer[DRAG_HISTORY - 1].y - view->drag_info.buffer[0].y);
5302 
5303  return TRUE;
5304 }
5305 
5306 static gboolean
5308 {
5309  gdouble dhadj_value, dvadj_value;
5310  gdouble oldhadjustment, oldvadjustment;
5311  gdouble h_page_size, v_page_size;
5312  gdouble h_upper, v_upper;
5313  GtkAllocation allocation;
5314 
5315  view->drag_info.momentum.x /= 1.2;
5316  view->drag_info.momentum.y /= 1.2; /* Alter these constants to change "friction" */
5317 
5318  gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
5319 
5320  h_page_size = gtk_adjustment_get_page_size (view->hadjustment);
5321  v_page_size = gtk_adjustment_get_page_size (view->vadjustment);
5322 
5323  dhadj_value = h_page_size *
5324  (gdouble)view->drag_info.momentum.x / allocation.width;
5325  dvadj_value = v_page_size *
5326  (gdouble)view->drag_info.momentum.y / allocation.height;
5327 
5328  oldhadjustment = gtk_adjustment_get_value (view->hadjustment);
5329  oldvadjustment = gtk_adjustment_get_value (view->vadjustment);
5330 
5331  h_upper = gtk_adjustment_get_upper (view->hadjustment);
5332  v_upper = gtk_adjustment_get_upper (view->vadjustment);
5333 
5334  /* When we reach the edges, we need either to absorb some momentum and bounce by
5335  * multiplying it on -0.5 or stop scrolling by setting momentum to 0. */
5336  if (((oldhadjustment + dhadj_value) > (h_upper - h_page_size)) ||
5337  ((oldhadjustment + dhadj_value) < 0))
5338  view->drag_info.momentum.x = 0;
5339  if (((oldvadjustment + dvadj_value) > (v_upper - v_page_size)) ||
5340  ((oldvadjustment + dvadj_value) < 0))
5341  view->drag_info.momentum.y = 0;
5342 
5343  gtk_adjustment_set_value (view->hadjustment,
5344  MIN (oldhadjustment + dhadj_value,
5345  h_upper - h_page_size));
5346  gtk_adjustment_set_value (view->vadjustment,
5347  MIN (oldvadjustment + dvadj_value,
5348  v_upper - v_page_size));
5349 
5350  if (((view->drag_info.momentum.x < 1) && (view->drag_info.momentum.x > -1)) &&
5351  ((view->drag_info.momentum.y < 1) && (view->drag_info.momentum.y > -1)))
5352  return FALSE;
5353  else
5354  return TRUE;
5355 }
5356 
5357 static gboolean
5358 ev_view_motion_notify_event (GtkWidget *widget,
5359  GdkEventMotion *event)
5360 {
5361  EvView *view = EV_VIEW (widget);
5362  GdkWindow *window;
5363  gint x, y;
5364 
5365  if (!view->document)
5366  return FALSE;
5367 
5368  if (gtk_gesture_is_recognized (view->zoom_gesture))
5369  return TRUE;
5370 
5371  window = gtk_widget_get_window (widget);
5372 
5373  if (event->is_hint || event->window != window) {
5374  ev_document_misc_get_pointer_position (widget, &x, &y);
5375  } else {
5376  x = event->x;
5377  y = event->y;
5378  }
5379 
5380  if (view->scroll_info.autoscrolling) {
5381  if (y >= 0)
5382  view->scroll_info.last_y = y;
5383  return TRUE;
5384  }
5385 
5386  if (view->selection_info.in_drag) {
5387  if (gtk_drag_check_threshold (widget,
5388  view->selection_info.start.x,
5389  view->selection_info.start.y,
5390  x, y)) {
5391  GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
5392 
5393  gtk_target_list_add_text_targets (target_list, TARGET_DND_TEXT);
5394 
5395  gtk_drag_begin (widget, target_list,
5396  GDK_ACTION_COPY,
5397  1, (GdkEvent *)event);
5398 
5399  view->selection_info.in_drag = FALSE;
5400 
5401  gtk_target_list_unref (target_list);
5402 
5403  return TRUE;
5404  }
5405  } else if (view->image_dnd_info.in_drag) {
5406  if (gtk_drag_check_threshold (widget,
5407  view->selection_info.start.x,
5408  view->selection_info.start.y,
5409  x, y)) {
5410  GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
5411 
5412  gtk_target_list_add_uri_targets (target_list, TARGET_DND_URI);
5413  gtk_target_list_add_image_targets (target_list, TARGET_DND_IMAGE, TRUE);
5414 
5415  gtk_drag_begin (widget, target_list,
5416  GDK_ACTION_COPY,
5417  1, (GdkEvent *)event);
5418 
5419  view->image_dnd_info.in_drag = FALSE;
5420 
5421  gtk_target_list_unref (target_list);
5422 
5423  return TRUE;
5424  }
5425  }
5426 
5427  switch (view->pressed_button) {
5428  case 1:
5429  /* For the Evince 0.4.x release, we limit selection to un-rotated
5430  * documents only.
5431  */
5432  if (view->rotation != 0)
5433  return FALSE;
5434 
5435  if (view->adding_annot_info.adding_annot) {
5436  EvRectangle rect;
5437  EvRectangle current_area;
5438  EvPoint start;
5439  EvPoint end;
5440  GdkRectangle page_area;
5441  GtkBorder border;
5442  guint annot_page;
5443 
5444  if (!view->adding_annot_info.annot)
5445  return TRUE;
5446 
5447  ev_annotation_get_area (view->adding_annot_info.annot, &current_area);
5448 
5449  view->adding_annot_info.stop.x = event->x + view->scroll_x;
5450  view->adding_annot_info.stop.y = event->y + view->scroll_y;
5452  ev_view_get_page_extents (view, annot_page, &page_area, &border);
5453  _ev_view_transform_view_point_to_doc_point (view, &view->adding_annot_info.start, &page_area, &border,
5454  &start.x, &start.y);
5455  _ev_view_transform_view_point_to_doc_point (view, &view->adding_annot_info.stop, &page_area, &border,
5456  &end.x, &end.y);
5457 
5458  switch (view->adding_annot_info.type) {
5460  rect.x1 = end.x;
5461  rect.y1 = end.y;
5462  rect.x2 = rect.x1 + current_area.x2 - current_area.x1;
5463  rect.y2 = rect.y1 + current_area.y2 - current_area.y1;
5464  break;
5466  rect.x1 = start.x;
5467  rect.y1 = start.y;
5468  rect.x2 = end.x;
5469  rect.y2 = end.y;
5470  break;
5471  default:
5472  g_assert_not_reached ();
5473  }
5474 
5475  /* Take the mutex before set_area, because the notify signal
5476  * updates the mappings in the backend */
5478  if (ev_annotation_set_area (view->adding_annot_info.annot, &rect)) {
5480  view->adding_annot_info.annot,
5482  }
5484 
5485 
5486  /* FIXME: reload only annotation area */
5487  ev_view_reload_page (view, annot_page, NULL);
5488  } else if (view->moving_annot_info.annot_clicked) {
5489  EvRectangle rect;
5490  EvRectangle current_area;
5491  GdkPoint view_point;
5492  EvPoint doc_point;
5493  GdkRectangle page_area;
5494  GtkBorder border;
5495  guint annot_page;
5496  double page_width;
5497  double page_height;
5498 
5499  if (!view->moving_annot_info.annot)
5500  return TRUE;
5501 
5502  view_point.x = event->x + view->scroll_x;
5503  view_point.y = event->y + view->scroll_y;
5504 
5505  if (!view->moving_annot_info.moving_annot) {
5506  /* Only move the annotation if the threshold is exceeded */
5507  if (!gtk_drag_check_threshold (widget,
5508  view->moving_annot_info.start.x,
5509  view->moving_annot_info.start.y,
5510  view_point.x,
5511  view_point.y))
5512  return TRUE;
5514  }
5515 
5516  ev_annotation_get_area (view->moving_annot_info.annot, &current_area);
5518  ev_view_get_page_extents (view, annot_page, &page_area, &border);
5519  _ev_view_transform_view_point_to_doc_point (view, &view_point, &page_area, &border,
5520  &doc_point.x, &doc_point.y);
5521 
5522  ev_document_get_page_size (view->document, annot_page, &page_width, &page_height);
5523 
5524  rect.x1 = MAX (0, doc_point.x - view->moving_annot_info.cursor_offset.x);
5525  rect.y1 = MAX (0, doc_point.y - view->moving_annot_info.cursor_offset.y);
5526  rect.x2 = rect.x1 + current_area.x2 - current_area.x1;
5527  rect.y2 = rect.y1 + current_area.y2 - current_area.y1;
5528 
5529  /* Prevent the annotation from being moved off the page */
5530  if (rect.x2 > page_width) {
5531  rect.x2 = page_width;
5532  rect.x1 = page_width - current_area.x2 + current_area.x1;
5533  }
5534  if (rect.y2 > page_height) {
5535  rect.y2 = page_height;
5536  rect.y1 = page_height - current_area.y2 + current_area.y1;
5537  }
5538 
5539  /* Take the mutex before set_area, because the notify signal
5540  * updates the mappings in the backend */
5542  if (ev_annotation_set_area (view->moving_annot_info.annot, &rect)) {
5544  view->moving_annot_info.annot,
5546  }
5548 
5549  /* FIXME: reload only annotation area */
5550  ev_view_reload_page (view, annot_page, NULL);
5551  } else {
5552  /* Schedule timeout to scroll during selection and additionally
5553  * scroll once to allow arbitrary speed. */
5554  if (!view->selection_scroll_id)
5555  view->selection_scroll_id = g_timeout_add (SCROLL_TIME,
5556  (GSourceFunc)selection_scroll_timeout_cb,
5557  view);
5558  else
5560 
5561  view->motion.x = x + view->scroll_x;
5562  view->motion.y = y + view->scroll_y;
5563 
5564  /* Queue an idle to handle the motion. We do this because
5565  * handling any selection events in the motion could be slower
5566  * than new motion events reach us. We always put it in the
5567  * idle to make sure we catch up and don't visibly lag the
5568  * mouse. */
5569  if (!view->selection_update_id)
5570  view->selection_update_id = g_idle_add ((GSourceFunc)selection_update_idle_cb, view);
5571  }
5572 
5573  return TRUE;
5574  case 2:
5575  if (!view->drag_info.in_drag) {
5576  gboolean start;
5577  int i;
5578 
5579  start = gtk_drag_check_threshold (widget,
5580  view->drag_info.start.x,
5581  view->drag_info.start.y,
5582  event->x_root,
5583  event->y_root);
5584  view->drag_info.in_drag = start;
5585  view->drag_info.drag_timeout_id = g_timeout_add (10,
5586  (GSourceFunc)ev_view_drag_update_momentum, view);
5587  /* Set 100 to choose how long it takes to build up momentum */
5588  /* Clear out previous momentum info: */
5589  for (i = 0; i < DRAG_HISTORY; i++) {
5590  view->drag_info.buffer[i].x = event->x;
5591  view->drag_info.buffer[i].y = event->y;
5592  }
5593  view->drag_info.momentum.x = 0;
5594  view->drag_info.momentum.y = 0;
5595  }
5596 
5597  if (view->drag_info.in_drag) {
5598  int dx, dy;
5599  gdouble dhadj_value, dvadj_value;
5600  GtkAllocation allocation;
5601 
5602  view->drag_info.buffer[0].x = event->x;
5603  view->drag_info.buffer[0].y = event->y;
5604 
5605  dx = event->x_root - view->drag_info.start.x;
5606  dy = event->y_root - view->drag_info.start.y;
5607 
5608  gtk_widget_get_allocation (widget, &allocation);
5609 
5610  dhadj_value = gtk_adjustment_get_page_size (view->hadjustment) *
5611  (gdouble)dx / allocation.width;
5612  dvadj_value = gtk_adjustment_get_page_size (view->vadjustment) *
5613  (gdouble)dy / allocation.height;
5614 
5615  /* clamp scrolling to visible area */
5616  gtk_adjustment_set_value (view->hadjustment,
5617  MIN (view->drag_info.hadj - dhadj_value,
5618  gtk_adjustment_get_upper (view->hadjustment) -
5619  gtk_adjustment_get_page_size (view->hadjustment)));
5620  gtk_adjustment_set_value (view->vadjustment,
5621  MIN (view->drag_info.vadj - dvadj_value,
5622  gtk_adjustment_get_upper (view->vadjustment) -
5623  gtk_adjustment_get_page_size (view->vadjustment)));
5624 
5625  return TRUE;
5626  }
5627 
5628  break;
5629  default:
5630  ev_view_handle_cursor_over_xy (view, x, y);
5631  }
5632 
5633  return FALSE;
5634 }
5635 
5636 static gboolean
5637 ev_view_button_release_event (GtkWidget *widget,
5638  GdkEventButton *event)
5639 {
5640  EvView *view = EV_VIEW (widget);
5641  EvLink *link = NULL;
5642 
5643  view->image_dnd_info.in_drag = FALSE;
5644 
5645  if (gtk_gesture_is_recognized (view->zoom_gesture))
5646  return TRUE;
5647 
5648  if (view->scroll_info.autoscrolling) {
5649  ev_view_autoscroll_stop (view);
5650  view->pressed_button = -1;
5651 
5652  return TRUE;
5653  }
5654 
5655  if (view->pressed_button == 1 && event->state & GDK_CONTROL_MASK) {
5656  view->pressed_button = -1;
5657  return TRUE;
5658  }
5659 
5660  if (view->drag_info.in_drag) {
5662  g_timeout_add (20,
5663  (GSourceFunc)ev_view_scroll_drag_release, view);
5664  }
5665 
5666  if (view->document && !view->drag_info.in_drag && view->pressed_button != 3) {
5667  link = ev_view_get_link_at_location (view, event->x, event->y);
5668  }
5669 
5670  view->drag_info.in_drag = FALSE;
5671 
5672  if (view->adding_annot_info.adding_annot) {
5673  gboolean annot_added = TRUE;
5674 
5675  /* We ignore right-click buttons while in annotation add mode */
5676  if (view->pressed_button != 1)
5677  return FALSE;
5678  g_assert (view->adding_annot_info.annot);
5679 
5681  GtkWindow *parent;
5682  GtkWidget *window;
5683  EvRectangle area;
5684  EvRectangle popup_rect;
5685 
5687 
5688  if (area.x1 == 0 && area.y1 == 0 && area.x2 == 0 && area.y2 == 0) {
5689  /* Do not create empty annots */
5690  annot_added = FALSE;
5691 
5694  view->adding_annot_info.annot);
5696 
5700  } else {
5701  popup_rect.x1 = area.x2;
5702  popup_rect.x2 = popup_rect.x1 + ANNOT_POPUP_WINDOW_DEFAULT_WIDTH;
5703  popup_rect.y1 = area.y2;
5704  popup_rect.y2 = popup_rect.y1 + ANNOT_POPUP_WINDOW_DEFAULT_HEIGHT;
5705 
5707  &popup_rect)) {
5710  view->adding_annot_info.annot,
5713  }
5714  /* the annotation window might already exist */
5715  window = get_window_for_annot (view, view->adding_annot_info.annot);
5716 
5717  if (window == NULL) {
5718  parent = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view)));
5719  window = ev_view_create_annotation_window (view, view->adding_annot_info.annot, parent);
5720  }
5721  /* Show the annot window the first time for text annotations */
5723  ev_view_annotation_show_popup_window (view, window);
5724  }
5725  }
5726 
5727  view->adding_annot_info.stop.x = event->x + view->scroll_x;
5728  view->adding_annot_info.stop.y = event->y + view->scroll_y;
5729  if (annot_added)
5730  g_signal_emit (view, signals[SIGNAL_ANNOT_ADDED], 0, view->adding_annot_info.annot);
5731 
5733  view->adding_annot_info.annot = NULL;
5734  ev_view_handle_cursor_over_xy (view, event->x, event->y);
5735  view->pressed_button = -1;
5736 
5737  return FALSE;
5738  }
5739 
5740  if (view->moving_annot_info.annot_clicked) {
5741  if (view->moving_annot_info.moving_annot)
5742  ev_view_handle_cursor_over_xy (view, event->x, event->y);
5743  else
5744  ev_view_handle_annotation (view, view->moving_annot_info.annot, event->x, event->y, event->time);
5745 
5748  view->moving_annot_info.annot = NULL;
5749  view->pressed_button = -1;
5750 
5751  return FALSE;
5752  }
5753 
5754  if (view->pressed_button == 1) {
5755  EvAnnotation *annot = ev_view_get_annotation_at_location (view, event->x, event->y);
5756 
5757  if (annot)
5758  ev_view_handle_annotation (view, annot, event->x, event->y, event->time);
5759  }
5760 
5761  if (view->pressed_button == 2) {
5762  ev_view_handle_cursor_over_xy (view, event->x, event->y);
5763  }
5764 
5765  view->pressed_button = -1;
5766 
5767  if (view->selection_scroll_id) {
5768  g_source_remove (view->selection_scroll_id);
5769  view->selection_scroll_id = 0;
5770  }
5771  if (view->selection_update_id) {
5772  g_source_remove (view->selection_update_id);
5773  view->selection_update_id = 0;
5774  }
5775 
5776  if (view->selection_info.selections) {
5777  clear_link_selected (view);
5779 
5780  position_caret_cursor_for_event (view, event, FALSE);
5781 
5782  if (view->selection_info.in_drag)
5783  clear_selection (view);
5784  view->selection_info.in_drag = FALSE;
5785  } else if (link) {
5786  if (event->button == 2) {
5787  EvLinkAction *action;
5788  EvLinkActionType type;
5789 
5790  action = ev_link_get_action (link);
5791  if (!action)
5792  return FALSE;
5793 
5794  type = ev_link_action_get_action_type (action);
5795  if (type == EV_LINK_ACTION_TYPE_GOTO_DEST) {
5796  g_signal_emit (view,
5798  0, action);
5799  }
5800  } else {
5801  ev_view_handle_link (view, link);
5802  }
5803  }
5804 
5805  return FALSE;
5806 }
5807 
5808 static gboolean
5810  GdkEventKey *event)
5811 {
5812  GtkWidget *child_widget = NULL;
5813  GdkEventKey *new_event;
5814  gboolean handled;
5815 
5816  if (view->window_child_focus) {
5817  child_widget = view->window_child_focus->window;
5818  } else if (view->children) {
5819  EvViewChild *child = (EvViewChild *)view->children->data;
5820 
5821  child_widget = child->widget;
5822  } else {
5823  return FALSE;
5824  }
5825 
5826  new_event = (GdkEventKey *) gdk_event_copy ((GdkEvent *)event);
5827  g_object_unref (new_event->window);
5828  new_event->window = gtk_widget_get_window (child_widget);
5829  if (new_event->window)
5830  g_object_ref (new_event->window);
5831  gtk_widget_realize (child_widget);
5832  handled = gtk_widget_event (child_widget, (GdkEvent *)new_event);
5833  gdk_event_free ((GdkEvent *)new_event);
5834 
5835  return handled;
5836 }
5837 
5838 static gint
5840  gint page)
5841 {
5842  int n_pages;
5843  gboolean dual_page;
5844 
5845  if (!view->document)
5846  return -1;
5847 
5848  n_pages = ev_document_get_n_pages (view->document);
5849 
5850  dual_page = is_dual_page (view, NULL);
5851  page += dual_page ? 2 : 1;
5852 
5853  if (page < n_pages)
5854  return page;
5855 
5856  if (dual_page && page == n_pages)
5857  return page - 1;
5858 
5859  return -1;
5860 }
5861 
5862 static gint
5864  gint page)
5865 {
5866  gboolean dual_page;
5867 
5868  if (!view->document)
5869  return -1;
5870 
5871  dual_page = is_dual_page (view, NULL);
5872  page -= dual_page ? 2 : 1;
5873 
5874  if (page >= 0)
5875  return page;
5876 
5877  if (dual_page && page == -1)
5878  return 0;
5879 
5880  return -1;
5881 }
5882 
5883 static gboolean
5885 {
5886  view->cursor_offset = 0;
5887 
5888  return TRUE;
5889 }
5890 
5891 static gboolean
5893 {
5894  PangoLogAttr *log_attrs = NULL;
5895  gulong n_attrs;
5896 
5897  if (!view->page_cache)
5898  return FALSE;
5899 
5900  ev_page_cache_get_text_log_attrs (view->page_cache, view->cursor_page, &log_attrs, &n_attrs);
5901  if (!log_attrs)
5902  return FALSE;
5903 
5904  view->cursor_offset = n_attrs;
5905 
5906  return TRUE;
5907 }
5908 
5909 static gboolean
5911 {
5912  gint new_page;
5913 
5914  new_page = go_to_next_page (view, view->cursor_page);
5915  if (new_page != -1) {
5916  view->cursor_page = new_page;
5917  return cursor_go_to_page_start (view);
5918  }
5919 
5920  return FALSE;
5921 }
5922 
5923 static gboolean
5925 {
5926  gint new_page;
5927 
5928  new_page = go_to_previous_page (view, view->cursor_page);
5929  if (new_page != -1) {
5930  view->cursor_page = new_page;
5931  return cursor_go_to_page_end (view);
5932  }
5933  return FALSE;
5934 }
5935 
5936 static gboolean
5938 {
5939  view->cursor_page = 0;
5940  return cursor_go_to_page_start (view);
5941 }
5942 
5943 static gboolean
5945 {
5946  if (!view->document)
5947  return FALSE;
5948 
5949  view->cursor_page = ev_document_get_n_pages (view->document) - 1;
5950  return cursor_go_to_page_end (view);
5951 }
5952 
5953 static gboolean
5955 {
5956  PangoLogAttr *log_attrs = NULL;
5957  gulong n_attrs;
5958 
5959  if (!view->page_cache)
5960  return FALSE;
5961 
5962  ev_page_cache_get_text_log_attrs (view->page_cache, view->cursor_page, &log_attrs, &n_attrs);
5963  if (!log_attrs)
5964  return FALSE;
5965 
5966  if (view->cursor_offset == 0)
5967  return cursor_go_to_previous_page (view);
5968 
5969  do {
5970  view->cursor_offset--;
5971  } while (view->cursor_offset >= 0 && !log_attrs[view->cursor_offset].is_cursor_position);
5972 
5973  return TRUE;
5974 }
5975 
5976 static gboolean
5978 {
5979  PangoLogAttr *log_attrs = NULL;
5980  gulong n_attrs;
5981 
5982  if (!view->page_cache)
5983  return FALSE;
5984 
5985  ev_page_cache_get_text_log_attrs (view->page_cache, view->cursor_page, &log_attrs, &n_attrs);
5986  if (!log_attrs)
5987  return FALSE;
5988 
5989  if (view->cursor_offset >= n_attrs)
5990  return cursor_go_to_next_page (view);
5991 
5992  do {
5993  view->cursor_offset++;
5994  } while (view->cursor_offset <= n_attrs && !log_attrs[view->cursor_offset].is_cursor_position);
5995 
5996  return TRUE;
5997 }
5998 
5999 static gboolean
6001 {
6002  PangoLogAttr *log_attrs = NULL;
6003  gulong n_attrs;
6004  gint i, j;
6005 
6006  if (!view->page_cache)
6007  return FALSE;
6008 
6009  ev_page_cache_get_text_log_attrs (view->page_cache, view->cursor_page, &log_attrs, &n_attrs);
6010  if (!log_attrs)
6011  return FALSE;
6012 
6013  /* Skip current word starts */
6014  for (i = view->cursor_offset; i >= 0 && log_attrs[i].is_word_start; i--);
6015  if (i <= 0) {
6016  if (cursor_go_to_previous_page (view))
6017  return cursor_backward_word_start (view);
6018  return FALSE;
6019  }
6020 
6021  /* Move to the beginning of the word */
6022  for (j = i; j >= 0 && !log_attrs[j].is_word_start; j--);
6023  view->cursor_offset = MAX (0, j);
6024 
6025  return TRUE;
6026 }
6027 
6028 static gboolean
6030 {
6031  PangoLogAttr *log_attrs = NULL;
6032  gulong n_attrs;
6033  gint i, j;
6034 
6035  if (!view->page_cache)
6036  return FALSE;
6037 
6038  ev_page_cache_get_text_log_attrs (view->page_cache, view->cursor_page, &log_attrs, &n_attrs);
6039  if (!log_attrs)
6040  return FALSE;
6041 
6042  /* Skip current current word ends */
6043  for (i = view->cursor_offset; i < n_attrs && log_attrs[i].is_word_end; i++);
6044  if (i >= n_attrs) {
6045  if (cursor_go_to_next_page (view))
6046  return cursor_forward_word_end (view);
6047  return FALSE;
6048  }
6049 
6050  /* Move to the end of the word. */
6051  for (j = i; j < n_attrs && !log_attrs[j].is_word_end; j++);
6052  view->cursor_offset = MIN (j, n_attrs);
6053 
6054  return TRUE;
6055 }
6056 
6057 static gboolean
6059 {
6060  PangoLogAttr *log_attrs = NULL;
6061  gulong n_attrs;
6062  gint i;
6063 
6064  if (!view->page_cache)
6065  return FALSE;
6066 
6067  ev_page_cache_get_text_log_attrs (view->page_cache, view->cursor_page, &log_attrs, &n_attrs);
6068  if (!log_attrs)
6069  return FALSE;
6070 
6071  for (i = view->cursor_offset; i >= 0 && !log_attrs[i].is_mandatory_break; i--);
6072  view->cursor_offset = MAX (0, i);
6073 
6074  return TRUE;
6075 }
6076 
6077 static gboolean
6079 {
6080  PangoLogAttr *log_attrs = NULL;
6081  gulong n_attrs;
6082 
6083  if (!cursor_go_to_line_start (view))
6084  return FALSE;
6085 
6086  if (view->cursor_offset == 0)
6087  return cursor_go_to_previous_page (view);
6088 
6089  ev_page_cache_get_text_log_attrs (view->page_cache, view->cursor_page, &log_attrs, &n_attrs);
6090 
6091  do {
6092  view->cursor_offset--;
6093  } while (view->cursor_offset >= 0 && !log_attrs[view->cursor_offset].is_mandatory_break);
6094  view->cursor_offset = MAX (0, view->cursor_offset);
6095 
6096  return TRUE;
6097 }
6098 
6099 static gboolean
6101 {
6102  PangoLogAttr *log_attrs = NULL;
6103  gulong n_attrs;
6104  gint i;
6105 
6106  if (!view->page_cache)
6107  return FALSE;
6108 
6109  ev_page_cache_get_text_log_attrs (view->page_cache, view->cursor_page, &log_attrs, &n_attrs);
6110  if (!log_attrs)
6111  return FALSE;
6112 
6113  for (i = view->cursor_offset + 1; i <= n_attrs && !log_attrs[i].is_mandatory_break; i++);
6114  view->cursor_offset = MIN (i, n_attrs);
6115 
6116  if (view->cursor_offset == n_attrs)
6117  return TRUE;
6118 
6119  do {
6120  view->cursor_offset--;
6121  } while (view->cursor_offset >= 0 && !log_attrs[view->cursor_offset].is_cursor_position);
6122 
6123  return TRUE;
6124 }
6125 
6126 static gboolean
6128 {
6129  PangoLogAttr *log_attrs = NULL;
6130  gulong n_attrs;
6131 
6132  if (!cursor_go_to_line_end (view))
6133  return FALSE;
6134 
6135  ev_page_cache_get_text_log_attrs (view->page_cache, view->cursor_page, &log_attrs, &n_attrs);
6136 
6137  if (view->cursor_offset == n_attrs)
6138  return cursor_go_to_next_page (view);
6139 
6140  do {
6141  view->cursor_offset++;
6142  } while (view->cursor_offset <= n_attrs && !log_attrs[view->cursor_offset].is_cursor_position);
6143 
6144  return TRUE;
6145 }
6146 
6147 static void
6149  GdkPoint *start_point,
6150  GdkPoint *end_point)
6151 {
6152  if (!view->selection_info.selections) {
6153  view->selection_info.start.x = start_point->x;
6154  view->selection_info.start.y = start_point->y;
6155  }
6156 
6157  compute_selections (view,
6159  &(view->selection_info.start),
6160  end_point);
6161 }
6162 
6163 static gboolean
6165  gboolean forward)
6166 {
6167  GList *l;
6168  EvViewSelection *selection;
6169  cairo_rectangle_int_t rect;
6170  gint doc_x, doc_y;
6171 
6172  /* When clearing the selection, move the cursor to
6173  * the limits of the selection region.
6174  */
6175  if (!view->selection_info.selections)
6176  return FALSE;
6177 
6178  l = forward ? g_list_last (view->selection_info.selections) : view->selection_info.selections;
6179  selection = (EvViewSelection *)l->data;
6180  if (!selection->covered_region || cairo_region_is_empty (selection->covered_region))
6181  return FALSE;
6182 
6183  cairo_region_get_rectangle (selection->covered_region,
6184  forward ? cairo_region_num_rectangles (selection->covered_region) - 1 : 0,
6185  &rect);
6186 
6187  if (!get_doc_point_from_offset (view, selection->page,
6188  forward ? rect.x + rect.width : rect.x,
6189  rect.y + (rect.height / 2), &doc_x, &doc_y))
6190  return FALSE;
6191 
6192  position_caret_cursor_at_doc_point (view, selection->page, doc_x, doc_y);
6193  return TRUE;
6194 }
6195 
6196 static gboolean
6198  GtkMovementStep step,
6199  gint count,
6200  gboolean extend_selections)
6201 {
6202  GdkRectangle rect;
6203  GdkRectangle prev_rect;
6204  gint prev_offset;
6205  gint prev_page;
6206  cairo_region_t *damage_region;
6207  gboolean clear_selections = FALSE;
6208 
6209  if (!view->caret_enabled || view->rotation != 0)
6210  return FALSE;
6211 
6212  view->key_binding_handled = TRUE;
6213  view->cursor_blink_time = 0;
6214 
6215  prev_offset = view->cursor_offset;
6216  prev_page = view->cursor_page;
6217 
6218  clear_selections = !extend_selections && view->selection_info.selections != NULL;
6219 
6220  switch (step) {
6221  case GTK_MOVEMENT_VISUAL_POSITIONS:
6222  if (!clear_selections || !cursor_clear_selection (view, count > 0)) {
6223  while (count > 0) {
6224  cursor_forward_char (view);
6225  count--;
6226  }
6227  while (count < 0) {
6228  cursor_backward_char (view);
6229  count++;
6230  }
6231  }
6232  break;
6233  case GTK_MOVEMENT_WORDS:
6234  while (count > 0) {
6235  cursor_forward_word_end (view);
6236  count--;
6237  }
6238  while (count < 0) {
6240  count++;
6241  }
6242  break;
6243  case GTK_MOVEMENT_DISPLAY_LINES:
6244  while (count > 0) {
6245  cursor_forward_line (view);
6246  count--;
6247  }
6248  while (count < 0) {
6249  cursor_backward_line (view);
6250  count++;
6251  }
6252  break;
6253  case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
6254  if (count > 0)
6255  cursor_go_to_line_end (view);
6256  else if (count < 0)
6257  cursor_go_to_line_start (view);
6258  break;
6259  case GTK_MOVEMENT_BUFFER_ENDS:
6260  if (count > 0)
6262  else if (count < 0)
6264  break;
6265  default:
6266  g_assert_not_reached ();
6267  }
6268 
6270 
6271  /* Notify the user that it was not possible to move the caret cursor */
6272  if (!clear_selections &&
6273  prev_offset == view->cursor_offset && prev_page == view->cursor_page) {
6274  gtk_widget_error_bell (GTK_WIDGET (view));
6275  return TRUE;
6276  }
6277 
6278  /* Scroll to make the caret visible */
6279  if (!get_caret_cursor_area (view, view->cursor_page, view->cursor_offset, &rect))
6280  return TRUE;
6281 
6282  if (step == GTK_MOVEMENT_DISPLAY_LINES) {
6284  MAX (rect.x, view->cursor_line_offset),
6285  rect.y + (rect.height / 2));
6286  if (!clear_selections &&
6287  prev_offset == view->cursor_offset && prev_page == view->cursor_page) {
6288  gtk_widget_error_bell (GTK_WIDGET (view));
6289  return TRUE;
6290  }
6291 
6292  if (!get_caret_cursor_area (view, view->cursor_page, view->cursor_offset, &rect))
6293  return TRUE;
6294  } else {
6295  view->cursor_line_offset = rect.x;
6296  }
6297 
6298  damage_region = cairo_region_create_rectangle (&rect);
6299  if (get_caret_cursor_area (view, prev_page, prev_offset, &prev_rect))
6300  cairo_region_union_rectangle (damage_region, &prev_rect);
6301 
6302  rect.x += view->scroll_x;
6303  rect.y += view->scroll_y;
6304 
6306  ensure_rectangle_is_visible (view, &rect);
6307 
6308  g_signal_emit (view, signals[SIGNAL_CURSOR_MOVED], 0, view->cursor_page, view->cursor_offset);
6309 
6310  gdk_window_invalidate_region (gtk_widget_get_window (GTK_WIDGET (view)),
6311  damage_region, TRUE);
6312  cairo_region_destroy (damage_region);
6313 
6314  /* Select text */
6315  if (extend_selections && EV_IS_SELECTION (view->document)) {
6316  GdkPoint start_point, end_point;
6317 
6318  start_point.x = prev_rect.x + view->scroll_x;
6319  start_point.y = prev_rect.y + (prev_rect.height / 2) + view->scroll_y;
6320 
6321  end_point.x = rect.x;
6322  end_point.y = rect.y + rect.height / 2;
6323 
6324  extend_selection (view, &start_point, &end_point);
6325  } else if (clear_selections)
6326  clear_selection (view);
6327 
6328  return TRUE;
6329 }
6330 
6331 static gboolean
6332 ev_view_key_press_event (GtkWidget *widget,
6333  GdkEventKey *event)
6334 {
6335  EvView *view = EV_VIEW (widget);
6336  gboolean retval;
6337 
6338  if (!view->document)
6339  return FALSE;
6340 
6341  if (!gtk_widget_has_focus (widget))
6342  return ev_view_forward_key_event_to_focused_child (view, event);
6343 
6344  /* I expected GTK+ do this for me, but it doesn't cancel
6345  * the propagation of bindings handled for the same binding set
6346  */
6347  view->key_binding_handled = FALSE;
6348  retval = gtk_bindings_activate_event (G_OBJECT (widget), event);
6349  view->key_binding_handled = FALSE;
6350 
6351  return retval;
6352 }
6353 
6354 static gboolean
6356  EvFormField *field)
6357 {
6358  gboolean handled = FALSE;
6359 
6360  if (field->is_read_only)
6361  return handled;
6362 
6363  if (field->activation_link) {
6364  ev_view_handle_link (view, field->activation_link);
6365  handled = TRUE;
6366  }
6367 
6368  if (EV_IS_FORM_FIELD_BUTTON (field)) {
6369  ev_view_form_field_button_toggle (view, field);
6370  handled = TRUE;
6371  }
6372 
6373  return handled;
6374 }
6375 
6376 static gboolean
6378 {
6379  GdkEvent *current_event;
6380  guint keyval;
6381  gboolean is_space_key_press;
6382 
6383  current_event = gtk_get_current_event ();
6384  if (!current_event)
6385  return FALSE;
6386 
6387  is_space_key_press = current_event->type == GDK_KEY_PRESS &&
6388  gdk_event_get_keyval (current_event, &keyval) &&
6389  (keyval == GDK_KEY_space || keyval == GDK_KEY_KP_Space);
6390  gdk_event_free (current_event);
6391 
6392  return is_space_key_press;
6393 }
6394 
6395 static gboolean
6397  EvLink *link)
6398 {
6399  /* Most of the GtkWidgets emit activate on both Space and Return key press,
6400  * but we don't want to activate links on Space for consistency with the Web.
6401  */
6403  return FALSE;
6404 
6405  ev_view_handle_link (view, link);
6406 
6407  return TRUE;
6408 }
6409 
6410 static void
6412 {
6413  if (!view->focused_element)
6414  return;
6415 
6416  if (EV_IS_DOCUMENT_FORMS (view->document) &&
6419  return;
6420  }
6421 
6422  if (EV_IS_DOCUMENT_LINKS (view->document) &&
6423  EV_IS_LINK (view->focused_element->data)) {
6425  return;
6426  }
6427 }
6428 
6429 static gboolean
6431 {
6432  gdouble speed, value;
6433 
6434  /* If the user stops autoscrolling, autoscrolling will be
6435  * set to false but the timeout will continue; stop the timeout: */
6436  if (!view->scroll_info.autoscrolling) {
6437  view->scroll_info.timeout_id = 0;
6438  return FALSE;
6439  }
6440 
6441  /* Replace 100 with your speed of choice: The lower the faster.
6442  * Replace 3 with another speed of choice: The higher, the faster it accelerated
6443  * based on the distance of the starting point from the mouse
6444  * (All also effected by the timeout interval of this callback) */
6445 
6446  if (view->scroll_info.start_y > view->scroll_info.last_y)
6447  speed = -pow ((((gdouble)view->scroll_info.start_y - view->scroll_info.last_y) / 100), 3);
6448  else
6449  speed = pow ((((gdouble)view->scroll_info.last_y - view->scroll_info.start_y) / 100), 3);
6450 
6451  value = gtk_adjustment_get_value (view->vadjustment);
6452  value = CLAMP (value + speed, 0,
6453  gtk_adjustment_get_upper (view->vadjustment) -
6454  gtk_adjustment_get_page_size (view->vadjustment));
6455  gtk_adjustment_set_value (view->vadjustment, value);
6456 
6457  return TRUE;
6458 
6459 }
6460 
6461 static void
6463 {
6464  if (!view->scroll_info.autoscrolling)
6465  return;
6466 
6467  if (view->scroll_info.timeout_id > 0)
6468  return;
6469 
6470  view->scroll_info.timeout_id =
6471  g_timeout_add (20, (GSourceFunc)ev_view_autoscroll_cb,
6472  view);
6473 }
6474 
6475 static void
6477 {
6478  if (!view->scroll_info.autoscrolling)
6479  return;
6480 
6481  if (view->scroll_info.timeout_id == 0)
6482  return;
6483 
6484  g_source_remove (view->scroll_info.timeout_id);
6485  view->scroll_info.timeout_id = 0;
6486 }
6487 
6488 static gint
6489 ev_view_focus_in (GtkWidget *widget,
6490  GdkEventFocus *event)
6491 {
6492  EvView *view = EV_VIEW (widget);
6493 
6494  if (view->pixbuf_cache)
6496 
6498 
6500  gtk_widget_queue_draw (widget);
6501 
6502  return FALSE;
6503 }
6504 
6505 static gint
6506 ev_view_focus_out (GtkWidget *widget,
6507  GdkEventFocus *event)
6508 {
6509  EvView *view = EV_VIEW (widget);
6510 
6511  if (view->pixbuf_cache)
6513 
6514  ev_view_autoscroll_pause (view);
6515 
6517  gtk_widget_queue_draw (widget);
6518 
6519  return FALSE;
6520 }
6521 
6522 static gboolean
6523 ev_view_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event)
6524 {
6525  EvView *view = EV_VIEW (widget);
6526 
6527  if (view->cursor != EV_VIEW_CURSOR_NORMAL)
6529 
6530  return FALSE;
6531 }
6532 
6533 static gboolean
6534 ev_view_enter_notify_event (GtkWidget *widget, GdkEventCrossing *event)
6535 {
6536  EvView *view = EV_VIEW (widget);
6537 
6538  ev_view_handle_cursor_over_xy (view, event->x, event->y);
6539 
6540  return FALSE;
6541 }
6542 
6543 static void
6544 ev_view_style_updated (GtkWidget *widget)
6545 {
6546  if (EV_VIEW (widget)->pixbuf_cache)
6547  ev_pixbuf_cache_style_changed (EV_VIEW (widget)->pixbuf_cache);
6548 
6549  GTK_WIDGET_CLASS (ev_view_parent_class)->style_updated (widget);
6550 }
6551 
6552 /*** Drawing ***/
6553 
6554 static void
6556  cairo_t *cr,
6557  const GdkRectangle *rect,
6558  gdouble alpha)
6559 {
6560  GtkStyleContext *context;
6561  GdkRGBA color;
6562 
6563  context = gtk_widget_get_style_context (GTK_WIDGET (view));
6564  gtk_style_context_save (context);
6565  gtk_style_context_get_background_color (context, GTK_STATE_FLAG_SELECTED, &color);
6566  gtk_style_context_restore (context);
6567  cairo_save (cr);
6568 
6569  cairo_set_source_rgba (cr, color.red, color.green, color.blue, alpha);
6570  cairo_rectangle (cr,
6571  rect->x - view->scroll_x,
6572  rect->y - view->scroll_y,
6573  rect->width, rect->height);
6574  cairo_fill_preserve (cr);
6575 
6576  cairo_set_line_width (cr, 0.5);
6577  cairo_set_source_rgb (cr, color.red, color.green, color.blue);
6578  cairo_stroke (cr);
6579 
6580  cairo_restore (cr);
6581 }
6582 
6583 
6584 static void
6586  cairo_t *cr,
6587  int page)
6588 {
6589  gint i, n_results = 0;
6590 
6591  n_results = ev_view_find_get_n_results (view, page);
6592 
6593  for (i = 0; i < n_results; i++) {
6594  EvRectangle *rectangle;
6595  GdkRectangle view_rectangle;
6596  gdouble alpha;
6597 
6598  if (i == view->find_result && page == view->find_page) {
6599  alpha = 0.6;
6600  } else {
6601  alpha = 0.3;
6602  }
6603 
6604  rectangle = ev_view_find_get_result (view, page, i);
6605  _ev_view_transform_doc_rect_to_view_rect (view, page, rectangle, &view_rectangle);
6606  draw_rubberband (view, cr, &view_rectangle, alpha);
6607  }
6608 }
6609 
6610 static void
6612  cairo_t *cr,
6613  int page)
6614 {
6615  GdkRectangle rect;
6616  EvMapping *mapping = view->synctex_result;
6617 
6618  if (GPOINTER_TO_INT (mapping->data) != page)
6619  return;
6620 
6621  _ev_view_transform_doc_rect_to_view_rect (view, page, &mapping->area, &rect);
6622 
6623  cairo_save (cr);
6624  cairo_set_source_rgb (cr, 1., 0., 0.);
6625  cairo_rectangle (cr,
6626  rect.x - view->scroll_x,
6627  rect.y - view->scroll_y,
6628  rect.width, rect.height);
6629  cairo_stroke (cr);
6630  cairo_restore (cr);
6631 }
6632 
6633 static void
6634 draw_surface (cairo_t *cr,
6635  cairo_surface_t *surface,
6636  gint x,
6637  gint y,
6638  gint offset_x,
6639  gint offset_y,
6640  gint target_width,
6641  gint target_height)
6642 {
6643  gdouble width, height;
6644  gdouble device_scale_x = 1, device_scale_y = 1;
6645 
6646 #ifdef HAVE_HIDPI_SUPPORT
6647  cairo_surface_get_device_scale (surface, &device_scale_x, &device_scale_y);
6648 #endif
6649  width = cairo_image_surface_get_width (surface) / device_scale_x;
6650  height = cairo_image_surface_get_height (surface) / device_scale_y;
6651 
6652  cairo_save (cr);
6653  cairo_translate (cr, x, y);
6654 
6655  if (width != target_width || height != target_height) {
6656  gdouble scale_x, scale_y;
6657 
6658  scale_x = (gdouble)target_width / width;
6659  scale_y = (gdouble)target_height / height;
6660  cairo_pattern_set_filter (cairo_get_source (cr),
6661  CAIRO_FILTER_NEAREST);
6662  cairo_scale (cr, scale_x, scale_y);
6663 
6664  offset_x /= scale_x;
6665  offset_y /= scale_y;
6666  }
6667 
6668  cairo_surface_set_device_offset (surface,
6669  offset_x * device_scale_x,
6670  offset_y * device_scale_y);
6671  cairo_set_source_surface (cr, surface, 0, 0);
6672  cairo_paint (cr);
6673  cairo_restore (cr);
6674 }
6675 
6676 void
6678  GdkRGBA *bg_color,
6679  GdkRGBA *fg_color)
6680 {
6681  GtkWidget *widget = GTK_WIDGET (view);
6682  GtkStateFlags state;
6683  GtkStyleContext *context;
6684 
6685  context = gtk_widget_get_style_context (widget);
6686  gtk_style_context_save (context);
6687  state = gtk_style_context_get_state (context) |
6688  (gtk_widget_has_focus (widget) ? GTK_STATE_FLAG_SELECTED : GTK_STATE_FLAG_ACTIVE);
6689  gtk_style_context_set_state (context, state);
6690 
6691  if (bg_color)
6692  gtk_style_context_get_background_color (context, state, bg_color);
6693 
6694  if (fg_color)
6695  gtk_style_context_get_color (context, state, fg_color);
6696 
6697  gtk_style_context_restore (context);
6698 }
6699 
6700 static void
6702  cairo_region_t *region,
6703  GdkRGBA *color,
6704  gint x,
6705  gint y,
6706  gdouble scale_x,
6707  gdouble scale_y)
6708 {
6709  cairo_save (cr);
6710  cairo_translate (cr, x, y);
6711  cairo_scale (cr, scale_x, scale_y);
6712  gdk_cairo_region (cr, region);
6713  cairo_set_source_rgb (cr, color->red, color->green, color->blue);
6714  cairo_set_operator (cr, CAIRO_OPERATOR_MULTIPLY);
6715  cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
6716  cairo_fill (cr);
6717  cairo_restore (cr);
6718 }
6719 
6720 static void
6722  gint page,
6723  cairo_t *cr,
6724  GdkRectangle *page_area,
6725  GtkBorder *border,
6726  GdkRectangle *expose_area,
6727  gboolean *page_ready)
6728 {
6729  GtkStyleContext *context;
6730  GdkRectangle overlap;
6731  GdkRectangle real_page_area;
6732  gint current_page;
6733 
6734  g_assert (view->document);
6735 
6736  if (! gdk_rectangle_intersect (page_area, expose_area, &overlap))
6737  return;
6738 
6739  /* Render the document itself */
6740  real_page_area = *page_area;
6741 
6742  real_page_area.x += border->left;
6743  real_page_area.y += border->top;
6744  real_page_area.width -= (border->left + border->right);
6745  real_page_area.height -= (border->top + border->bottom);
6746  *page_ready = TRUE;
6747 
6748  context = gtk_widget_get_style_context (GTK_WIDGET (view));
6749  current_page = ev_document_model_get_page (view->model);
6750 
6751  gtk_style_context_save (context);
6752  gtk_style_context_add_class (context, EV_STYLE_CLASS_DOCUMENT_PAGE);
6754  gtk_style_context_add_class (context, EV_STYLE_CLASS_INVERTED);
6755 
6756  if (view->continuous && page == current_page)
6757  gtk_style_context_set_state (context, GTK_STATE_FLAG_ACTIVE);
6758 
6759  gtk_render_background (context, cr, page_area->x, page_area->y, page_area->width, page_area->height);
6760  gtk_render_frame (context, cr, page_area->x, page_area->y, page_area->width, page_area->height);
6761  gtk_style_context_restore (context);
6762 
6763  if (gdk_rectangle_intersect (&real_page_area, expose_area, &overlap)) {
6764  gint width, height;
6765  cairo_surface_t *page_surface = NULL;
6766  cairo_surface_t *selection_surface = NULL;
6767  gint offset_x, offset_y;
6768  cairo_region_t *region = NULL;
6769 
6770  page_surface = ev_pixbuf_cache_get_surface (view->pixbuf_cache, page);
6771 
6772  if (!page_surface) {
6773  if (page == current_page)
6774  ev_view_set_loading (view, TRUE);
6775 
6776  *page_ready = FALSE;
6777 
6778  return;
6779  }
6780 
6781  if (page == current_page)
6782  ev_view_set_loading (view, FALSE);
6783 
6784  ev_view_get_page_size (view, page, &width, &height);
6785  offset_x = overlap.x - real_page_area.x;
6786  offset_y = overlap.y - real_page_area.y;
6787 
6788  draw_surface (cr, page_surface, overlap.x, overlap.y, offset_x, offset_y, width, height);
6789 
6790  /* Get the selection pixbuf iff we have something to draw */
6791  if (!find_selection_for_page (view, page))
6792  return;
6793 
6794  selection_surface = ev_pixbuf_cache_get_selection_surface (view->pixbuf_cache,
6795  page,
6796  view->scale);
6797  if (selection_surface) {
6798  draw_surface (cr, selection_surface, overlap.x, overlap.y, offset_x, offset_y,
6799  width, height);
6800  return;
6801  }
6802 
6804  page,
6805  view->scale);
6806  if (region) {
6807  double scale_x, scale_y;
6808  GdkRGBA color;
6809  double device_scale_x = 1, device_scale_y = 1;
6810 
6811  scale_x = (gdouble)width / cairo_image_surface_get_width (page_surface);
6812  scale_y = (gdouble)height / cairo_image_surface_get_height (page_surface);
6813 
6814 #ifdef HAVE_HIDPI_SUPPORT
6815  cairo_surface_get_device_scale (page_surface, &device_scale_x, &device_scale_y);
6816 #endif
6817 
6818  scale_x *= device_scale_x;
6819  scale_y *= device_scale_y;
6820 
6821  _ev_view_get_selection_colors (view, &color, NULL);
6822  draw_selection_region (cr, region, &color, real_page_area.x, real_page_area.y,
6823  scale_x, scale_y);
6824  }
6825  }
6826 }
6827 
6828 /*** GObject functions ***/
6829 
6830 static void
6831 ev_view_finalize (GObject *object)
6832 {
6833  EvView *view = EV_VIEW (object);
6834 
6835  if (view->selection_info.selections) {
6836  g_list_free_full (view->selection_info.selections, (GDestroyNotify)selection_free);
6837  view->selection_info.selections = NULL;
6838  }
6839  clear_link_selected (view);
6840 
6841  if (view->synctex_result) {
6842  g_free (view->synctex_result);
6843  view->synctex_result = NULL;
6844  }
6845 
6846  if (view->image_dnd_info.image)
6847  g_object_unref (view->image_dnd_info.image);
6848  view->image_dnd_info.image = NULL;
6849  if (view->annot_window_map)
6850  g_hash_table_destroy (view->annot_window_map);
6851 
6852  g_object_unref (view->zoom_gesture);
6853 
6854  G_OBJECT_CLASS (ev_view_parent_class)->finalize (object);
6855 }
6856 
6857 static void
6858 ev_view_dispose (GObject *object)
6859 {
6860  EvView *view = EV_VIEW (object);
6861 
6862  if (view->model) {
6863  g_signal_handlers_disconnect_by_data (view->model, view);
6864  g_object_unref (view->model);
6865  view->model = NULL;
6866  }
6867 
6868  if (view->pixbuf_cache) {
6869  g_object_unref (view->pixbuf_cache);
6870  view->pixbuf_cache = NULL;
6871  }
6872 
6873  if (view->document) {
6874  g_object_unref (view->document);
6875  view->document = NULL;
6876  }
6877 
6878  if (view->page_cache) {
6879  g_object_unref (view->page_cache);
6880  view->page_cache = NULL;
6881  }
6882 
6883  ev_view_find_cancel (view);
6884 
6886 
6887  if (view->selection_scroll_id) {
6888  g_source_remove (view->selection_scroll_id);
6889  view->selection_scroll_id = 0;
6890  }
6891 
6892  if (view->selection_update_id) {
6893  g_source_remove (view->selection_update_id);
6894  view->selection_update_id = 0;
6895  }
6896 
6897  if (view->scroll_info.timeout_id) {
6898  g_source_remove (view->scroll_info.timeout_id);
6899  view->scroll_info.timeout_id = 0;
6900  }
6901 
6902  if (view->drag_info.drag_timeout_id) {
6903  g_source_remove (view->drag_info.drag_timeout_id);
6904  view->drag_info.drag_timeout_id = 0;
6905  }
6906 
6907  if (view->drag_info.release_timeout_id) {
6908  g_source_remove (view->drag_info.release_timeout_id);
6909  view->drag_info.release_timeout_id = 0;
6910  }
6911 
6912  if (view->cursor_blink_timeout_id) {
6913  g_source_remove (view->cursor_blink_timeout_id);
6914  view->cursor_blink_timeout_id = 0;
6915  }
6916 
6917  if (view->child_focus_idle_id) {
6918  g_source_remove (view->child_focus_idle_id);
6919  view->child_focus_idle_id = 0;
6920  }
6921 
6922  gtk_scrollable_set_hadjustment (GTK_SCROLLABLE (view), NULL);
6923  gtk_scrollable_set_vadjustment (GTK_SCROLLABLE (view), NULL);
6924 
6925  g_clear_object(&view->accessible);
6926 
6927  G_OBJECT_CLASS (ev_view_parent_class)->dispose (object);
6928 }
6929 
6930 static void
6931 ev_view_get_property (GObject *object,
6932  guint prop_id,
6933  GValue *value,
6934  GParamSpec *pspec)
6935 {
6936  EvView *view = EV_VIEW (object);
6937 
6938  switch (prop_id) {
6939  case PROP_IS_LOADING:
6940  g_value_set_boolean (value, view->loading);
6941  break;
6942  case PROP_CAN_ZOOM_IN:
6943  g_value_set_boolean (value, view->can_zoom_in);
6944  break;
6945  case PROP_CAN_ZOOM_OUT:
6946  g_value_set_boolean (value, view->can_zoom_out);
6947  break;
6948  case PROP_HADJUSTMENT:
6949  g_value_set_object (value, view->hadjustment);
6950  break;
6951  case PROP_VADJUSTMENT:
6952  g_value_set_object (value, view->vadjustment);
6953  break;
6954  case PROP_HSCROLL_POLICY:
6955  g_value_set_enum (value, view->hscroll_policy);
6956  break;
6957  case PROP_VSCROLL_POLICY:
6958  g_value_set_enum (value, view->vscroll_policy);
6959  break;
6960  default:
6961  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
6962  break;
6963  }
6964 }
6965 
6966 static void
6967 ev_view_set_property (GObject *object,
6968  guint prop_id,
6969  const GValue *value,
6970  GParamSpec *pspec)
6971 {
6972  EvView *view = EV_VIEW (object);
6973 
6974  switch (prop_id) {
6975  case PROP_IS_LOADING:
6976  ev_view_set_loading (view, g_value_get_boolean (value));
6977  break;
6978  case PROP_HADJUSTMENT:
6979  ev_view_set_scroll_adjustment (view, GTK_ORIENTATION_HORIZONTAL,
6980  (GtkAdjustment *) g_value_get_object (value));
6981  break;
6982  case PROP_VADJUSTMENT:
6983  ev_view_set_scroll_adjustment (view, GTK_ORIENTATION_VERTICAL,
6984  (GtkAdjustment *) g_value_get_object (value));
6985  break;
6986  case PROP_HSCROLL_POLICY:
6987  view->hscroll_policy = g_value_get_enum (value);
6988  gtk_widget_queue_resize (GTK_WIDGET (view));
6989  break;
6990  case PROP_VSCROLL_POLICY:
6991  view->vscroll_policy = g_value_get_enum (value);
6992  gtk_widget_queue_resize (GTK_WIDGET (view));
6993  break;
6994  default:
6995  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
6996  break;
6997  }
6998 }
6999 
7000 /* Accessibility */
7001 static AtkObject *
7002 ev_view_get_accessible (GtkWidget *widget)
7003 {
7004  EvView *view = EV_VIEW (widget);
7005 
7006  if (!view->accessible)
7007  view->accessible = ev_view_accessible_new (widget);
7008  return view->accessible;
7009 }
7010 
7011 /* GtkContainer */
7012 static void
7013 ev_view_remove (GtkContainer *container,
7014  GtkWidget *widget)
7015 {
7016  EvView *view = EV_VIEW (container);
7017  GList *tmp_list = view->children;
7018  EvViewChild *child;
7019 
7020  while (tmp_list) {
7021  child = tmp_list->data;
7022 
7023  if (child->widget == widget) {
7024  gtk_widget_unparent (widget);
7025 
7026  view->children = g_list_remove_link (view->children, tmp_list);
7027  g_list_free_1 (tmp_list);
7028  g_slice_free (EvViewChild, child);
7029 
7030  return;
7031  }
7032 
7033  tmp_list = tmp_list->next;
7034  }
7035 }
7036 
7037 static void
7038 ev_view_forall (GtkContainer *container,
7039  gboolean include_internals,
7040  GtkCallback callback,
7041  gpointer callback_data)
7042 {
7043  EvView *view = EV_VIEW (container);
7044  GList *tmp_list = view->children;
7045  EvViewChild *child;
7046 
7047  while (tmp_list) {
7048  child = tmp_list->data;
7049  tmp_list = tmp_list->next;
7050 
7051  (* callback) (child->widget, callback_data);
7052  }
7053 }
7054 
7055 static void
7057 {
7058  gdouble min_width, min_height;
7059  gdouble width, height;
7060  gdouble max_scale;
7061  gdouble dpi;
7062  gint rotation;
7063  GdkScreen *screen;
7064 
7065  if (!view->document)
7066  return;
7067 
7068  rotation = ev_document_model_get_rotation (view->model);
7069  screen = gtk_widget_get_screen (GTK_WIDGET (view));
7070  dpi = ev_document_misc_get_screen_dpi (screen) / 72.0;
7071 
7072  ev_document_get_min_page_size (view->document, &min_width, &min_height);
7073  width = (rotation == 0 || rotation == 180) ? min_width : min_height;
7074  height = (rotation == 0 || rotation == 180) ? min_height : min_width;
7075  max_scale = sqrt (view->pixbuf_cache_size / (width * dpi * 4 * height * dpi));
7076 
7078  ev_document_model_set_max_scale (view->model, max_scale * dpi);
7079 }
7080 
7081 static void
7082 ev_view_screen_changed (GtkWidget *widget,
7083  GdkScreen *old_screen)
7084 {
7085  EvView *view = EV_VIEW (widget);
7086  GdkScreen *screen;
7087 
7088  screen = gtk_widget_get_screen (widget);
7089  if (screen == old_screen)
7090  return;
7091 
7092  view_update_scale_limits (view);
7093 
7094  if (GTK_WIDGET_CLASS (ev_view_parent_class)->screen_changed) {
7095  GTK_WIDGET_CLASS (ev_view_parent_class)->screen_changed (widget, old_screen);
7096  }
7097 }
7098 
7099 static void
7100 pan_gesture_pan_cb (GtkGesturePan *gesture,
7101  GtkPanDirection direction,
7102  gdouble offset,
7103  EvView *view)
7104 {
7105  GtkAllocation allocation;
7106 
7107  gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
7108 
7109  if (view->continuous ||
7110  allocation.width < view->requisition.width) {
7111  gtk_gesture_set_state (GTK_GESTURE (gesture),
7112  GTK_EVENT_SEQUENCE_DENIED);
7113  return;
7114  }
7115 
7116 #define PAN_ACTION_DISTANCE 200
7117 
7119  gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
7120 
7121  if (offset > PAN_ACTION_DISTANCE) {
7122  if (direction == GTK_PAN_DIRECTION_LEFT ||
7123  gtk_widget_get_direction (GTK_WIDGET (view)) == GTK_TEXT_DIR_RTL)
7125  else
7127  }
7128 #undef PAN_ACTION_DISTANCE
7129 }
7130 
7131 static void
7132 pan_gesture_end_cb (GtkGesture *gesture,
7133  GdkEventSequence *sequence,
7134  EvView *view)
7135 {
7136  if (!gtk_gesture_handles_sequence (gesture, sequence))
7137  return;
7138 
7139  if (view->pan_action == EV_PAN_ACTION_PREV)
7140  ev_view_previous_page (view);
7141  else if (view->pan_action == EV_PAN_ACTION_NEXT)
7142  ev_view_next_page (view);
7143 
7145 }
7146 
7147 static void
7148 ev_view_hierarchy_changed (GtkWidget *widget,
7149  GtkWidget *previous_toplevel)
7150 {
7151  GtkWidget *parent = gtk_widget_get_parent (widget);
7152  EvView *view = EV_VIEW (widget);
7153 
7154  if (parent && !view->pan_gesture) {
7155  view->pan_gesture =
7156  gtk_gesture_pan_new (parent, GTK_ORIENTATION_HORIZONTAL);
7157  g_signal_connect (view->pan_gesture, "pan",
7158  G_CALLBACK (pan_gesture_pan_cb), widget);
7159  g_signal_connect (view->pan_gesture, "end",
7160  G_CALLBACK (pan_gesture_end_cb), widget);
7161 
7162  gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (view->pan_gesture), TRUE);
7163  gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (view->pan_gesture),
7164  GTK_PHASE_CAPTURE);
7165  } else if (!parent && view->pan_gesture) {
7166  g_clear_object (&view->pan_gesture);
7167  }
7168 }
7169 
7170 static void
7171 add_move_binding_keypad (GtkBindingSet *binding_set,
7172  guint keyval,
7173  GdkModifierType modifiers,
7174  GtkMovementStep step,
7175  gint count)
7176 {
7177  guint keypad_keyval = keyval - GDK_KEY_Left + GDK_KEY_KP_Left;
7178 
7179  gtk_binding_entry_add_signal (binding_set, keyval, modifiers,
7180  "move-cursor", 3,
7181  GTK_TYPE_MOVEMENT_STEP, step,
7182  G_TYPE_INT, count,
7183  G_TYPE_BOOLEAN, FALSE);
7184  gtk_binding_entry_add_signal (binding_set, keypad_keyval, modifiers,
7185  "move-cursor", 3,
7186  GTK_TYPE_MOVEMENT_STEP, step,
7187  G_TYPE_INT, count,
7188  G_TYPE_BOOLEAN, FALSE);
7189 
7190  /* Selection-extending version */
7191  gtk_binding_entry_add_signal (binding_set, keyval, modifiers | GDK_SHIFT_MASK,
7192  "move-cursor", 3,
7193  GTK_TYPE_MOVEMENT_STEP, step,
7194  G_TYPE_INT, count,
7195  G_TYPE_BOOLEAN, TRUE);
7196  gtk_binding_entry_add_signal (binding_set, keypad_keyval, modifiers | GDK_SHIFT_MASK,
7197  "move-cursor", 3,
7198  GTK_TYPE_MOVEMENT_STEP, step,
7199  G_TYPE_INT, count,
7200  G_TYPE_BOOLEAN, TRUE);
7201 }
7202 
7203 static gint
7205  const EvMapping *b,
7206  gpointer user_data)
7207 {
7208  GtkTextDirection text_direction = GPOINTER_TO_INT (user_data);
7209  gint y1 = a->area.y1 + (a->area.y2 - a->area.y1) / 2;
7210  gint y2 = b->area.y1 + (b->area.y2 - b->area.y1) / 2;
7211 
7212  if (y1 == y2) {
7213  gint x1 = a->area.x1 + (a->area.x2 - a->area.x1) / 2;
7214  gint x2 = b->area.x1 + (b->area.x2 - b->area.x1) / 2;
7215 
7216  if (text_direction == GTK_TEXT_DIR_RTL)
7217  return (x1 < x2) ? 1 : ((x1 == x2) ? 0 : -1);
7218 
7219  return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1);
7220  }
7221 
7222  return (y1 < y2) ? -1 : 1;
7223 }
7224 
7225 static GList *
7227  GtkDirectionType direction,
7228  gint page)
7229 {
7230  GList *mapping_list = NULL, *l;
7231  EvMappingList *forms_mapping;
7232 
7233  forms_mapping = ev_page_cache_get_form_field_mapping (view->page_cache, page);
7234 
7235  for (l = ev_mapping_list_get_list (forms_mapping); l; l = g_list_next (l)) {
7236  EvMapping *mapping = (EvMapping *)l->data;
7237  EvFormField *field = (EvFormField *)mapping->data;
7238 
7239  if (field->is_read_only || EV_IS_FORM_FIELD_SIGNATURE (field))
7240  continue;
7241 
7242  mapping_list = g_list_prepend (mapping_list, mapping);
7243  }
7244 
7245  if (!mapping_list)
7246  return NULL;
7247 
7248  mapping_list = g_list_sort_with_data (g_list_reverse (mapping_list),
7249  (GCompareDataFunc)ev_view_mapping_compare,
7250  GINT_TO_POINTER (gtk_widget_get_direction (GTK_WIDGET (view))));
7251 
7252  if (direction == GTK_DIR_TAB_BACKWARD)
7253  mapping_list = g_list_reverse (mapping_list);
7254  return mapping_list;
7255 }
7256 
7257 static gboolean
7258 child_focus_forward_idle_cb (gpointer user_data)
7259 {
7260  EvView *view = EV_VIEW (user_data);
7261 
7262  view->child_focus_idle_id = 0;
7263  gtk_widget_child_focus (GTK_WIDGET (view), GTK_DIR_TAB_FORWARD);
7264 
7265  return G_SOURCE_REMOVE;
7266 }
7267 
7268 static gboolean
7269 child_focus_backward_idle_cb (gpointer user_data)
7270 {
7271  EvView *view = EV_VIEW (user_data);
7272 
7273  view->child_focus_idle_id = 0;
7274  gtk_widget_child_focus (GTK_WIDGET (view), GTK_DIR_TAB_BACKWARD);
7275 
7276  return G_SOURCE_REMOVE;
7277 }
7278 
7279 static void
7281  GtkDirectionType direction)
7282 {
7283  if (view->child_focus_idle_id)
7284  g_source_remove (view->child_focus_idle_id);
7285  view->child_focus_idle_id =
7286  g_idle_add (direction == GTK_DIR_TAB_FORWARD ? child_focus_forward_idle_cb : child_focus_backward_idle_cb,
7287  view);
7288 }
7289 
7290 static gboolean
7292  GtkDirectionType direction)
7293 {
7294  EvMapping *focus_element;
7295  GList *elements;
7296  gboolean had_focused_element;
7297 
7298  if (view->focused_element) {
7299  GList *l;
7300 
7301  elements = ev_view_get_sorted_mapping_list (view, direction, view->focused_element_page);
7302  l = g_list_find (elements, view->focused_element);
7303  l = g_list_next (l);
7304  focus_element = l ? l->data : NULL;
7305  had_focused_element = TRUE;
7306  } else {
7307  elements = ev_view_get_sorted_mapping_list (view, direction, view->current_page);
7308  focus_element = elements ? elements->data : NULL;
7309  had_focused_element = FALSE;
7310  }
7311 
7312  g_list_free (elements);
7313 
7314  if (focus_element) {
7316  _ev_view_focus_form_field (view, EV_FORM_FIELD (focus_element->data));
7317 
7318  return TRUE;
7319  }
7320 
7322  _ev_view_set_focused_element (view, NULL, -1);
7323 
7324  /* Only try to move the focus to next/previous pages when the current page had
7325  * a focused element. This prevents the view from jumping to the first/last page
7326  * when there are not focusable elements.
7327  */
7328  if (!had_focused_element)
7329  return FALSE;
7330 
7331  /* FIXME: this doesn't work if the next/previous page doesn't have form fields */
7332  if (direction == GTK_DIR_TAB_FORWARD) {
7333  if (ev_view_next_page (view)) {
7334  schedule_child_focus_in_idle (view, direction);
7335  return TRUE;
7336  }
7337  } else if (direction == GTK_DIR_TAB_BACKWARD) {
7338  if (ev_view_previous_page (view)) {
7339  schedule_child_focus_in_idle (view, direction);
7340  return TRUE;
7341  }
7342  }
7343 
7344  return FALSE;
7345 }
7346 
7347 static gboolean
7348 ev_view_focus (GtkWidget *widget,
7349  GtkDirectionType direction)
7350 {
7351  EvView *view = EV_VIEW (widget);
7352 
7353  if (view->document) {
7354  if (direction == GTK_DIR_TAB_FORWARD || direction == GTK_DIR_TAB_BACKWARD)
7355  return ev_view_focus_next (view, direction);
7356  }
7357 
7358  return GTK_WIDGET_CLASS (ev_view_parent_class)->focus (widget, direction);
7359 }
7360 
7361 static void
7362 ev_view_parent_set (GtkWidget *widget,
7363  GtkWidget *previous_parent)
7364 {
7365  GtkWidget *parent;
7366 
7367  parent = gtk_widget_get_parent (widget);
7368  g_assert (!parent || GTK_IS_SCROLLED_WINDOW (parent));
7369 }
7370 
7371 static void
7373 {
7374  GObjectClass *object_class = G_OBJECT_CLASS (class);
7375  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
7376  GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
7377  GtkBindingSet *binding_set;
7378 
7379  object_class->get_property = ev_view_get_property;
7380  object_class->set_property = ev_view_set_property;
7381  object_class->dispose = ev_view_dispose;
7382  object_class->finalize = ev_view_finalize;
7383 
7384  widget_class->realize = ev_view_realize;
7385  widget_class->draw = ev_view_draw;
7386  widget_class->button_press_event = ev_view_button_press_event;
7387  widget_class->motion_notify_event = ev_view_motion_notify_event;
7388  widget_class->button_release_event = ev_view_button_release_event;
7389  widget_class->key_press_event = ev_view_key_press_event;
7390  widget_class->focus_in_event = ev_view_focus_in;
7391  widget_class->focus_out_event = ev_view_focus_out;
7392  widget_class->get_accessible = ev_view_get_accessible;
7393  widget_class->get_preferred_width = ev_view_get_preferred_width;
7394  widget_class->get_preferred_height = ev_view_get_preferred_height;
7395  widget_class->size_allocate = ev_view_size_allocate;
7396  widget_class->scroll_event = ev_view_scroll_event;
7397  widget_class->enter_notify_event = ev_view_enter_notify_event;
7398  widget_class->leave_notify_event = ev_view_leave_notify_event;
7399  widget_class->style_updated = ev_view_style_updated;
7400  widget_class->drag_data_get = ev_view_drag_data_get;
7401  widget_class->drag_motion = ev_view_drag_motion;
7402  widget_class->popup_menu = ev_view_popup_menu;
7403  widget_class->query_tooltip = ev_view_query_tooltip;
7404  widget_class->screen_changed = ev_view_screen_changed;
7405  widget_class->focus = ev_view_focus;
7406  widget_class->parent_set = ev_view_parent_set;
7407  widget_class->hierarchy_changed = ev_view_hierarchy_changed;
7408 
7409 #if GTK_CHECK_VERSION(3, 20, 0)
7410  gtk_widget_class_set_css_name (widget_class, "evview");
7411 #endif
7412 
7413  container_class->remove = ev_view_remove;
7414  container_class->forall = ev_view_forall;
7415 
7416  class->scroll = ev_view_scroll_internal;
7417  class->move_cursor = ev_view_move_cursor;
7418  class->activate = ev_view_activate;
7419 
7420  g_object_class_install_property (object_class,
7422  g_param_spec_boolean ("is-loading",
7423  "Is Loading",
7424  "Whether the view is loading",
7425  FALSE,
7426  G_PARAM_READABLE |
7427  G_PARAM_STATIC_STRINGS));
7433  g_object_class_install_property (object_class,
7435  g_param_spec_boolean ("can-zoom-in",
7436  "Can Zoom In",
7437  "Whether the view can be zoomed in further",
7438  TRUE,
7439  G_PARAM_READABLE |
7440  G_PARAM_STATIC_STRINGS));
7446  g_object_class_install_property (object_class,
7448  g_param_spec_boolean ("can-zoom-out",
7449  "Can Zoom Out",
7450  "Whether the view can be zoomed out further",
7451  TRUE,
7452  G_PARAM_READABLE |
7453  G_PARAM_STATIC_STRINGS));
7454 
7455  /* Scrollable interface */
7456  g_object_class_override_property (object_class, PROP_HADJUSTMENT, "hadjustment");
7457  g_object_class_override_property (object_class, PROP_VADJUSTMENT, "vadjustment");
7458  g_object_class_override_property (object_class, PROP_HSCROLL_POLICY, "hscroll-policy");
7459  g_object_class_override_property (object_class, PROP_VSCROLL_POLICY, "vscroll-policy");
7460 
7461  signals[SIGNAL_SCROLL] = g_signal_new ("scroll",
7462  G_TYPE_FROM_CLASS (object_class),
7463  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7464  G_STRUCT_OFFSET (EvViewClass, scroll),
7465  NULL, NULL,
7466  ev_view_marshal_VOID__ENUM_ENUM,
7467  G_TYPE_NONE, 2,
7468  GTK_TYPE_SCROLL_TYPE,
7469  GTK_TYPE_ORIENTATION);
7470  signals[SIGNAL_HANDLE_LINK] = g_signal_new ("handle-link",
7471  G_TYPE_FROM_CLASS (object_class),
7472  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7473  G_STRUCT_OFFSET (EvViewClass, handle_link),
7474  NULL, NULL,
7475  g_cclosure_marshal_VOID__OBJECT,
7476  G_TYPE_NONE, 1,
7477  G_TYPE_OBJECT);
7478  signals[SIGNAL_EXTERNAL_LINK] = g_signal_new ("external-link",
7479  G_TYPE_FROM_CLASS (object_class),
7480  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7481  G_STRUCT_OFFSET (EvViewClass, external_link),
7482  NULL, NULL,
7483  g_cclosure_marshal_VOID__OBJECT,
7484  G_TYPE_NONE, 1,
7485  G_TYPE_OBJECT);
7486  signals[SIGNAL_POPUP_MENU] = g_signal_new ("popup",
7487  G_TYPE_FROM_CLASS (object_class),
7488  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7489  G_STRUCT_OFFSET (EvViewClass, popup_menu),
7490  NULL, NULL,
7491  g_cclosure_marshal_VOID__POINTER,
7492  G_TYPE_NONE, 1,
7493  G_TYPE_POINTER);
7494  signals[SIGNAL_SELECTION_CHANGED] = g_signal_new ("selection-changed",
7495  G_TYPE_FROM_CLASS (object_class),
7496  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7497  G_STRUCT_OFFSET (EvViewClass, selection_changed),
7498  NULL, NULL,
7499  g_cclosure_marshal_VOID__VOID,
7500  G_TYPE_NONE, 0,
7501  G_TYPE_NONE);
7502  signals[SIGNAL_SYNC_SOURCE] = g_signal_new ("sync-source",
7503  G_TYPE_FROM_CLASS (object_class),
7504  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7505  G_STRUCT_OFFSET (EvViewClass, sync_source),
7506  NULL, NULL,
7507  g_cclosure_marshal_VOID__POINTER,
7508  G_TYPE_NONE, 1,
7509  G_TYPE_POINTER);
7510  signals[SIGNAL_ANNOT_ADDED] = g_signal_new ("annot-added",
7511  G_TYPE_FROM_CLASS (object_class),
7512  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7513  G_STRUCT_OFFSET (EvViewClass, annot_added),
7514  NULL, NULL,
7515  g_cclosure_marshal_VOID__OBJECT,
7516  G_TYPE_NONE, 1,
7518  signals[SIGNAL_ANNOT_REMOVED] = g_signal_new ("annot-removed",
7519  G_TYPE_FROM_CLASS (object_class),
7520  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7521  G_STRUCT_OFFSET (EvViewClass, annot_removed),
7522  NULL, NULL,
7523  g_cclosure_marshal_VOID__OBJECT,
7524  G_TYPE_NONE, 1,
7526  signals[SIGNAL_LAYERS_CHANGED] = g_signal_new ("layers-changed",
7527  G_TYPE_FROM_CLASS (object_class),
7528  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7529  G_STRUCT_OFFSET (EvViewClass, layers_changed),
7530  NULL, NULL,
7531  g_cclosure_marshal_VOID__VOID,
7532  G_TYPE_NONE, 0,
7533  G_TYPE_NONE);
7534  signals[SIGNAL_MOVE_CURSOR] = g_signal_new ("move-cursor",
7535  G_TYPE_FROM_CLASS (object_class),
7536  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7537  G_STRUCT_OFFSET (EvViewClass, move_cursor),
7538  NULL, NULL,
7539  ev_view_marshal_BOOLEAN__ENUM_INT_BOOLEAN,
7540  G_TYPE_BOOLEAN, 3,
7541  GTK_TYPE_MOVEMENT_STEP,
7542  G_TYPE_INT,
7543  G_TYPE_BOOLEAN);
7544  signals[SIGNAL_CURSOR_MOVED] = g_signal_new ("cursor-moved",
7545  G_TYPE_FROM_CLASS (object_class),
7546  G_SIGNAL_RUN_LAST,
7547  0,
7548  NULL, NULL,
7549  ev_view_marshal_VOID__INT_INT,
7550  G_TYPE_NONE, 2,
7551  G_TYPE_INT,
7552  G_TYPE_INT);
7553  signals[SIGNAL_ACTIVATE] = g_signal_new ("activate",
7554  G_OBJECT_CLASS_TYPE (object_class),
7555  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
7556  G_STRUCT_OFFSET (EvViewClass, activate),
7557  NULL, NULL,
7558  g_cclosure_marshal_VOID__VOID,
7559  G_TYPE_NONE, 0,
7560  G_TYPE_NONE);
7561  widget_class->activate_signal = signals[SIGNAL_ACTIVATE];
7562 
7563  binding_set = gtk_binding_set_by_class (class);
7564 
7565  add_move_binding_keypad (binding_set, GDK_KEY_Left, 0, GTK_MOVEMENT_VISUAL_POSITIONS, -1);
7566  add_move_binding_keypad (binding_set, GDK_KEY_Right, 0, GTK_MOVEMENT_VISUAL_POSITIONS, 1);
7567  add_move_binding_keypad (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK, GTK_MOVEMENT_WORDS, -1);
7568  add_move_binding_keypad (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK, GTK_MOVEMENT_WORDS, 1);
7569  add_move_binding_keypad (binding_set, GDK_KEY_Up, 0, GTK_MOVEMENT_DISPLAY_LINES, -1);
7570  add_move_binding_keypad (binding_set, GDK_KEY_Down, 0, GTK_MOVEMENT_DISPLAY_LINES, 1);
7571  add_move_binding_keypad (binding_set, GDK_KEY_Home, 0, GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
7572  add_move_binding_keypad (binding_set, GDK_KEY_End, 0, GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
7573  add_move_binding_keypad (binding_set, GDK_KEY_Home, GDK_CONTROL_MASK, GTK_MOVEMENT_BUFFER_ENDS, -1);
7574  add_move_binding_keypad (binding_set, GDK_KEY_End, GDK_CONTROL_MASK, GTK_MOVEMENT_BUFFER_ENDS, 1);
7575 
7576  add_scroll_binding_keypad (binding_set, GDK_KEY_Left, 0, GTK_SCROLL_STEP_BACKWARD, GTK_ORIENTATION_HORIZONTAL);
7577  add_scroll_binding_keypad (binding_set, GDK_KEY_Right, 0, GTK_SCROLL_STEP_FORWARD, GTK_ORIENTATION_HORIZONTAL);
7578  add_scroll_binding_keypad (binding_set, GDK_KEY_Left, GDK_MOD1_MASK, GTK_SCROLL_STEP_DOWN, GTK_ORIENTATION_HORIZONTAL);
7579  add_scroll_binding_keypad (binding_set, GDK_KEY_Right, GDK_MOD1_MASK, GTK_SCROLL_STEP_UP, GTK_ORIENTATION_HORIZONTAL);
7580  add_scroll_binding_keypad (binding_set, GDK_KEY_Up, 0, GTK_SCROLL_STEP_BACKWARD, GTK_ORIENTATION_VERTICAL);
7581  add_scroll_binding_keypad (binding_set, GDK_KEY_Down, 0, GTK_SCROLL_STEP_FORWARD, GTK_ORIENTATION_VERTICAL);
7582  add_scroll_binding_keypad (binding_set, GDK_KEY_Up, GDK_MOD1_MASK, GTK_SCROLL_STEP_DOWN, GTK_ORIENTATION_VERTICAL);
7583  add_scroll_binding_keypad (binding_set, GDK_KEY_Down, GDK_MOD1_MASK, GTK_SCROLL_STEP_UP, GTK_ORIENTATION_VERTICAL);
7584  add_scroll_binding_keypad (binding_set, GDK_KEY_Page_Up, 0, GTK_SCROLL_PAGE_BACKWARD, GTK_ORIENTATION_VERTICAL);
7585  add_scroll_binding_keypad (binding_set, GDK_KEY_Page_Down, 0, GTK_SCROLL_PAGE_FORWARD, GTK_ORIENTATION_VERTICAL);
7586  add_scroll_binding_keypad (binding_set, GDK_KEY_Home, GDK_CONTROL_MASK, GTK_SCROLL_START, GTK_ORIENTATION_VERTICAL);
7587  add_scroll_binding_keypad (binding_set, GDK_KEY_End, GDK_CONTROL_MASK, GTK_SCROLL_END, GTK_ORIENTATION_VERTICAL);
7588 
7589  /* We can't use the bindings defined in GtkWindow for Space and Return,
7590  * because we also have those bindings for scrolling.
7591  */
7592  gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0,
7593  "activate", 0);
7594  gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0,
7595  "activate", 0);
7596  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0,
7597  "activate", 0);
7598  gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0,
7599  "activate", 0);
7600  gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0,
7601  "activate", 0);
7602 
7603  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "scroll", 2,
7604  GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD,
7605  GTK_TYPE_ORIENTATION, GTK_ORIENTATION_VERTICAL);
7606  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, GDK_SHIFT_MASK, "scroll", 2,
7607  GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD,
7608  GTK_TYPE_ORIENTATION, GTK_ORIENTATION_VERTICAL);
7609  gtk_binding_entry_add_signal (binding_set, GDK_KEY_H, 0, "scroll", 2,
7610  GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD,
7611  GTK_TYPE_ORIENTATION, GTK_ORIENTATION_HORIZONTAL);
7612  gtk_binding_entry_add_signal (binding_set, GDK_KEY_J, 0, "scroll", 2,
7613  GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD,
7614  GTK_TYPE_ORIENTATION, GTK_ORIENTATION_VERTICAL);
7615  gtk_binding_entry_add_signal (binding_set, GDK_KEY_K, 0, "scroll", 2,
7616  GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD,
7617  GTK_TYPE_ORIENTATION, GTK_ORIENTATION_VERTICAL);
7618  gtk_binding_entry_add_signal (binding_set, GDK_KEY_L, 0, "scroll", 2,
7619  GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD,
7620  GTK_TYPE_ORIENTATION, GTK_ORIENTATION_HORIZONTAL);
7621  gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "scroll", 2,
7622  GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD,
7623  GTK_TYPE_ORIENTATION, GTK_ORIENTATION_VERTICAL);
7624  gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "scroll", 2,
7625  GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD,
7626  GTK_TYPE_ORIENTATION, GTK_ORIENTATION_VERTICAL);
7627  gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "scroll", 2,
7628  GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD,
7629  GTK_TYPE_ORIENTATION, GTK_ORIENTATION_VERTICAL);
7630  gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_SHIFT_MASK, "scroll", 2,
7631  GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD,
7632  GTK_TYPE_ORIENTATION, GTK_ORIENTATION_VERTICAL);
7633 }
7634 
7635 static void
7637  GParamSpec *pspec)
7638 {
7639  if (view->document)
7641 }
7642 
7643 static void
7644 zoom_gesture_begin_cb (GtkGesture *gesture,
7645  GdkEventSequence *sequence,
7646  EvView *view)
7647 {
7648  view->prev_zoom_gesture_scale = 1;
7649 }
7650 
7651 static void
7652 zoom_gesture_scale_changed_cb (GtkGestureZoom *gesture,
7653  gdouble scale,
7654  EvView *view)
7655 {
7656  gdouble factor;
7657 
7658  view->drag_info.in_drag = FALSE;
7659  view->image_dnd_info.in_drag = FALSE;
7660 
7661  factor = scale - view->prev_zoom_gesture_scale + 1;
7662  view->prev_zoom_gesture_scale = scale;
7664 
7665  gtk_gesture_get_bounding_box_center (GTK_GESTURE (gesture), &view->zoom_center_x, &view->zoom_center_y);
7666 
7667  if ((factor < 1.0 && ev_view_can_zoom_out (view)) ||
7668  (factor >= 1.0 && ev_view_can_zoom_in (view)))
7669  ev_view_zoom (view, factor);
7670 }
7671 
7672 static void
7674 {
7675  GtkStyleContext *context;
7676 #if defined (ENABLE_MULTIMEDIA) && defined (GDK_WINDOWING_X11)
7677  GdkVisual *visual;
7678 #endif
7679 
7680  gtk_widget_set_has_window (GTK_WIDGET (view), TRUE);
7681  gtk_widget_set_can_focus (GTK_WIDGET (view), TRUE);
7682  gtk_widget_set_redraw_on_allocate (GTK_WIDGET (view), FALSE);
7683  gtk_container_set_resize_mode (GTK_CONTAINER (view), GTK_RESIZE_QUEUE);
7684 
7685  context = gtk_widget_get_style_context (GTK_WIDGET (view));
7686  gtk_style_context_add_class (context, "content-view");
7687  gtk_style_context_add_class (context, "view");
7688 
7689 #if defined (ENABLE_MULTIMEDIA) && defined (GDK_WINDOWING_X11)
7690  /* Use always the system visual, instead of the one inherited from the
7691  * window, because gst xvimagesink doesn't work with RGBA visuals.
7692  * See https://bugzilla.gnome.org/show_bug.cgi?id=721148
7693  */
7694  visual = gdk_screen_get_system_visual (gdk_screen_get_default ());
7695  gtk_widget_set_visual (GTK_WIDGET (view), visual);
7696 #endif
7697 
7698  gtk_widget_set_events (GTK_WIDGET (view),
7699  GDK_TOUCH_MASK |
7700  GDK_EXPOSURE_MASK |
7701  GDK_BUTTON_PRESS_MASK |
7702  GDK_BUTTON_RELEASE_MASK |
7703  GDK_SCROLL_MASK |
7704  GDK_SMOOTH_SCROLL_MASK |
7705  GDK_KEY_PRESS_MASK |
7706  GDK_POINTER_MOTION_MASK |
7707  GDK_POINTER_MOTION_HINT_MASK |
7708  GDK_ENTER_NOTIFY_MASK |
7709  GDK_LEAVE_NOTIFY_MASK);
7710 
7711  view->start_page = -1;
7712  view->end_page = -1;
7713  view->spacing = 5;
7714  view->scale = 1.0;
7715  view->current_page = 0;
7716  view->pressed_button = -1;
7717  view->cursor = EV_VIEW_CURSOR_NORMAL;
7718  view->drag_info.in_drag = FALSE;
7720  view->selection_info.selections = NULL;
7721  view->selection_info.in_drag = FALSE;
7722  view->continuous = TRUE;
7723  view->dual_even_left = TRUE;
7724  view->fullscreen = FALSE;
7728  view->find_page = -1;
7729  view->jump_to_find_result = TRUE;
7730  view->highlight_find_results = FALSE;
7732  view->caret_enabled = FALSE;
7733  view->cursor_page = 0;
7734  view->allow_links_change_zoom = TRUE;
7735  view->zoom_center_x = -1;
7736  view->zoom_center_y = -1;
7737 
7738  g_signal_connect (view, "notify::scale-factor",
7739  G_CALLBACK (on_notify_scale_factor), NULL);
7740 
7741  view->zoom_gesture = gtk_gesture_zoom_new (GTK_WIDGET (view));
7742  gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (view->zoom_gesture),
7743  GTK_PHASE_CAPTURE);
7744 
7745  g_signal_connect (view->zoom_gesture, "begin",
7746  G_CALLBACK (zoom_gesture_begin_cb), view);
7747  g_signal_connect (view->zoom_gesture, "scale-changed",
7748  G_CALLBACK (zoom_gesture_scale_changed_cb), view);
7749 }
7750 
7751 /*** Callbacks ***/
7752 
7753 static void
7755  gint new_page)
7756 {
7757  gint x, y;
7758 
7759  view->current_page = new_page;
7761 
7762  ev_view_set_loading (view, FALSE);
7763 
7764  ev_document_misc_get_pointer_position (GTK_WIDGET (view), &x, &y);
7765  ev_view_handle_cursor_over_xy (view, x, y);
7766 
7767  gtk_widget_queue_resize (GTK_WIDGET (view));
7768 }
7769 
7770 static void
7772  cairo_region_t *region,
7773  EvView *view)
7774 {
7775  if (region) {
7776  gdk_window_invalidate_region (gtk_widget_get_window (GTK_WIDGET (view)), region, TRUE);
7777  } else {
7778  gtk_widget_queue_draw (GTK_WIDGET (view));
7779  }
7780 }
7781 
7782 static void
7784  gint old_page,
7785  gint new_page,
7786  EvView *view)
7787 {
7788  if (!view->document)
7789  return;
7790 
7791  if (view->current_page != new_page) {
7792  ev_view_change_page (view, new_page);
7793  } else {
7794  gtk_widget_queue_draw (GTK_WIDGET (view));
7795  }
7796 }
7797 
7798 static void
7799 on_adjustment_value_changed (GtkAdjustment *adjustment,
7800  EvView *view)
7801 {
7802  GtkWidget *widget = GTK_WIDGET (view);
7803  int dx = 0, dy = 0;
7804  gint x, y;
7805  gint value;
7806  GList *l;
7807 
7808  if (!gtk_widget_get_realized (widget))
7809  return;
7810 
7811  if (view->hadjustment) {
7812  value = (gint) gtk_adjustment_get_value (view->hadjustment);
7813  dx = view->scroll_x - value;
7814  view->scroll_x = value;
7815  } else {
7816  view->scroll_x = 0;
7817  }
7818 
7819  if (view->vadjustment) {
7820  value = (gint) gtk_adjustment_get_value (view->vadjustment);
7821  dy = view->scroll_y - value;
7822  view->scroll_y = value;
7823  } else {
7824  view->scroll_y = 0;
7825  }
7826 
7827  for (l = view->children; l && l->data; l = g_list_next (l)) {
7828  EvViewChild *child = (EvViewChild *)l->data;
7829 
7830  child->x += dx;
7831  child->y += dy;
7832  if (gtk_widget_get_visible (child->widget) && gtk_widget_get_visible (widget))
7833  gtk_widget_queue_resize (widget);
7834  }
7835 
7836  for (l = view->window_children; l && l->data; l = g_list_next (l)) {
7837  EvViewWindowChild *child;
7838 
7839  child = (EvViewWindowChild *)l->data;
7840 
7841  ev_view_window_child_move (view, child, child->x + dx, child->y + dy);
7842  }
7843 
7844  if (view->pending_resize) {
7845  gtk_widget_queue_draw (widget);
7846  } else {
7847  gdk_window_scroll (gtk_widget_get_window (widget), dx, dy);
7848  }
7849 
7850  ev_document_misc_get_pointer_position (widget, &x, &y);
7851  ev_view_handle_cursor_over_xy (view, x, y);
7852 
7853  if (view->document)
7855 }
7856 
7857 GtkWidget*
7859 {
7860  GtkWidget *view;
7861 
7862  view = g_object_new (EV_TYPE_VIEW, NULL);
7863 
7864  return view;
7865 }
7866 
7867 static void
7869 {
7870  gboolean inverted_colors;
7871 
7873  view->pixbuf_cache = ev_pixbuf_cache_new (GTK_WIDGET (view), view->model, view->pixbuf_cache_size);
7874  view->page_cache = ev_page_cache_new (view->document);
7875 
7882 
7883  inverted_colors = ev_document_model_get_inverted_colors (view->model);
7884  ev_pixbuf_cache_set_inverted_colors (view->pixbuf_cache, inverted_colors);
7885  g_signal_connect (view->pixbuf_cache, "job-finished", G_CALLBACK (job_finished_cb), view);
7886 }
7887 
7888 static void
7890 {
7891  if (view->pixbuf_cache) {
7892  g_object_unref (view->pixbuf_cache);
7893  view->pixbuf_cache = NULL;
7894  }
7895 
7896  if (view->page_cache) {
7897  g_object_unref (view->page_cache);
7898  view->page_cache = NULL;
7899  }
7900 }
7901 
7915 void
7917  gsize cache_size)
7918 {
7919  if (view->pixbuf_cache_size == cache_size)
7920  return;
7921 
7922  view->pixbuf_cache_size = cache_size;
7923  if (view->pixbuf_cache)
7924  ev_pixbuf_cache_set_max_size (view->pixbuf_cache, cache_size);
7925 
7926  view_update_scale_limits (view);
7927 }
7928 
7936 void
7938  gboolean loading)
7939 {
7940  if (view->loading == loading)
7941  return;
7942 
7943  view->loading = loading;
7944  g_object_notify (G_OBJECT (view), "is-loading");
7945 }
7946 
7955 gboolean
7957 {
7958  return view->loading;
7959 }
7960 
7961 void
7963 {
7964  gint x, y;
7965 
7966  g_return_if_fail (EV_IS_VIEW (view));
7967 
7968  if (view->scroll_info.autoscrolling)
7969  return;
7970 
7971  view->scroll_info.autoscrolling = TRUE;
7973 
7974  ev_document_misc_get_pointer_position (GTK_WIDGET (view), &x, &y);
7975  ev_view_handle_cursor_over_xy (view, x, y);
7976 }
7977 
7978 void
7980 {
7981  gint x, y;
7982 
7983  g_return_if_fail (EV_IS_VIEW (view));
7984 
7985  if (!view->scroll_info.autoscrolling)
7986  return;
7987 
7989  ev_view_autoscroll_pause (view);
7990 
7991  ev_document_misc_get_pointer_position (GTK_WIDGET (view), &x, &y);
7992  ev_view_handle_cursor_over_xy (view, x, y);
7993 }
7994 
7995 static void
7997  GParamSpec *pspec,
7998  EvView *view)
7999 {
8000  EvDocument *document = ev_document_model_get_document (model);
8001 
8002  if (document != view->document) {
8003  gint current_page;
8004 
8005  ev_view_remove_all (view);
8006  clear_caches (view);
8007 
8008  if (view->document) {
8009  g_object_unref (view->document);
8010  }
8011 
8012  view->document = document ? g_object_ref (document) : NULL;
8013  view->find_page = -1;
8014  view->find_result = 0;
8015 
8016  if (view->document) {
8017  if (ev_document_get_n_pages (view->document) <= 0 ||
8019  return;
8020 
8021  ev_view_set_loading (view, FALSE);
8022  setup_caches (view);
8023 
8024  if (view->caret_enabled)
8026  }
8027 
8028  current_page = ev_document_model_get_page (model);
8029  if (view->current_page != current_page) {
8030  ev_view_change_page (view, current_page);
8031  } else {
8033  gtk_widget_queue_resize (GTK_WIDGET (view));
8034  }
8035  view_update_scale_limits (view);
8036  }
8037 }
8038 
8039 static void
8041  GParamSpec *pspec,
8042  EvView *view)
8043 {
8044  gint rotation = ev_document_model_get_rotation (model);
8045 
8046  view->rotation = rotation;
8047 
8048  if (view->pixbuf_cache) {
8052  gtk_widget_queue_resize (GTK_WIDGET (view));
8053  }
8054 
8055  ev_view_remove_all (view);
8056  view_update_scale_limits (view);
8057 
8058  if (rotation != 0)
8059  clear_selection (view);
8060 }
8061 
8062 static void
8064  GParamSpec *pspec,
8065  EvView *view)
8066 {
8067  if (view->pixbuf_cache) {
8068  gboolean inverted_colors;
8069 
8070  inverted_colors = ev_document_model_get_inverted_colors (model);
8071  ev_pixbuf_cache_set_inverted_colors (view->pixbuf_cache, inverted_colors);
8072  gtk_widget_queue_draw (GTK_WIDGET (view));
8073  }
8074 }
8075 
8076 static void
8078  GParamSpec *pspec,
8079  EvView *view)
8080 {
8082 
8083  view->sizing_mode = mode;
8084  if (mode != EV_SIZING_FREE)
8085  gtk_widget_queue_resize (GTK_WIDGET (view));
8086 }
8087 
8088 static void
8090 {
8091  gdouble min_scale;
8092  gdouble max_scale;
8093  gboolean can_zoom_in;
8094  gboolean can_zoom_out;
8095 
8096  min_scale = ev_document_model_get_min_scale (view->model);
8097  max_scale = ev_document_model_get_max_scale (view->model);
8098 
8099  can_zoom_in = (view->scale * ZOOM_IN_FACTOR) <= max_scale;
8100  can_zoom_out = (view->scale * ZOOM_OUT_FACTOR) > min_scale;
8101 
8102  if (can_zoom_in != view->can_zoom_in) {
8103  view->can_zoom_in = can_zoom_in;
8104  g_object_notify (G_OBJECT (view), "can-zoom-in");
8105  }
8106 
8107  if (can_zoom_out != view->can_zoom_out) {
8108  view->can_zoom_out = can_zoom_out;
8109  g_object_notify (G_OBJECT (view), "can-zoom-out");
8110  }
8111 }
8112 
8113 static void
8115  GParamSpec *pspec,
8116  EvView *view)
8117 {
8119 
8120  view->page_layout = layout;
8121 
8123  gtk_widget_queue_resize (GTK_WIDGET (view));
8124 
8125  /* FIXME: if we're keeping the pixbuf cache around, we should extend the
8126  * preload_cache_size to be 2 if dual_page is set.
8127  */
8128 }
8129 
8130 #define EPSILON 0.0000001
8131 static void
8133  GParamSpec *pspec,
8134  EvView *view)
8135 {
8136  gdouble scale = ev_document_model_get_scale (model);
8137 
8138  if (ABS (view->scale - scale) < EPSILON)
8139  return;
8140 
8141  view->scale = scale;
8142 
8143  view->pending_resize = TRUE;
8144  if (view->sizing_mode == EV_SIZING_FREE)
8145  gtk_widget_queue_resize (GTK_WIDGET (view));
8146 
8147  update_can_zoom (view);
8148 }
8149 
8150 static void
8152  GParamSpec *pspec,
8153  EvView *view)
8154 {
8155  update_can_zoom (view);
8156 }
8157 
8158 static void
8160  GParamSpec *pspec,
8161  EvView *view)
8162 {
8163  update_can_zoom (view);
8164 }
8165 
8166 static void
8168  GParamSpec *pspec,
8169  EvView *view)
8170 {
8171  gboolean continuous = ev_document_model_get_continuous (model);
8172 
8173  if (view->document) {
8174  GdkPoint view_point;
8175  GdkRectangle page_area;
8176  GtkBorder border;
8177 
8178  view_point.x = view->scroll_x;
8179  view_point.y = view->scroll_y;
8180  ev_view_get_page_extents (view, view->start_page, &page_area, &border);
8181  _ev_view_transform_view_point_to_doc_point (view, &view_point,
8182  &page_area, &border,
8183  &view->pending_point.x,
8184  &view->pending_point.y);
8185  }
8186  view->continuous = continuous;
8188  gtk_widget_queue_resize (GTK_WIDGET (view));
8189 }
8190 
8191 static void
8193  GParamSpec *pspec,
8194  EvView *view)
8195 {
8198  gtk_widget_queue_resize (GTK_WIDGET (view));
8199 }
8200 
8201 static void
8203  GParamSpec *pspec,
8204  EvView *view)
8205 {
8206  gboolean fullscreen = ev_document_model_get_fullscreen (model);
8207 
8208  view->fullscreen = fullscreen;
8209  gtk_widget_queue_resize (GTK_WIDGET (view));
8210 }
8211 
8212 void
8214  EvDocumentModel *model)
8215 {
8216  g_return_if_fail (EV_IS_VIEW (view));
8217  g_return_if_fail (EV_IS_DOCUMENT_MODEL (model));
8218 
8219  if (model == view->model)
8220  return;
8221 
8222  if (view->model) {
8223  g_signal_handlers_disconnect_by_data (view->model, view);
8224  g_object_unref (view->model);
8225  }
8226  view->model = g_object_ref (model);
8227 
8228  /* Initialize view from model */
8231  view->scale = ev_document_model_get_scale (view->model);
8235  ev_view_document_changed_cb (view->model, NULL, view);
8236 
8237  g_signal_connect (view->model, "notify::document",
8238  G_CALLBACK (ev_view_document_changed_cb),
8239  view);
8240  g_signal_connect (view->model, "notify::rotation",
8241  G_CALLBACK (ev_view_rotation_changed_cb),
8242  view);
8243  g_signal_connect (view->model, "notify::inverted-colors",
8245  view);
8246  g_signal_connect (view->model, "notify::sizing-mode",
8247  G_CALLBACK (ev_view_sizing_mode_changed_cb),
8248  view);
8249  g_signal_connect (view->model, "notify::page-layout",
8250  G_CALLBACK (ev_view_page_layout_changed_cb),
8251  view);
8252  g_signal_connect (view->model, "notify::scale",
8253  G_CALLBACK (ev_view_scale_changed_cb),
8254  view);
8255  g_signal_connect (view->model, "notify::min-scale",
8256  G_CALLBACK (ev_view_min_scale_changed_cb),
8257  view);
8258  g_signal_connect (view->model, "notify::max-scale",
8259  G_CALLBACK (ev_view_max_scale_changed_cb),
8260  view);
8261  g_signal_connect (view->model, "notify::continuous",
8262  G_CALLBACK (ev_view_continuous_changed_cb),
8263  view);
8264  g_signal_connect (view->model, "notify::dual-odd-left",
8265  G_CALLBACK (ev_view_dual_odd_left_changed_cb),
8266  view);
8267  g_signal_connect (view->model, "notify::fullscreen",
8268  G_CALLBACK (ev_view_fullscreen_changed_cb),
8269  view);
8270  g_signal_connect (view->model, "page-changed",
8271  G_CALLBACK (ev_view_page_changed_cb),
8272  view);
8273 
8274  if (view->accessible)
8276  view->model);
8277 }
8278 
8279 static void
8281  gint page,
8282  cairo_region_t *region)
8283 {
8285  region,
8286  page,
8287  view->rotation,
8288  view->scale);
8289 }
8290 
8291 void
8293 {
8296 }
8297 
8298 /*** Zoom and sizing mode ***/
8299 
8300 gboolean
8302 {
8303  return view->can_zoom_in;
8304 }
8305 
8306 gboolean
8308 {
8309  return view->can_zoom_out;
8310 }
8311 
8312 static void
8313 ev_view_zoom (EvView *view, gdouble factor)
8314 {
8315  gdouble scale;
8316 
8317  g_return_if_fail (view->sizing_mode == EV_SIZING_FREE);
8318 
8320  scale = ev_document_model_get_scale (view->model) * factor;
8321  ev_document_model_set_scale (view->model, scale);
8322 }
8323 
8324 void
8326 {
8327  ev_view_zoom (view, ZOOM_IN_FACTOR);
8328 }
8329 
8330 void
8332 {
8333  ev_view_zoom (view, ZOOM_OUT_FACTOR);
8334 }
8335 
8336 static double
8337 zoom_for_size_fit_width (gdouble doc_width,
8338  gdouble doc_height,
8339  int target_width,
8340  int target_height)
8341 {
8342  return (double)target_width / doc_width;
8343 }
8344 
8345 static double
8346 zoom_for_size_fit_height (gdouble doc_width,
8347  gdouble doc_height,
8348  int target_width,
8349  int target_height)
8350 {
8351  return (double)target_height / doc_height;
8352 }
8353 
8354 static double
8355 zoom_for_size_fit_page (gdouble doc_width,
8356  gdouble doc_height,
8357  int target_width,
8358  int target_height)
8359 {
8360  double w_scale;
8361  double h_scale;
8362 
8363  w_scale = (double)target_width / doc_width;
8364  h_scale = (double)target_height / doc_height;
8365 
8366  return MIN (w_scale, h_scale);
8367 }
8368 
8369 static double
8370 zoom_for_size_automatic (GdkScreen *screen,
8371  gdouble doc_width,
8372  gdouble doc_height,
8373  int target_width,
8374  int target_height)
8375 {
8376  double fit_width_scale;
8377  double scale;
8378 
8379  fit_width_scale = zoom_for_size_fit_width (doc_width, doc_height, target_width, target_height);
8380 
8381  if (doc_height < doc_width) {
8382  double fit_height_scale;
8383 
8384  fit_height_scale = zoom_for_size_fit_height (doc_width, doc_height, target_width, target_height);
8385  scale = MIN (fit_width_scale, fit_height_scale);
8386  } else {
8387  double actual_scale;
8388 
8389  actual_scale = ev_document_misc_get_screen_dpi (screen) / 72.0;
8390  scale = MIN (fit_width_scale, actual_scale);
8391  }
8392 
8393  return scale;
8394 }
8395 
8396 static void
8398  int width,
8399  int height)
8400 {
8401  gdouble doc_width, doc_height;
8402  GtkBorder border;
8403  gdouble scale;
8404  gint sb_size;
8405 
8406  ev_document_get_max_page_size (view->document, &doc_width, &doc_height);
8407  if (view->rotation == 90 || view->rotation == 270) {
8408  gdouble tmp;
8409 
8410  tmp = doc_width;
8411  doc_width = doc_height;
8412  doc_height = tmp;
8413  }
8414 
8415  compute_border (view, &border);
8416 
8417  doc_width *= 2;
8418  width -= (2 * (border.left + border.right) + 3 * view->spacing);
8419  height -= (border.top + border.bottom + 2 * view->spacing);
8420 
8421  sb_size = ev_view_get_scrollbar_size (view, GTK_ORIENTATION_VERTICAL);
8422 
8423  switch (view->sizing_mode) {
8424  case EV_SIZING_FIT_WIDTH:
8425  scale = zoom_for_size_fit_width (doc_width, doc_height, width - sb_size, height);
8426  break;
8427  case EV_SIZING_FIT_PAGE:
8428  scale = zoom_for_size_fit_page (doc_width, doc_height, width - sb_size, height);
8429  break;
8430  case EV_SIZING_AUTOMATIC:
8431  scale = zoom_for_size_automatic (gtk_widget_get_screen (GTK_WIDGET (view)),
8432  doc_width, doc_height, width - sb_size, height);
8433  break;
8434  default:
8435  g_assert_not_reached ();
8436  }
8437 
8438  ev_document_model_set_scale (view->model, scale);
8439 }
8440 
8441 static void
8443  int width,
8444  int height)
8445 {
8446  gdouble doc_width, doc_height;
8447  GtkBorder border;
8448  gdouble scale;
8449  gint sb_size;
8450 
8451  ev_document_get_max_page_size (view->document, &doc_width, &doc_height);
8452  if (view->rotation == 90 || view->rotation == 270) {
8453  gdouble tmp;
8454 
8455  tmp = doc_width;
8456  doc_width = doc_height;
8457  doc_height = tmp;
8458  }
8459 
8460  compute_border (view, &border);
8461 
8462  width -= (border.left + border.right + 2 * view->spacing);
8463  height -= (border.top + border.bottom + 2 * view->spacing);
8464 
8465  sb_size = ev_view_get_scrollbar_size (view, GTK_ORIENTATION_VERTICAL);
8466 
8467  switch (view->sizing_mode) {
8468  case EV_SIZING_FIT_WIDTH:
8469  scale = zoom_for_size_fit_width (doc_width, doc_height, width - sb_size, height);
8470  break;
8471  case EV_SIZING_FIT_PAGE:
8472  scale = zoom_for_size_fit_page (doc_width, doc_height, width - sb_size, height);
8473  break;
8474  case EV_SIZING_AUTOMATIC:
8475  scale = zoom_for_size_automatic (gtk_widget_get_screen (GTK_WIDGET (view)),
8476  doc_width, doc_height, width - sb_size, height);
8477  break;
8478  default:
8479  g_assert_not_reached ();
8480  }
8481 
8482  ev_document_model_set_scale (view->model, scale);
8483 }
8484 
8485 static void
8487  int width,
8488  int height)
8489 {
8490  GtkBorder border;
8491  gdouble doc_width, doc_height;
8492  gdouble scale;
8493  gint other_page;
8494  gint sb_size;
8495 
8496  other_page = view->current_page ^ 1;
8497 
8498  /* Find the largest of the two. */
8499  get_doc_page_size (view, view->current_page, &doc_width, &doc_height);
8500  if (other_page < ev_document_get_n_pages (view->document)) {
8501  gdouble width_2, height_2;
8502 
8503  get_doc_page_size (view, other_page, &width_2, &height_2);
8504  if (width_2 > doc_width)
8505  doc_width = width_2;
8506  if (height_2 > doc_height)
8507  doc_height = height_2;
8508  }
8509  compute_border (view, &border);
8510 
8511  doc_width = doc_width * 2;
8512  width -= ((border.left + border.right)* 2 + 3 * view->spacing);
8513  height -= (border.top + border.bottom + 2 * view->spacing);
8514 
8515  switch (view->sizing_mode) {
8516  case EV_SIZING_FIT_WIDTH:
8517  sb_size = ev_view_get_scrollbar_size (view, GTK_ORIENTATION_VERTICAL);
8518  scale = zoom_for_size_fit_width (doc_width, doc_height, width - sb_size, height);
8519  break;
8520  case EV_SIZING_FIT_PAGE:
8521  scale = zoom_for_size_fit_page (doc_width, doc_height, width, height);
8522  break;
8523  case EV_SIZING_AUTOMATIC:
8524  sb_size = ev_view_get_scrollbar_size (view, GTK_ORIENTATION_VERTICAL);
8525  scale = zoom_for_size_automatic (gtk_widget_get_screen (GTK_WIDGET (view)),
8526  doc_width, doc_height, width - sb_size, height);
8527  break;
8528  default:
8529  g_assert_not_reached ();
8530  }
8531 
8532  ev_document_model_set_scale (view->model, scale);
8533 }
8534 
8535 static void
8537  int width,
8538  int height)
8539 {
8540  gdouble doc_width, doc_height;
8541  GtkBorder border;
8542  gdouble scale;
8543  gint sb_size;
8544 
8545  get_doc_page_size (view, view->current_page, &doc_width, &doc_height);
8546 
8547  /* Get an approximate border */
8548  compute_border (view, &border);
8549 
8550  width -= (border.left + border.right + 2 * view->spacing);
8551  height -= (border.top + border.bottom + 2 * view->spacing);
8552 
8553  switch (view->sizing_mode) {
8554  case EV_SIZING_FIT_WIDTH:
8555  sb_size = ev_view_get_scrollbar_size (view, GTK_ORIENTATION_VERTICAL);
8556  scale = zoom_for_size_fit_width (doc_width, doc_height, width - sb_size, height);
8557  break;
8558  case EV_SIZING_FIT_PAGE:
8559  scale = zoom_for_size_fit_page (doc_width, doc_height, width, height);
8560  break;
8561  case EV_SIZING_AUTOMATIC:
8562  sb_size = ev_view_get_scrollbar_size (view, GTK_ORIENTATION_VERTICAL);
8563  scale = zoom_for_size_automatic (gtk_widget_get_screen (GTK_WIDGET (view)),
8564  doc_width, doc_height, width - sb_size, height);
8565  break;
8566  default:
8567  g_assert_not_reached ();
8568  }
8569 
8570  ev_document_model_set_scale (view->model, scale);
8571 }
8572 
8573 static void
8575  int width,
8576  int height)
8577 {
8578  gboolean dual_page;
8579 
8580  g_return_if_fail (EV_IS_VIEW (view));
8581  g_return_if_fail (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
8582  view->sizing_mode == EV_SIZING_FIT_PAGE ||
8583  view->sizing_mode == EV_SIZING_AUTOMATIC);
8584  g_return_if_fail (width >= 0);
8585  g_return_if_fail (height >= 0);
8586 
8587  if (view->document == NULL)
8588  return;
8589 
8590  dual_page = is_dual_page (view, NULL);
8591  if (view->continuous && dual_page)
8592  ev_view_zoom_for_size_continuous_and_dual_page (view, width, height);
8593  else if (view->continuous)
8594  ev_view_zoom_for_size_continuous (view, width, height);
8595  else if (dual_page)
8596  ev_view_zoom_for_size_dual_page (view, width, height);
8597  else
8598  ev_view_zoom_for_size_single_page (view, width, height);
8599 }
8600 
8601 static gboolean
8603  GtkOrientation orientation)
8604 {
8605  GtkRequisition requisition;
8606  GtkAllocation allocation;
8607  double size;
8608 
8609  if (view->sizing_mode == EV_SIZING_FIT_PAGE)
8610  return TRUE;
8611 
8612  if (orientation == GTK_ORIENTATION_HORIZONTAL &&
8613  (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
8614  view->sizing_mode == EV_SIZING_AUTOMATIC))
8615  return TRUE;
8616 
8617  gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
8618  ev_view_size_request (GTK_WIDGET (view), &requisition);
8619 
8620  if (orientation == GTK_ORIENTATION_HORIZONTAL) {
8621  if (requisition.width == 1) {
8622  size = 1.0;
8623  } else {
8624  if (allocation.width > 0.0)
8625  size = (double) requisition.width / allocation.width;
8626  else
8627  size = 1.0;
8628  }
8629  } else {
8630  if (requisition.height == 1) {
8631  size = 1.0;
8632  } else {
8633  if (allocation.height > 0.0)
8634  size = (double) requisition.height / allocation.height;
8635  else
8636  size = 1.0;
8637  }
8638  }
8639 
8640  return size <= 1.0;
8641 }
8642 
8643 /*** Find ***/
8644 static gint
8646 {
8647  return view->find_pages ? g_list_length (view->find_pages[page]) : 0;
8648 }
8649 
8650 static EvRectangle *
8651 ev_view_find_get_result (EvView *view, gint page, gint result)
8652 {
8653  return view->find_pages ? (EvRectangle *) g_list_nth_data (view->find_pages[page], result) : NULL;
8654 }
8655 
8656 static void
8658 {
8659  gint n_results;
8660  gint page = view->find_page;
8661 
8662  n_results = ev_view_find_get_n_results (view, page);
8663 
8664  if (n_results > 0 && view->find_result < n_results) {
8665  EvRectangle *rect;
8666  GdkRectangle view_rect;
8667 
8668  rect = ev_view_find_get_result (view, page, view->find_result);
8669  _ev_view_transform_doc_rect_to_view_rect (view, page, rect, &view_rect);
8670  ensure_rectangle_is_visible (view, &view_rect);
8671  if (view->caret_enabled && view->rotation == 0)
8672  position_caret_cursor_at_doc_point (view, page, rect->x1, rect->y1);
8673 
8674  view->jump_to_find_result = FALSE;
8675  }
8676 }
8677 
8688 static void
8689 jump_to_find_page (EvView *view, EvViewFindDirection direction, gint shift)
8690 {
8691  int n_pages, i;
8692 
8693  n_pages = ev_document_get_n_pages (view->document);
8694 
8695  for (i = 0; i < n_pages; i++) {
8696  int page;
8697 
8698  if (direction == EV_VIEW_FIND_NEXT)
8699  page = view->find_page + i;
8700  else
8701  page = view->find_page - i;
8702  page += shift;
8703 
8704  if (page >= n_pages)
8705  page = page - n_pages;
8706  else if (page < 0)
8707  page = page + n_pages;
8708 
8709  if (view->find_pages && view->find_pages[page]) {
8710  view->find_page = page;
8711  break;
8712  }
8713  }
8714 
8715  if (!view->continuous)
8717 }
8718 
8719 static void
8720 find_job_updated_cb (EvJobFind *job, gint page, EvView *view)
8721 {
8722  ev_view_find_changed (view, ev_job_find_get_results (job), page);
8723 }
8724 
8732 void
8734 {
8735  if (view->find_job == job)
8736  return;
8737 
8738  ev_view_find_cancel (view);
8739  view->find_job = g_object_ref (job);
8740  view->find_page = view->current_page;
8741  view->find_result = 0;
8742 
8743  g_signal_connect (job, "updated", G_CALLBACK (find_job_updated_cb), view);
8744 }
8745 
8754 void
8755 ev_view_find_changed (EvView *view, GList **results, gint page)
8756 {
8757  g_return_if_fail (view->current_page >= 0);
8758 
8759  view->find_pages = results;
8760  if (view->find_page == -1)
8761  view->find_page = view->current_page;
8762 
8763  if (view->jump_to_find_result == TRUE) {
8765  jump_to_find_result (view);
8766  }
8767 
8768  if (view->find_page == page)
8769  gtk_widget_queue_draw (GTK_WIDGET (view));
8770 }
8771 
8781 void
8783  gint page)
8784 {
8785  if (!view->find_job)
8786  return;
8787 
8788  view->find_page = page;
8789  view->find_result = 0;
8791  jump_to_find_result (view);
8792  gtk_widget_queue_draw (GTK_WIDGET (view));
8793 }
8794 
8795 void
8797 {
8798  gint n_results;
8799 
8800  n_results = ev_view_find_get_n_results (view, view->find_page);
8801  view->find_result++;
8802 
8803  if (view->find_result >= n_results) {
8804  view->find_result = 0;
8806  } else if (view->find_page != view->current_page) {
8808  }
8809 
8810  jump_to_find_result (view);
8811  gtk_widget_queue_draw (GTK_WIDGET (view));
8812 }
8813 
8814 void
8816 {
8817  view->find_result--;
8818 
8819  if (view->find_result < 0) {
8821  view->find_result = MAX (0, ev_view_find_get_n_results (view, view->find_page) - 1);
8822  } else if (view->find_page != view->current_page) {
8824  }
8825 
8826  jump_to_find_result (view);
8827  gtk_widget_queue_draw (GTK_WIDGET (view));
8828 }
8829 
8840 void
8841 ev_view_find_set_result (EvView *view, gint page, gint result)
8842 {
8843  view->find_page = page;
8844  view->find_result = result;
8846  jump_to_find_result (view);
8847  gtk_widget_queue_draw (GTK_WIDGET (view));
8848 }
8849 
8850 void
8852 {
8853  /* search string has changed, focus on new search result */
8854  view->jump_to_find_result = TRUE;
8855  ev_view_find_cancel (view);
8856 }
8857 
8858 void
8860 {
8861  view->highlight_find_results = value;
8862  gtk_widget_queue_draw (GTK_WIDGET (view));
8863 }
8864 
8865 void
8867 {
8868  view->find_pages = NULL;
8869  view->find_page = -1;
8870  view->find_result = 0;
8871 
8872  if (!view->find_job)
8873  return;
8874 
8875  g_signal_handlers_disconnect_by_func (view->find_job, find_job_updated_cb, view);
8876  g_object_unref (view->find_job);
8877  view->find_job = NULL;
8878 }
8879 
8880 /*** Synctex ***/
8881 void
8883  EvSourceLink *link)
8884 {
8885  EvMapping *mapping;
8886  gint page;
8887  GdkRectangle view_rect;
8888 
8889  if (!ev_document_has_synctex (view->document))
8890  return;
8891 
8892  mapping = ev_document_synctex_forward_search (view->document, link);
8893  if (!mapping)
8894  return;
8895 
8896  if (view->synctex_result)
8897  g_free (view->synctex_result);
8898  view->synctex_result = mapping;
8899 
8900  page = GPOINTER_TO_INT (mapping->data);
8901  ev_document_model_set_page (view->model, page);
8902 
8903  _ev_view_transform_doc_rect_to_view_rect (view, page, &mapping->area, &view_rect);
8904  ensure_rectangle_is_visible (view, &view_rect);
8905  gtk_widget_queue_draw (GTK_WIDGET (view));
8906 }
8907 
8908 /*** Selections ***/
8909 static gboolean
8910 gdk_rectangle_point_in (GdkRectangle *rectangle,
8911  GdkPoint *point)
8912 {
8913  return rectangle->x <= point->x &&
8914  rectangle->y <= point->y &&
8915  point->x < rectangle->x + rectangle->width &&
8916  point->y < rectangle->y + rectangle->height;
8917 }
8918 
8919 static inline gboolean
8920 gdk_point_equal (GdkPoint *a,
8921  GdkPoint *b)
8922 {
8923  return a->x == b->x && a->y == b->y;
8924 }
8925 
8926 static gboolean
8928  EvSelectionStyle style,
8929  GdkPoint *start,
8930  GdkPoint *stop,
8931  gint *first_page,
8932  gint *last_page)
8933 {
8934  gint start_page, end_page;
8935  gint first, last;
8936  gint i, n_pages;
8937 
8938  n_pages = ev_document_get_n_pages (view->document);
8939 
8940  if (gdk_point_equal (start, stop)) {
8941  start_page = view->start_page;
8942  end_page = view->end_page;
8943  } else if (view->continuous) {
8944  start_page = 0;
8945  end_page = n_pages - 1;
8946  } else if (is_dual_page (view, NULL)) {
8947  start_page = view->start_page;
8948  end_page = view->end_page;
8949  } else {
8950  start_page = view->current_page;
8951  end_page = view->current_page;
8952  }
8953 
8954  first = -1;
8955  last = -1;
8956  for (i = start_page; i <= end_page; i++) {
8957  GdkRectangle page_area;
8958  GtkBorder border;
8959 
8960  ev_view_get_page_extents (view, i, &page_area, &border);
8961  page_area.x -= border.left;
8962  page_area.y -= border.top;
8963  page_area.width += border.left + border.right;
8964  page_area.height += border.top + border.bottom;
8965  if (gdk_rectangle_point_in (&page_area, start) ||
8966  gdk_rectangle_point_in (&page_area, stop)) {
8967  if (first == -1)
8968  first = i;
8969  last = i;
8970  }
8971  }
8972 
8973  if (first != -1 && last != -1) {
8974  *first_page = first;
8975  *last_page = last;
8976 
8977  return TRUE;
8978  }
8979 
8980  return FALSE;
8981 }
8982 
8983 static GList *
8985  EvSelectionStyle style,
8986  GdkPoint *start,
8987  GdkPoint *stop)
8988 {
8989  int i, first, last;
8990  GList *list = NULL;
8991 
8992  /* First figure out the range of pages the selection affects. */
8993  if (!get_selection_page_range (view, style, start, stop, &first, &last))
8994  return list;
8995 
8996  /* Now create a list of EvViewSelection's for the affected
8997  * pages. This could be an empty list, a list of just one
8998  * page or a number of pages.*/
8999  for (i = first; i <= last; i++) {
9000  EvViewSelection *selection;
9001  GdkRectangle page_area;
9002  GtkBorder border;
9003  GdkPoint *point;
9004  gdouble width, height;
9005 
9006  get_doc_page_size (view, i, &width, &height);
9007 
9008  selection = g_slice_new0 (EvViewSelection);
9009  selection->page = i;
9010  selection->style = style;
9011  selection->rect.x1 = selection->rect.y1 = 0;
9012  selection->rect.x2 = width;
9013  selection->rect.y2 = height;
9014 
9015  ev_view_get_page_extents (view, i, &page_area, &border);
9016  if (gdk_rectangle_point_in (&page_area, start))
9017  point = start;
9018  else
9019  point = stop;
9020 
9021  if (i == first) {
9023  &page_area, &border,
9024  &selection->rect.x1,
9025  &selection->rect.y1);
9026  }
9027 
9028  /* If the selection is contained within just one page,
9029  * make sure we don't write 'start' into both points
9030  * in selection->rect. */
9031  if (first == last)
9032  point = stop;
9033 
9034  if (i == last) {
9036  &page_area, &border,
9037  &selection->rect.x2,
9038  &selection->rect.y2);
9039  }
9040 
9041  list = g_list_prepend (list, selection);
9042  }
9043 
9044  return g_list_reverse (list);
9045 }
9046 
9047 /* This function takes the newly calculated list, and figures out which regions
9048  * have changed. It then queues a redraw approporiately.
9049  */
9050 static void
9052  GList *new_list)
9053 {
9054  GList *old_list;
9055  GList *new_list_ptr, *old_list_ptr;
9056 
9057  /* Update the selection */
9059  g_list_free_full (view->selection_info.selections, (GDestroyNotify)selection_free);
9060  view->selection_info.selections = new_list;
9062  g_signal_emit (view, signals[SIGNAL_SELECTION_CHANGED], 0, NULL);
9063 
9064  new_list_ptr = new_list;
9065  old_list_ptr = old_list;
9066 
9067  while (new_list_ptr || old_list_ptr) {
9068  EvViewSelection *old_sel, *new_sel;
9069  int cur_page;
9070  cairo_region_t *region = NULL;
9071 
9072  new_sel = (new_list_ptr) ? (new_list_ptr->data) : NULL;
9073  old_sel = (old_list_ptr) ? (old_list_ptr->data) : NULL;
9074 
9075  /* Assume that the lists are in order, and we run through them
9076  * comparing them, one page at a time. We come out with the
9077  * first page we see. */
9078  if (new_sel && old_sel) {
9079  if (new_sel->page < old_sel->page) {
9080  new_list_ptr = new_list_ptr->next;
9081  old_sel = NULL;
9082  } else if (new_sel->page > old_sel->page) {
9083  old_list_ptr = old_list_ptr->next;
9084  new_sel = NULL;
9085  } else {
9086  new_list_ptr = new_list_ptr->next;
9087  old_list_ptr = old_list_ptr->next;
9088  }
9089  } else if (new_sel) {
9090  new_list_ptr = new_list_ptr->next;
9091  } else if (old_sel) {
9092  old_list_ptr = old_list_ptr->next;
9093  }
9094 
9095  g_assert (new_sel || old_sel);
9096 
9097  /* is the page we're looking at on the screen?*/
9098  cur_page = new_sel ? new_sel->page : old_sel->page;
9099  if (cur_page < view->start_page || cur_page > view->end_page)
9100  continue;
9101 
9102  /* seed the cache with a new page. We are going to need the new
9103  * region too. */
9104  if (new_sel) {
9105  cairo_region_t *tmp_region;
9106 
9108  cur_page,
9109  view->scale);
9110  if (tmp_region)
9111  new_sel->covered_region = cairo_region_reference (tmp_region);
9112  }
9113 
9114  /* Now we figure out what needs redrawing */
9115  if (old_sel && new_sel) {
9116  if (old_sel->covered_region && new_sel->covered_region) {
9117  if (!cairo_region_equal (old_sel->covered_region, new_sel->covered_region)) {
9118  /* Anything that was previously or currently selected may
9119  * have changed */
9120  region = cairo_region_copy (old_sel->covered_region);
9121  cairo_region_union (region, new_sel->covered_region);
9122  }
9123  } else if (old_sel->covered_region) {
9124  region = cairo_region_reference (old_sel->covered_region);
9125  } else if (new_sel->covered_region) {
9126  region = cairo_region_reference (new_sel->covered_region);
9127  }
9128  } else if (old_sel && !new_sel) {
9129  if (old_sel->covered_region && !cairo_region_is_empty (old_sel->covered_region)) {
9130  region = cairo_region_reference (old_sel->covered_region);
9131  }
9132  } else if (!old_sel && new_sel) {
9133  if (new_sel->covered_region && !cairo_region_is_empty (new_sel->covered_region)) {
9134  region = cairo_region_reference (new_sel->covered_region);
9135  }
9136  } else {
9137  g_assert_not_reached ();
9138  }
9139 
9140  /* Redraw the damaged region! */
9141  if (region) {
9142  GdkRectangle page_area;
9143  GtkBorder border;
9144  cairo_region_t *damage_region;
9145  gint i, n_rects;
9146 
9147  ev_view_get_page_extents (view, cur_page, &page_area, &border);
9148 
9149  damage_region = cairo_region_create ();
9150  /* Translate the region and grow it 2 pixels because for some zoom levels
9151  * the area actually drawn by cairo is larger than the selected region, due
9152  * to rounding errors or pixel alignment.
9153  */
9154  n_rects = cairo_region_num_rectangles (region);
9155  for (i = 0; i < n_rects; i++) {
9156  cairo_rectangle_int_t rect;
9157 
9158  cairo_region_get_rectangle (region, i, &rect);
9159  rect.x += page_area.x + border.left - view->scroll_x - 2;
9160  rect.y += page_area.y + border.top - view->scroll_y - 2;
9161  rect.width += 4;
9162  rect.height += 4;
9163  cairo_region_union_rectangle (damage_region, &rect);
9164  }
9165  cairo_region_destroy (region);
9166 
9167  gdk_window_invalidate_region (gtk_widget_get_window (GTK_WIDGET (view)),
9168  damage_region, TRUE);
9169  cairo_region_destroy (damage_region);
9170  }
9171  }
9172 
9174 
9175  /* Free the old list, now that we're done with it. */
9176  g_list_free_full (old_list, (GDestroyNotify)selection_free);
9177 }
9178 
9179 static void
9181  EvSelectionStyle style,
9182  GdkPoint *start,
9183  GdkPoint *stop)
9184 {
9185  merge_selection_region (view, compute_new_selection (view, style, start, stop));
9186 }
9187 
9188 /* Free's the selection. It's up to the caller to queue redraws if needed.
9189  */
9190 static void
9192 {
9193  if (selection->covered_region)
9194  cairo_region_destroy (selection->covered_region);
9195  g_slice_free (EvViewSelection, selection);
9196 }
9197 
9198 static void
9200 {
9201  merge_selection_region (view, NULL);
9202 }
9203 
9204 void
9206 {
9207  GList *selections = NULL;
9208  int n_pages, i;
9209 
9210  /* Disable selection on rotated pages for the 0.4.0 series */
9211  if (view->rotation != 0)
9212  return;
9213 
9214  n_pages = ev_document_get_n_pages (view->document);
9215  for (i = 0; i < n_pages; i++) {
9216  gdouble width, height;
9217  EvViewSelection *selection;
9218 
9219  get_doc_page_size (view, i, &width, &height);
9220 
9221  selection = g_slice_new0 (EvViewSelection);
9222  selection->page = i;
9223  selection->style = EV_SELECTION_STYLE_GLYPH;
9224  selection->rect.x1 = selection->rect.y1 = 0;
9225  selection->rect.x2 = width;
9226  selection->rect.y2 = height;
9227 
9228  selections = g_list_prepend (selections, selection);
9229  }
9230 
9231  merge_selection_region (view, g_list_reverse (selections));
9232 }
9233 
9234 gboolean
9236 {
9237  return view->selection_info.selections != NULL;
9238 }
9239 
9240 void
9242 {
9243  clear_selection (view);
9244 }
9245 
9246 void
9248  GdkPoint *start_point,
9249  GdkPoint *end_point)
9250 {
9251  compute_selections (view, EV_SELECTION_STYLE_GLYPH, start_point, end_point);
9252 }
9253 
9254 static char *
9256 {
9257  GString *text;
9258  GList *l;
9259  gchar *normalized_text;
9260 
9261  text = g_string_new (NULL);
9262 
9264 
9265  for (l = view->selection_info.selections; l != NULL; l = l->next) {
9266  EvViewSelection *selection = (EvViewSelection *)l->data;
9267  EvPage *page;
9268  gchar *tmp;
9269 
9270  page = ev_document_get_page (view->document, selection->page);
9272  page, selection->style,
9273  &(selection->rect));
9274  g_object_unref (page);
9275  g_string_append (text, tmp);
9276  g_free (tmp);
9277  }
9278 
9280 
9281  normalized_text = g_utf8_normalize (text->str, text->len, G_NORMALIZE_NFKC);
9282  g_string_free (text, TRUE);
9283  return normalized_text;
9284 }
9285 
9286 static void
9288  const gchar *text)
9289 {
9290  GtkClipboard *clipboard;
9291 
9292  clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view),
9293  GDK_SELECTION_CLIPBOARD);
9294  gtk_clipboard_set_text (clipboard, text, -1);
9295 }
9296 
9297 void
9299 {
9300  char *text;
9301 
9302  if (!EV_IS_SELECTION (ev_view->document))
9303  return;
9304 
9305  text = get_selected_text (ev_view);
9306  ev_view_clipboard_copy (ev_view, text);
9307  g_free (text);
9308 }
9309 
9310 static void
9311 ev_view_primary_get_cb (GtkClipboard *clipboard,
9312  GtkSelectionData *selection_data,
9313  guint info,
9314  gpointer data)
9315 {
9316  EvView *ev_view = EV_VIEW (data);
9317 
9318  if (ev_view->link_selected) {
9319  gtk_selection_data_set_text (selection_data,
9321  -1);
9322  } else if (EV_IS_SELECTION (ev_view->document) &&
9323  ev_view->selection_info.selections) {
9324  gchar *text;
9325 
9326  text = get_selected_text (ev_view);
9327  if (text) {
9328  gtk_selection_data_set_text (selection_data, text, -1);
9329  g_free (text);
9330  }
9331  }
9332 }
9333 
9334 static void
9335 ev_view_primary_clear_cb (GtkClipboard *clipboard,
9336  gpointer data)
9337 {
9338  EvView *view = EV_VIEW (data);
9339 
9340  clear_selection (view);
9341  clear_link_selected (view);
9342 }
9343 
9344 static void
9346 {
9347  GtkClipboard *clipboard;
9348 
9349  clipboard = gtk_widget_get_clipboard (GTK_WIDGET (ev_view),
9350  GDK_SELECTION_PRIMARY);
9351 
9352  if (ev_view->selection_info.selections || ev_view->link_selected) {
9353  GtkTargetList *target_list;
9354  GtkTargetEntry *targets;
9355  int n_targets;
9356 
9357  target_list = gtk_target_list_new (NULL, 0);
9358  gtk_target_list_add_text_targets (target_list, 0);
9359  targets = gtk_target_table_new_from_list (target_list, &n_targets);
9360  gtk_target_list_unref (target_list);
9361 
9362  gtk_clipboard_set_with_owner (clipboard,
9363  targets, n_targets,
9366  G_OBJECT (ev_view));
9367 
9368  gtk_target_table_free (targets, n_targets);
9369  } else {
9370  if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (ev_view))
9371  gtk_clipboard_clear (clipboard);
9372  }
9373 }
9374 
9375 static void
9377 {
9378  if (view->link_selected) {
9379  g_object_unref (view->link_selected);
9380  view->link_selected = NULL;
9381  }
9382 }
9383 
9384 void
9386  EvLinkAction *action)
9387 {
9388  clear_link_selected (view);
9389 
9391 
9392  view->link_selected = g_object_ref (action);
9394 }
9395 
9396 /*** Cursor operations ***/
9397 static void
9399 {
9400  GdkCursor *cursor = NULL;
9401  GtkWidget *widget;
9402  GdkWindow *window;
9403 
9404  if (view->cursor == new_cursor) {
9405  return;
9406  }
9407 
9408  view->cursor = new_cursor;
9409 
9410  window = gtk_widget_get_window (GTK_WIDGET (view));
9411  widget = gtk_widget_get_toplevel (GTK_WIDGET (view));
9412  cursor = ev_view_cursor_new (gtk_widget_get_display (widget), new_cursor);
9413  gdk_window_set_cursor (window, cursor);
9414  gdk_flush ();
9415  if (cursor)
9416  g_object_unref (cursor);
9417 }
9418 
9419 void
9421 {
9423 }
9424 
9425 void
9427 {
9429 }
9430 
9431 gboolean
9433 {
9434  gint next_page;
9435 
9436  g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
9437 
9438  next_page = go_to_next_page (view, view->current_page);
9439  if (next_page == -1)
9440  return FALSE;
9441 
9442  ev_document_model_set_page (view->model, next_page);
9443 
9444  return TRUE;
9445 }
9446 
9447 gboolean
9449 {
9450  gint prev_page;
9451 
9452  g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
9453 
9454  prev_page = go_to_previous_page (view, view->current_page);
9455  if (prev_page == -1)
9456  return FALSE;
9457 
9458  ev_document_model_set_page (view->model, prev_page);
9459 
9460  return TRUE;
9461 }
9462 
9463 void
9465 {
9466  g_return_if_fail (EV_IS_VIEW (view));
9467 
9468  view->allow_links_change_zoom = allowed;
9469 }
9470 
9471 gboolean
9473 {
9474  g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
9475 
9476  return view->allow_links_change_zoom;
9477 }