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