Bug Summary

File:libview/ev-view.c
Warning:line 377, column 35
Out of bound memory access (accessed memory precedes memory block)

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ev-view.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/libview -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -D LECTORDATADIR="/usr/share/lector" -D G_LOG_DOMAIN="LectorView" -D CAFELOCALEDIR="/usr/share/locale" -D LECTOR_COMPILATION -I .. -I ../libdocument -I .. -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/cail-3.0 -I /usr/include/ctk-3.0/unix-print -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/libview -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-02-18-122410-54188-1 -x c ev-view.c
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2/* this file is part of lector, a cafe document viewer
3 *
4 * Copyright (C) 2004 Red Hat, Inc
5 *
6 * Lector 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 * Lector 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 <ctk/ctk.h>
29#include <cdk/cdkx.h>
30#include <cdk/cdkkeysyms.h>
31
32#include "ev-mapping-list.h"
33#include "ev-document-forms.h"
34#include "ev-document-images.h"
35#include "ev-document-links.h"
36#include "ev-document-layers.h"
37#include "ev-document-misc.h"
38#include "ev-document-text.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
49#define EV_VIEW_CLASS(klass)((((EvViewClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), ((ev_view_get_type ()))))))
(G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_VIEW, EvViewClass)(((EvViewClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), ((ev_view_get_type ())))))
)
50#define EV_IS_VIEW_CLASS(klass)(((__extension__ ({ GTypeClass *__class = (GTypeClass*) ((klass
)); GType __t = ((ev_view_get_type ())); gboolean __r; if (!__class
) __r = (0); else if (__class->g_type == __t) __r = (!(0))
; else __r = g_type_check_class_is_a (__class, __t); __r; }))
))
(G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_VIEW)((__extension__ ({ GTypeClass *__class = (GTypeClass*) ((klass
)); GType __t = ((ev_view_get_type ())); gboolean __r; if (!__class
) __r = (0); else if (__class->g_type == __t) __r = (!(0))
; else __r = g_type_check_class_is_a (__class, __t); __r; }))
)
)
51#define EV_VIEW_GET_CLASS(obj)((((EvViewClass*) (((GTypeInstance*) ((obj)))->g_class)))) (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_VIEW, EvViewClass)(((EvViewClass*) (((GTypeInstance*) ((obj)))->g_class))))
52
53enum {
54 SIGNAL_SCROLL,
55 SIGNAL_HANDLE_LINK,
56 SIGNAL_EXTERNAL_LINK,
57 SIGNAL_POPUP_MENU,
58 SIGNAL_SELECTION_CHANGED,
59 SIGNAL_SYNC_SOURCE,
60 SIGNAL_ANNOT_ADDED,
61 SIGNAL_ANNOT_REMOVED,
62 SIGNAL_LAYERS_CHANGED,
63 SIGNAL_MOVE_CURSOR,
64 SIGNAL_CURSOR_MOVED,
65 N_SIGNALS
66};
67
68enum {
69 TARGET_DND_URI,
70 TARGET_DND_TEXT,
71 TARGET_DND_IMAGE
72};
73
74enum {
75 PROP_0,
76 PROP_IS_LOADING,
77 PROP_HADJUSTMENT,
78 PROP_VADJUSTMENT,
79 PROP_HSCROLL_POLICY,
80 PROP_VSCROLL_POLICY
81};
82
83static guint signals[N_SIGNALS] = { 0 };
84
85typedef enum {
86 EV_VIEW_FIND_NEXT,
87 EV_VIEW_FIND_PREV
88} EvViewFindDirection;
89
90typedef struct {
91 CtkWidget *widget;
92
93 /* View coords */
94 gint x;
95 gint y;
96
97 /* Document */
98 guint page;
99 EvRectangle doc_rect;
100} EvViewChild;
101
102#define ZOOM_IN_FACTOR1.2 1.2
103#define ZOOM_OUT_FACTOR(1.0/1.2) (1.0/ZOOM_IN_FACTOR1.2)
104
105#define SCROLL_TIME150 150
106
107#define EV_STYLE_CLASS_DOCUMENT_PAGE"document-page" "document-page"
108#define EV_STYLE_CLASS_INVERTED"inverted" "inverted"
109
110/*** Scrolling ***/
111static void view_update_range_and_current_page (EvView *view);
112static void ensure_rectangle_is_visible (EvView *view,
113 CdkRectangle *rect);
114
115/*** Geometry computations ***/
116static void compute_border (EvView *view,
117 CtkBorder *border);
118static void get_page_y_offset (EvView *view,
119 int page,
120 int *y_offset);
121static void find_page_at_location (EvView *view,
122 gdouble x,
123 gdouble y,
124 gint *page,
125 gint *x_offset,
126 gint *y_offset);
127/*** Hyperrefs ***/
128static EvLink * ev_view_get_link_at_location (EvView *view,
129 gdouble x,
130 gdouble y);
131static char* tip_from_link (EvView *view,
132 EvLink *link);
133/*** Forms ***/
134static EvFormField *ev_view_get_form_field_at_location (EvView *view,
135 gdouble x,
136 gdouble y);
137
138/*** Annotations ***/
139static EvAnnotation *ev_view_get_annotation_at_location (EvView *view,
140 gdouble x,
141 gdouble y);
142static void show_annotation_windows (EvView *view,
143 gint page);
144static void hide_annotation_windows (EvView *view,
145 gint page);
146/*** CtkWidget implementation ***/
147static void ev_view_size_request_continuous_dual_page (EvView *view,
148 CtkRequisition *requisition);
149static void ev_view_size_request_continuous (EvView *view,
150 CtkRequisition *requisition);
151static void ev_view_size_request_dual_page (EvView *view,
152 CtkRequisition *requisition);
153static void ev_view_size_request_single_page (EvView *view,
154 CtkRequisition *requisition);
155static void ev_view_size_request (CtkWidget *widget,
156 CtkRequisition *requisition);
157static void ev_view_size_allocate (CtkWidget *widget,
158 CtkAllocation *allocation);
159static gboolean ev_view_scroll_event (CtkWidget *widget,
160 CdkEventScroll *event);
161static gboolean ev_view_draw (CtkWidget *widget,
162 cairo_t *cr);
163static gboolean ev_view_popup_menu (CtkWidget *widget);
164static gboolean ev_view_button_press_event (CtkWidget *widget,
165 CdkEventButton *event);
166static gboolean ev_view_motion_notify_event (CtkWidget *widget,
167 CdkEventMotion *event);
168static gboolean ev_view_button_release_event (CtkWidget *widget,
169 CdkEventButton *event);
170static gboolean ev_view_enter_notify_event (CtkWidget *widget,
171 CdkEventCrossing *event);
172static gboolean ev_view_leave_notify_event (CtkWidget *widget,
173 CdkEventCrossing *event);
174static void ev_view_style_updated (CtkWidget *widget);
175static void ev_view_remove_all (EvView *view);
176
177static AtkObject *ev_view_get_accessible (CtkWidget *widget);
178
179/*** Drawing ***/
180static void highlight_find_results (EvView *view,
181 cairo_t *cr,
182 int page);
183static void highlight_forward_search_results (EvView *view,
184 cairo_t *cr,
185 int page);
186static void draw_one_page (EvView *view,
187 gint page,
188 cairo_t *cr,
189 CdkRectangle *page_area,
190 CtkBorder *border,
191 CdkRectangle *expose_area,
192 gboolean *page_ready);
193static void ev_view_reload_page (EvView *view,
194 gint page,
195 cairo_region_t *region);
196
197/*** Callbacks ***/
198static void ev_view_change_page (EvView *view,
199 gint new_page);
200static void job_finished_cb (EvPixbufCache *pixbuf_cache,
201 cairo_region_t *region,
202 EvView *view);
203static void ev_view_page_changed_cb (EvDocumentModel *model,
204 gint old_page,
205 gint new_page,
206 EvView *view);
207static void on_adjustment_value_changed (CtkAdjustment *adjustment,
208 EvView *view);
209
210/*** GObject ***/
211static void ev_view_finalize (GObject *object);
212static void ev_view_dispose (GObject *object);
213
214/*** Zoom and sizing ***/
215static double zoom_for_size_fit_width (gdouble doc_width,
216 gdouble doc_height,
217 int target_width,
218 int target_height);
219static double zoom_for_size_fit_height (gdouble doc_width,
220 gdouble doc_height,
221 int target_width,
222 int target_height);
223static double zoom_for_size_fit_page (gdouble doc_width,
224 gdouble doc_height,
225 int target_width,
226 int target_height);
227static double zoom_for_size_automatic (CdkScreen *screen,
228 gdouble doc_width,
229 gdouble doc_height,
230 int target_width,
231 int target_height);
232static void ev_view_zoom_for_size (EvView *view,
233 int width,
234 int height);
235static void ev_view_zoom_for_size_continuous_and_dual_page (EvView *view,
236 int width,
237 int height);
238static void ev_view_zoom_for_size_continuous (EvView *view,
239 int width,
240 int height);
241static void ev_view_zoom_for_size_dual_page (EvView *view,
242 int width,
243 int height);
244static void ev_view_zoom_for_size_single_page (EvView *view,
245 int width,
246 int height);
247static gboolean ev_view_page_fits (EvView *view,
248 CtkOrientation orientation);
249/*** Cursors ***/
250static void ev_view_set_cursor (EvView *view,
251 EvViewCursor new_cursor);
252static void ev_view_handle_cursor_over_xy (EvView *view,
253 gint x,
254 gint y);
255
256/*** Find ***/
257static gint ev_view_find_get_n_results (EvView *view,
258 gint page);
259static EvRectangle *ev_view_find_get_result (EvView *view,
260 gint page,
261 gint result);
262static void jump_to_find_result (EvView *view);
263static void jump_to_find_page (EvView *view,
264 EvViewFindDirection direction,
265 gint shift);
266/*** Selection ***/
267static void compute_selections (EvView *view,
268 EvSelectionStyle style,
269 CdkPoint *start,
270 CdkPoint *stop);
271static void extend_selection (EvView *view,
272 CdkPoint *start,
273 CdkPoint *stop);
274static void clear_selection (EvView *view);
275static void clear_link_selected (EvView *view);
276static void selection_free (EvViewSelection *selection);
277static char* get_selected_text (EvView *ev_view);
278static void ev_view_primary_get_cb (CtkClipboard *clipboard,
279 CtkSelectionData *selection_data,
280 guint info,
281 gpointer data);
282static void ev_view_primary_clear_cb (CtkClipboard *clipboard,
283 gpointer data);
284static void ev_view_update_primary_selection (EvView *ev_view);
285
286/*** Caret navigation ***/
287static void ev_view_check_cursor_blink (EvView *ev_view);
288
289G_DEFINE_TYPE_WITH_CODE (EvView, ev_view, CTK_TYPE_CONTAINER,static void ev_view_init (EvView *self); static void ev_view_class_init
(EvViewClass *klass); static GType ev_view_get_type_once (void
); static gpointer ev_view_parent_class = ((void*)0); static gint
EvView_private_offset; static void ev_view_class_intern_init
(gpointer klass) { ev_view_parent_class = g_type_class_peek_parent
(klass); if (EvView_private_offset != 0) g_type_class_adjust_private_offset
(klass, &EvView_private_offset); ev_view_class_init ((EvViewClass
*) klass); } __attribute__ ((__unused__)) static inline gpointer
ev_view_get_instance_private (EvView *self) { return (((gpointer
) ((guint8*) (self) + (glong) (EvView_private_offset)))); } GType
ev_view_get_type (void) { static gsize static_g_define_type_id
= 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&static_g_define_type_id) : ((void*)0
)); (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id
)); }))) { GType g_define_type_id = ev_view_get_type_once ();
(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&static_g_define_type_id) = (g_define_type_id)
) : (void) 0; g_once_init_leave ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType ev_view_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
((ctk_container_get_type ()), g_intern_static_string ("EvView"
), sizeof (EvViewClass), (GClassInitFunc)(void (*)(void)) ev_view_class_intern_init
, sizeof (EvView), (GInstanceInitFunc)(void (*)(void)) ev_view_init
, (GTypeFlags) 0); { {{ const GInterfaceInfo g_implement_interface_info
= { (GInterfaceInitFunc)(void (*)(void)) ((void*)0), ((void*
)0), ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (ctk_scrollable_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
290 G_IMPLEMENT_INTERFACE (CTK_TYPE_SCROLLABLE, NULL))static void ev_view_init (EvView *self); static void ev_view_class_init
(EvViewClass *klass); static GType ev_view_get_type_once (void
); static gpointer ev_view_parent_class = ((void*)0); static gint
EvView_private_offset; static void ev_view_class_intern_init
(gpointer klass) { ev_view_parent_class = g_type_class_peek_parent
(klass); if (EvView_private_offset != 0) g_type_class_adjust_private_offset
(klass, &EvView_private_offset); ev_view_class_init ((EvViewClass
*) klass); } __attribute__ ((__unused__)) static inline gpointer
ev_view_get_instance_private (EvView *self) { return (((gpointer
) ((guint8*) (self) + (glong) (EvView_private_offset)))); } GType
ev_view_get_type (void) { static gsize static_g_define_type_id
= 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&static_g_define_type_id) : ((void*)0
)); (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id
)); }))) { GType g_define_type_id = ev_view_get_type_once ();
(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&static_g_define_type_id) = (g_define_type_id)
) : (void) 0; g_once_init_leave ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType ev_view_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
((ctk_container_get_type ()), g_intern_static_string ("EvView"
), sizeof (EvViewClass), (GClassInitFunc)(void (*)(void)) ev_view_class_intern_init
, sizeof (EvView), (GInstanceInitFunc)(void (*)(void)) ev_view_init
, (GTypeFlags) 0); { {{ const GInterfaceInfo g_implement_interface_info
= { (GInterfaceInitFunc)(void (*)(void)) ((void*)0), ((void*
)0), ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (ctk_scrollable_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
291
292/* HeightToPage cache */
293#define EV_HEIGHT_TO_PAGE_CACHE_KEY"ev-height-to-page-cache" "ev-height-to-page-cache"
294
295static void
296ev_view_build_height_to_page_cache (EvView *view,
297 EvHeightToPageCache *cache)
298{
299 gboolean swap, uniform;
300 int i;
301 double uniform_height, page_height, next_page_height;
302 double saved_height;
303 gdouble u_width, u_height;
304 gint n_pages;
305 EvDocument *document = view->document;
306
307 swap = (view->rotation == 90 || view->rotation == 270);
35
Assuming field 'rotation' is not equal to 90
36
Assuming field 'rotation' is not equal to 270
308
309 uniform = ev_document_is_page_size_uniform (document);
310 n_pages = ev_document_get_n_pages (document);
311
312 g_free (cache->height_to_page);
313 g_free (cache->dual_height_to_page);
314
315 cache->rotation = view->rotation;
316 cache->dual_even_left = view->dual_even_left;
317 cache->height_to_page = g_new0 (gdouble, n_pages + 1)((gdouble *) g_malloc0_n ((n_pages + 1), sizeof (gdouble)));
318 cache->dual_height_to_page = g_new0 (gdouble, n_pages + 2)((gdouble *) g_malloc0_n ((n_pages + 2), sizeof (gdouble)));
319
320 if (uniform)
37
Assuming 'uniform' is 0
38
Taking false branch
321 ev_document_get_page_size (document, 0, &u_width, &u_height);
322
323 saved_height = 0;
324 for (i = 0; i <= n_pages; i++) {
39
Assuming 'i' is <= 'n_pages'
40
Loop condition is true. Entering loop body
325 if (uniform
40.1
'uniform' is 0
) {
41
Taking false branch
326 uniform_height = swap ? u_width : u_height;
327 cache->height_to_page[i] = i * uniform_height;
328 } else {
329 if (i < n_pages) {
42
Assuming 'i' is >= 'n_pages'
43
Taking false branch
330 gdouble w, h;
331
332 ev_document_get_page_size (document, i, &w, &h);
333 page_height = swap ? w : h;
334 } else {
335 page_height = 0;
336 }
337 cache->height_to_page[i] = saved_height;
338 saved_height += page_height;
339 }
340 }
341
342 if (cache->dual_even_left && !uniform
44.1
'uniform' is 0
) {
44
Assuming field 'dual_even_left' is not equal to 0
45
Taking true branch
343 gdouble w, h;
344
345 ev_document_get_page_size (document, 0, &w, &h);
346 saved_height = swap
45.1
'swap' is 0
? w : h;
46
'?' condition is false
347 } else {
348 saved_height = 0;
349 }
350
351 for (i = cache->dual_even_left; i < n_pages + 2; i += 2) {
47
Assuming the condition is true
48
Loop condition is true. Entering loop body
352 if (uniform
48.1
'uniform' is 0
) {
49
Taking false branch
353 uniform_height = swap ? u_width : u_height;
354 cache->dual_height_to_page[i] = ((i + cache->dual_even_left) / 2) * uniform_height;
355 if (i + 1 < n_pages + 2)
356 cache->dual_height_to_page[i + 1] = ((i + cache->dual_even_left) / 2) * uniform_height;
357 } else {
358 if (i + 1 < n_pages) {
50
Assuming the condition is false
51
Taking false branch
359 gdouble w, h;
360
361 ev_document_get_page_size (document, i + 1, &w, &h);
362 next_page_height = swap ? w : h;
363 } else {
364 next_page_height = 0;
365 }
366
367 if (i < n_pages) {
52
Assuming 'i' is < 'n_pages'
53
Taking true branch
368 gdouble w, h;
369
370 ev_document_get_page_size (document, i, &w, &h);
371 page_height = swap
53.1
'swap' is 0
? w : h;
54
'?' condition is false
372 } else {
373 page_height = 0;
374 }
375
376 if (i + 1 < n_pages + 2) {
55
Taking true branch
377 cache->dual_height_to_page[i] = saved_height;
56
Out of bound memory access (accessed memory precedes memory block)
378 cache->dual_height_to_page[i + 1] = saved_height;
379 saved_height += MAX(page_height, next_page_height)(((page_height) > (next_page_height)) ? (page_height) : (next_page_height
))
;
380 } else {
381 cache->dual_height_to_page[i] = saved_height;
382 }
383 }
384 }
385}
386
387static void
388ev_height_to_page_cache_free (EvHeightToPageCache *cache)
389{
390 if (cache->height_to_page) {
391 g_free (cache->height_to_page);
392 cache->height_to_page = NULL((void*)0);
393 }
394
395 if (cache->dual_height_to_page) {
396 g_free (cache->dual_height_to_page);
397 cache->dual_height_to_page = NULL((void*)0);
398 }
399 g_free (cache);
400}
401
402static EvHeightToPageCache *
403ev_view_get_height_to_page_cache (EvView *view)
404{
405 EvHeightToPageCache *cache;
406
407 if (!view->document)
30
Assuming field 'document' is non-null
31
Taking false branch
408 return NULL((void*)0);
409
410 cache = g_object_get_data (G_OBJECT (view->document)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view->document)), (((GType) ((20) << (2))))))))
, EV_HEIGHT_TO_PAGE_CACHE_KEY"ev-height-to-page-cache");
411 if (!cache) {
32
Assuming 'cache' is null
33
Taking true branch
412 cache = g_new0 (EvHeightToPageCache, 1)((EvHeightToPageCache *) g_malloc0_n ((1), sizeof (EvHeightToPageCache
)))
;
413 ev_view_build_height_to_page_cache (view, cache);
34
Calling 'ev_view_build_height_to_page_cache'
414 g_object_set_data_full (G_OBJECT (view->document)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view->document)), (((GType) ((20) << (2))))))))
,
415 EV_HEIGHT_TO_PAGE_CACHE_KEY"ev-height-to-page-cache",
416 cache,
417 (GDestroyNotify)ev_height_to_page_cache_free);
418 }
419
420 return cache;
421}
422
423static void
424ev_view_get_height_to_page (EvView *view,
425 gint page,
426 gint *height,
427 gint *dual_height)
428{
429 EvHeightToPageCache *cache = NULL((void*)0);
430 gdouble h, dh;
431
432 if (!view->height_to_page_cache)
433 return;
434
435 cache = view->height_to_page_cache;
436 if (cache->rotation != view->rotation ||
437 cache->dual_even_left != view->dual_even_left) {
438 ev_view_build_height_to_page_cache (view, cache);
439 }
440
441 if (height) {
442 h = cache->height_to_page[page];
443 *height = (gint)(h * view->scale + 0.5);
444 }
445
446 if (dual_height) {
447 dh = cache->dual_height_to_page[page];
448 *dual_height = (gint)(dh * view->scale + 0.5);
449 }
450}
451
452static gint
453ev_view_get_scrollbar_size (EvView *view,
454 CtkOrientation orientation)
455{
456 CtkWidget *widget = CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
;
457 CtkWidget *sb;
458 CtkWidget *swindow = ctk_widget_get_parent (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
459 CtkAllocation allocation;
460 CtkRequisition req;
461 gint spacing;
462
463 if (!CTK_IS_SCROLLED_WINDOW (swindow)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(swindow)); GType __t = ((ctk_scrolled_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
464 return 0;
465
466 ctk_widget_get_allocation (widget, &allocation);
467
468 if (orientation == CTK_ORIENTATION_VERTICAL) {
469 if (allocation.height >= view->requisition.height)
470 sb = ctk_scrolled_window_get_vscrollbar (CTK_SCROLLED_WINDOW (swindow)((((CtkScrolledWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((swindow)), ((ctk_scrolled_window_get_type (
)))))))
);
471 else
472 return 0;
473 } else {
474 if (allocation.width >= view->requisition.width)
475 sb = ctk_scrolled_window_get_hscrollbar (CTK_SCROLLED_WINDOW (swindow)((((CtkScrolledWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((swindow)), ((ctk_scrolled_window_get_type (
)))))))
);
476 else
477 return 0;
478 }
479
480 ctk_widget_style_get (swindow, "scrollbar_spacing", &spacing, NULL((void*)0));
481 ctk_widget_get_preferred_size (sb, &req, NULL((void*)0));
482
483 return (orientation == CTK_ORIENTATION_VERTICAL ? req.width : req.height) + spacing;
484}
485
486static gboolean
487is_dual_page (EvView *view,
488 gboolean *odd_left_out)
489{
490 gboolean dual = FALSE(0);
491 gboolean odd_left = FALSE(0);
492
493 switch (view->page_layout) {
494 case EV_PAGE_LAYOUT_AUTOMATIC: {
495 CdkWindow *window;
496 CdkMonitor *monitor;
497 CdkDisplay *display;
498 double scale;
499 double doc_width;
500 double doc_height;
501 CtkAllocation allocation;
502
503 window = ctk_widget_get_window (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
504 display = cdk_window_get_display (window);
505 monitor = cdk_display_get_monitor_at_window (display, window);
506
507 scale = ev_document_misc_get_monitor_dpi (monitor) / 72.0;
508
509 ev_document_get_max_page_size (view->document, &doc_width, &doc_height);
510 ctk_widget_get_allocation (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
, &allocation);
511
512 /* If the width is ok and the height is pretty close, try to fit it in */
513 if (ev_document_get_n_pages (view->document) > 1 &&
514 doc_width < doc_height &&
515 allocation.width > (2 * doc_width * scale) &&
516 allocation.height > (doc_height * scale * 0.9)) {
517 odd_left = !view->dual_even_left;
518 dual = TRUE(!(0));
519 }
520 }
521 break;
522 case EV_PAGE_LAYOUT_DUAL:
523 odd_left = !view->dual_even_left;
524 dual = TRUE(!(0));
525 break;
526 case EV_PAGE_LAYOUT_SINGLE:
527 break;
528 default:
529 g_assert_not_reached ()do { g_assertion_message_expr ("LectorView", "ev-view.c", 529
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
530 }
531
532 if (odd_left_out)
533 *odd_left_out = odd_left;
534
535 return dual;
536}
537
538static void
539scroll_to_point (EvView *view,
540 gdouble x,
541 gdouble y,
542 CtkOrientation orientation)
543{
544 gdouble page_size;
545 gdouble upper, lower;
546
547 if (orientation == CTK_ORIENTATION_VERTICAL) {
548 page_size = ctk_adjustment_get_page_size (view->vadjustment);
549 upper = ctk_adjustment_get_upper (view->vadjustment);
550 lower = ctk_adjustment_get_lower (view->vadjustment);
551
552 if (view->continuous) {
553 ctk_adjustment_clamp_page (view->vadjustment,
554 y - view->spacing / 2,
555 y + page_size);
556 } else {
557 ctk_adjustment_set_value (view->vadjustment,
558 CLAMP (y, lower, upper - page_size)(((y) > (upper - page_size)) ? (upper - page_size) : (((y)
< (lower)) ? (lower) : (y)))
);
559 }
560 } else {
561 page_size = ctk_adjustment_get_page_size (view->hadjustment);
562 upper = ctk_adjustment_get_upper (view->hadjustment);
563 lower = ctk_adjustment_get_lower (view->hadjustment);
564
565 if (is_dual_page (view, NULL((void*)0))) {
566 ctk_adjustment_clamp_page (view->hadjustment, x,
567 x + page_size);
568 } else {
569 ctk_adjustment_set_value (view->hadjustment,
570 CLAMP (x, lower, upper - page_size)(((x) > (upper - page_size)) ? (upper - page_size) : (((x)
< (lower)) ? (lower) : (x)))
);
571 }
572 }
573}
574
575static void
576ev_view_scroll_to_page_position (EvView *view, CtkOrientation orientation)
577{
578 gdouble x, y;
579
580 if (!view->document)
581 return;
582
583 if ((orientation == CTK_ORIENTATION_VERTICAL && view->pending_point.y == 0) ||
584 (orientation == CTK_ORIENTATION_HORIZONTAL && view->pending_point.x == 0)) {
585 CdkRectangle page_area;
586 CtkBorder border;
587
588 ev_view_get_page_extents (view, view->current_page, &page_area, &border);
589 x = page_area.x;
590 y = page_area.y;
591 } else {
592 CdkPoint view_point;
593
594 _ev_view_transform_doc_point_to_view_point (view, view->current_page,
595 &view->pending_point, &view_point);
596 x = view_point.x;
597 y = view_point.y;
598 }
599
600 scroll_to_point (view, x, y, orientation);
601}
602
603static void
604view_set_adjustment_values (EvView *view,
605 CtkOrientation orientation)
606{
607 CtkWidget *widget = CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
;
608 CtkAdjustment *adjustment;
609 CtkAllocation allocation;
610 int req_size;
611 int alloc_size;
612 gdouble page_size;
613 gdouble value;
614 gdouble upper;
615 double factor;
616 gint new_value;
617 gdouble zoom_center;
618
619 ctk_widget_get_allocation (widget, &allocation);
620
621 if (orientation == CTK_ORIENTATION_HORIZONTAL) {
622 req_size = view->requisition.width;
623 alloc_size = allocation.width;
624 adjustment = view->hadjustment;
625 zoom_center = view->zoom_center_x;
626 } else {
627 req_size = view->requisition.height;
628 alloc_size = allocation.height;
629 adjustment = view->vadjustment;
630 zoom_center = view->zoom_center_y;
631 }
632
633 if (!adjustment)
634 return;
635
636 factor = 1.0;
637 value = ctk_adjustment_get_value (adjustment);
638 upper = ctk_adjustment_get_upper (adjustment);
639 page_size = ctk_adjustment_get_page_size (adjustment);
640 if (zoom_center < 0)
641 zoom_center = page_size * 0.5;
642
643 switch (view->pending_scroll) {
644 case SCROLL_TO_KEEP_POSITION:
645 case SCROLL_TO_FIND_LOCATION:
646 factor = value / upper;
647 break;
648 case SCROLL_TO_PAGE_POSITION:
649 break;
650 case SCROLL_TO_CENTER:
651 factor = (value + zoom_center) / upper;
652 break;
653 }
654
655 upper = MAX (alloc_size, req_size)(((alloc_size) > (req_size)) ? (alloc_size) : (req_size));
656 page_size = alloc_size;
657
658 ctk_adjustment_set_page_size (adjustment, page_size);
659 ctk_adjustment_set_step_increment (adjustment, alloc_size * 0.1);
660 ctk_adjustment_set_page_increment (adjustment, alloc_size * 0.9);
661 ctk_adjustment_set_lower (adjustment, 0);
662 ctk_adjustment_set_upper (adjustment, upper);
663
664 /*
665 * We add 0.5 to the values before to average out our rounding errors.
666 */
667 switch (view->pending_scroll) {
668 case SCROLL_TO_KEEP_POSITION:
669 case SCROLL_TO_FIND_LOCATION:
670 new_value = CLAMP (upper * factor + 0.5, 0, upper - page_size)(((upper * factor + 0.5) > (upper - page_size)) ? (upper -
page_size) : (((upper * factor + 0.5) < (0)) ? (0) : (upper
* factor + 0.5)))
;
671 ctk_adjustment_set_value (adjustment, (int)new_value);
672 break;
673 case SCROLL_TO_PAGE_POSITION:
674 ev_view_scroll_to_page_position (view, orientation);
675 break;
676 case SCROLL_TO_CENTER:
677 new_value = CLAMP (upper * factor - zoom_center + 0.5, 0, upper - page_size)(((upper * factor - zoom_center + 0.5) > (upper - page_size
)) ? (upper - page_size) : (((upper * factor - zoom_center + 0.5
) < (0)) ? (0) : (upper * factor - zoom_center + 0.5)))
;
678 if (orientation == CTK_ORIENTATION_HORIZONTAL)
679 view->zoom_center_x = -1.0;
680 else
681 view->zoom_center_y = -1.0;
682 ctk_adjustment_set_value (adjustment, (int)new_value);
683 break;
684 }
685}
686
687static void
688view_update_range_and_current_page (EvView *view)
689{
690 gint start = view->start_page;
691 gint end = view->end_page;
692 gboolean odd_left;
693
694 if (ev_document_get_n_pages (view->document) <= 0 ||
695 !ev_document_check_dimensions (view->document))
696 return;
697
698 if (view->continuous) {
699 CdkRectangle current_area, unused, page_area;
700 CtkBorder border;
701 gboolean found = FALSE(0);
702 gint area_max = -1, area;
703 gint best_current_page = -1;
704 int i, j = 0;
705
706 if (!(view->vadjustment && view->hadjustment))
707 return;
708
709 current_area.x = ctk_adjustment_get_value (view->hadjustment);
710 current_area.width = ctk_adjustment_get_page_size (view->hadjustment);
711 current_area.y = ctk_adjustment_get_value (view->vadjustment);
712 current_area.height = ctk_adjustment_get_page_size (view->vadjustment);
713
714 for (i = 0; i < ev_document_get_n_pages (view->document); i++) {
715
716 ev_view_get_page_extents (view, i, &page_area, &border);
717
718 if (cdk_rectangle_intersect (&current_area, &page_area, &unused)) {
719 area = unused.width * unused.height;
720
721 if (!found) {
722 area_max = area;
723 view->start_page = i;
724 found = TRUE(!(0));
725 best_current_page = i;
726 }
727 if (area > area_max) {
728 best_current_page = (area == area_max) ? MIN (i, best_current_page)(((i) < (best_current_page)) ? (i) : (best_current_page)) : i;
729 area_max = area;
730 }
731
732 view->end_page = i;
733 j = 0;
734 } else if (found && view->current_page <= view->end_page) {
735 if (is_dual_page (view, NULL((void*)0)) && j < 1) {
736 /* In dual mode we stop searching
737 * after two consecutive non-visible pages.
738 */
739 j++;
740 continue;
741 }
742 break;
743 }
744 }
745
746 if (view->pending_scroll == SCROLL_TO_KEEP_POSITION) {
747 best_current_page = MAX (best_current_page, view->start_page)(((best_current_page) > (view->start_page)) ? (best_current_page
) : (view->start_page))
;
748
749 if (best_current_page >= 0 && view->current_page != best_current_page) {
750 view->current_page = best_current_page;
751 ev_view_set_loading (view, FALSE(0));
752 ev_document_model_set_page (view->model, best_current_page);
753 }
754 }
755 } else if (is_dual_page (view, &odd_left)) {
756 if (view->current_page % 2 == !odd_left) {
757 view->start_page = view->current_page;
758 if (view->current_page + 1 < ev_document_get_n_pages (view->document))
759 view->end_page = view->start_page + 1;
760 else
761 view->end_page = view->start_page;
762 } else {
763 if (view->current_page < 1)
764 view->start_page = view->current_page;
765 else
766 view->start_page = view->current_page - 1;
767 view->end_page = view->current_page;
768 }
769 } else {
770 view->start_page = view->current_page;
771 view->end_page = view->current_page;
772 }
773
774 if (view->start_page == -1 || view->end_page == -1)
775 return;
776
777 if (start != view->start_page || end != view->end_page) {
778 gint i;
779
780 for (i = start; i < view->start_page && start != -1; i++) {
781 hide_annotation_windows (view, i);
782 }
783
784 for (i = end; i > view->end_page && end != -1; i--) {
785 hide_annotation_windows (view, i);
786 }
787
788 ev_view_check_cursor_blink (view);
789 }
790
791 ev_page_cache_set_page_range (view->page_cache,
792 view->start_page,
793 view->end_page);
794 ev_pixbuf_cache_set_page_range (view->pixbuf_cache,
795 view->start_page,
796 view->end_page,
797 view->selection_info.selections);
798 if (view->accessible)
799 ev_view_accessible_set_page_range (EV_VIEW_ACCESSIBLE (view->accessible)((((EvViewAccessible*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((view->accessible)), ((ev_view_accessible_get_type
()))))))
,
800 view->start_page,
801 view->end_page);
802
803 if (ev_pixbuf_cache_get_surface (view->pixbuf_cache, view->current_page))
804 ctk_widget_queue_draw (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
805}
806
807static void
808set_scroll_adjustment (EvView *view,
809 CtkOrientation orientation,
810 CtkAdjustment *adjustment)
811{
812 CtkAdjustment **to_set;
813 const gchar *prop_name;
814
815 if (orientation == CTK_ORIENTATION_HORIZONTAL) {
816 to_set = &view->hadjustment;
817 prop_name = "hadjustment";
818 } else {
819 to_set = &view->vadjustment;
820 prop_name = "vadjustment";
821 }
822 if (adjustment && adjustment == *to_set)
823 return;
824
825 if (*to_set) {
826 g_signal_handlers_disconnect_by_func (*to_set,g_signal_handlers_disconnect_matched ((*to_set), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), ((gpointer) on_adjustment_value_changed), (view))
827 (gpointer) on_adjustment_value_changed,g_signal_handlers_disconnect_matched ((*to_set), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), ((gpointer) on_adjustment_value_changed), (view))
828 view)g_signal_handlers_disconnect_matched ((*to_set), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), ((gpointer) on_adjustment_value_changed), (view))
;
829 g_object_unref (*to_set);
830 }
831
832 if (!adjustment)
833 adjustment = ctk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
834 g_signal_connect (adjustment, "value_changed",g_signal_connect_data ((adjustment), ("value_changed"), (((GCallback
) (on_adjustment_value_changed))), (view), ((void*)0), (GConnectFlags
) 0)
835 G_CALLBACK (on_adjustment_value_changed),g_signal_connect_data ((adjustment), ("value_changed"), (((GCallback
) (on_adjustment_value_changed))), (view), ((void*)0), (GConnectFlags
) 0)
836 view)g_signal_connect_data ((adjustment), ("value_changed"), (((GCallback
) (on_adjustment_value_changed))), (view), ((void*)0), (GConnectFlags
) 0)
;
837 *to_set = g_object_ref_sink (adjustment)((__typeof__ (adjustment)) (g_object_ref_sink) (adjustment));
838 view_set_adjustment_values (view, orientation);
839
840 g_object_notify (G_OBJECT (view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), (((GType) ((20) << (2))))))))
, prop_name);
841}
842
843static void
844add_scroll_binding_keypad (CtkBindingSet *binding_set,
845 guint keyval,
846 CdkModifierType modifiers,
847 CtkScrollType scroll,
848 CtkOrientation orientation)
849{
850 guint keypad_keyval = keyval - CDK_KEY_Left0xff51 + CDK_KEY_KP_Left0xff96;
851
852 ctk_binding_entry_add_signal (binding_set, keyval, modifiers,
853 "scroll", 2,
854 CTK_TYPE_SCROLL_TYPE(ctk_scroll_type_get_type ()), scroll,
855 CTK_TYPE_ORIENTATION(ctk_orientation_get_type ()), orientation);
856 ctk_binding_entry_add_signal (binding_set, keypad_keyval, modifiers,
857 "scroll", 2,
858 CTK_TYPE_SCROLL_TYPE(ctk_scroll_type_get_type ()), scroll,
859 CTK_TYPE_ORIENTATION(ctk_orientation_get_type ()), orientation);
860}
861
862static gdouble
863compute_scroll_increment (EvView *view,
864 CtkScrollType scroll)
865{
866 CtkWidget *widget = CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
;
867 CtkAdjustment *adjustment = view->vadjustment;
868 cairo_region_t *text_region, *region;
869 CtkAllocation allocation;
870 gint page;
871 CdkRectangle rect;
872 EvRectangle doc_rect;
873 CdkRectangle page_area;
874 CtkBorder border;
875 gdouble fraction = 1.0;
876
877 if (scroll != CTK_SCROLL_PAGE_BACKWARD && scroll != CTK_SCROLL_PAGE_FORWARD)
878 return ctk_adjustment_get_page_size (adjustment);
879
880 page = scroll == CTK_SCROLL_PAGE_BACKWARD ? view->start_page : view->end_page;
881
882 text_region = ev_page_cache_get_text_mapping (view->page_cache, page);
883 if (!text_region || cairo_region_is_empty (text_region))
884 return ctk_adjustment_get_page_size (adjustment);
885
886 ctk_widget_get_allocation (widget, &allocation);
887 ev_view_get_page_extents (view, page, &page_area, &border);
888 rect.x = page_area.x + view->scroll_x;
889 rect.y = view->scroll_y + (scroll == CTK_SCROLL_PAGE_BACKWARD ? 5 : allocation.height - 5);
890 rect.width = page_area.width;
891 rect.height = 1;
892 _ev_view_transform_view_rect_to_doc_rect (view, &rect, &page_area, &doc_rect);
893
894 /* Convert the doc rectangle into a CdkRectangle */
895 rect.x = doc_rect.x1;
896 rect.y = doc_rect.y1;
897 rect.width = doc_rect.x2 - doc_rect.x1;
898 rect.height = MAX (1, doc_rect.y2 - doc_rect.y1)(((1) > (doc_rect.y2 - doc_rect.y1)) ? (1) : (doc_rect.y2 -
doc_rect.y1))
;
899 region = cairo_region_create_rectangle (&rect);
900
901 cairo_region_intersect (region, text_region);
902 if (cairo_region_num_rectangles (region)) {
903 EvRenderContext *rc;
904 EvPage *ev_page;
905 cairo_region_t *sel_region;
906
907 cairo_region_get_rectangle (region, 0, &rect);
908 ev_page = ev_document_get_page (view->document, page);
909 rc = ev_render_context_new (ev_page, view->rotation, view->scale);
910 g_object_unref (ev_page);
911 /* Get the selection region to know the height of the line */
912 doc_rect.x1 = doc_rect.x2 = rect.x + 0.5;
913 doc_rect.y1 = doc_rect.y2 = rect.y + 0.5;
914
915 ev_document_doc_mutex_lock ();
916 sel_region = ev_selection_get_selection_region (EV_SELECTION (view->document)((((EvSelection*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view->document)), ((ev_selection_get_type ()))))))
,
917 rc, EV_SELECTION_STYLE_LINE,
918 &doc_rect);
919 ev_document_doc_mutex_unlock ();
920
921 g_object_unref (rc);
922
923 if (cairo_region_num_rectangles (sel_region) > 0) {
924 cairo_region_get_rectangle (sel_region, 0, &rect);
925 fraction = 1 - (rect.height / ctk_adjustment_get_page_size (adjustment));
926 }
927 cairo_region_destroy (sel_region);
928 }
929 cairo_region_destroy (region);
930
931 return ctk_adjustment_get_page_size (adjustment) * fraction;
932
933}
934
935void
936ev_view_scroll (EvView *view,
937 CtkScrollType scroll,
938 gboolean horizontal)
939{
940 CtkAdjustment *adjustment;
941 double value, increment;
942 gdouble upper, lower;
943 gdouble page_size;
944 gdouble step_increment;
945 gboolean first_page = FALSE(0);
946 gboolean last_page = FALSE(0);
947
948 if (view->key_binding_handled)
949 return;
950
951 view->jump_to_find_result = FALSE(0);
952
953 if ((!horizontal && ev_view_page_fits (view, CTK_ORIENTATION_VERTICAL)) ||
954 (horizontal && ev_view_page_fits (view, CTK_ORIENTATION_HORIZONTAL))) {
955 switch (scroll) {
956 case CTK_SCROLL_PAGE_BACKWARD:
957 case CTK_SCROLL_STEP_BACKWARD:
958 ev_view_previous_page (view);
959 break;
960 case CTK_SCROLL_PAGE_FORWARD:
961 case CTK_SCROLL_STEP_FORWARD:
962 ev_view_next_page (view);
963 break;
964 default:
965 break;
966 }
967 return;
968 }
969
970 /* Assign values for increment and vertical adjustment */
971 adjustment = horizontal ? view->hadjustment : view->vadjustment;
972 value = ctk_adjustment_get_value (adjustment);
973 upper = ctk_adjustment_get_upper (adjustment);
974 lower = ctk_adjustment_get_lower (adjustment);
975 page_size = ctk_adjustment_get_page_size (adjustment);
976 step_increment = ctk_adjustment_get_step_increment (adjustment);
977
978 /* Assign boolean for first and last page */
979 if (view->current_page == 0)
980 first_page = TRUE(!(0));
981 if (view->current_page == ev_document_get_n_pages (view->document) - 1)
982 last_page = TRUE(!(0));
983
984 switch (scroll) {
985 case CTK_SCROLL_PAGE_BACKWARD:
986 /* Do not jump backwards if at the first page */
987 if (value == lower && first_page) {
988 /* Do nothing */
989 /* At the top of a page, assign the upper bound limit of previous page */
990 } else if (value == lower) {
991 value = upper - page_size;
992 ev_view_previous_page (view);
993 /* Jump to the top */
994 } else {
995 increment = compute_scroll_increment (view, CTK_SCROLL_PAGE_BACKWARD);
996 value = MAX (value - increment, lower)(((value - increment) > (lower)) ? (value - increment) : (
lower))
;
997 }
998 break;
999 case CTK_SCROLL_PAGE_FORWARD:
1000 /* Do not jump forward if at the last page */
1001 if (value == (upper - page_size) && last_page) {
1002 /* Do nothing */
1003 /* At the bottom of a page, assign the lower bound limit of next page */
1004 } else if (value == (upper - page_size)) {
1005 value = 0;
1006 ev_view_next_page (view);
1007 /* Jump to the bottom */
1008 } else {
1009 increment = compute_scroll_increment (view, CTK_SCROLL_PAGE_FORWARD);
1010 value = MIN (value + increment, upper - page_size)(((value + increment) < (upper - page_size)) ? (value + increment
) : (upper - page_size))
;
1011 }
1012 break;
1013 case CTK_SCROLL_STEP_BACKWARD:
1014 value -= step_increment;
1015 break;
1016 case CTK_SCROLL_STEP_FORWARD:
1017 value += step_increment;
1018 break;
1019 case CTK_SCROLL_STEP_DOWN:
1020 value -= step_increment / 10;
1021 break;
1022 case CTK_SCROLL_STEP_UP:
1023 value += step_increment / 10;
1024 break;
1025 default:
1026 break;
1027 }
1028
1029 value = CLAMP (value, lower, upper - page_size)(((value) > (upper - page_size)) ? (upper - page_size) : (
((value) < (lower)) ? (lower) : (value)))
;
1030
1031 ctk_adjustment_set_value (adjustment, value);
1032}
1033
1034static void
1035ev_view_scroll_internal (EvView *view,
1036 CtkScrollType scroll,
1037 CtkOrientation orientation)
1038{
1039 ev_view_scroll (view, scroll, orientation == CTK_ORIENTATION_HORIZONTAL);
1040}
1041
1042#define MARGIN5 5
1043
1044static void
1045ensure_rectangle_is_visible (EvView *view, CdkRectangle *rect)
1046{
1047 CtkWidget *widget = CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
;
1048 CtkAdjustment *adjustment;
1049 CtkAllocation allocation;
1050 gdouble adj_value;
1051 int value;
1052
1053 view->pending_scroll = SCROLL_TO_FIND_LOCATION;
1054
1055 ctk_widget_get_allocation (widget, &allocation);
1056
1057 adjustment = view->vadjustment;
1058 adj_value = ctk_adjustment_get_value (adjustment);
1059
1060 if (rect->y < adj_value) {
1061 value = MAX (ctk_adjustment_get_lower (adjustment), rect->y - MARGIN)(((ctk_adjustment_get_lower (adjustment)) > (rect->y - 5
)) ? (ctk_adjustment_get_lower (adjustment)) : (rect->y - 5
))
;
1062 ctk_adjustment_set_value (view->vadjustment, value);
1063 } else if (rect->y + rect->height > adj_value + allocation.height) {
1064 value = MIN (ctk_adjustment_get_upper (adjustment), rect->y + rect->height -(((ctk_adjustment_get_upper (adjustment)) < (rect->y + rect
->height - allocation.height + 5)) ? (ctk_adjustment_get_upper
(adjustment)) : (rect->y + rect->height - allocation.height
+ 5))
1065 allocation.height + MARGIN)(((ctk_adjustment_get_upper (adjustment)) < (rect->y + rect
->height - allocation.height + 5)) ? (ctk_adjustment_get_upper
(adjustment)) : (rect->y + rect->height - allocation.height
+ 5))
;
1066 ctk_adjustment_set_value (view->vadjustment, value);
1067 }
1068
1069 adjustment = view->hadjustment;
1070 adj_value = ctk_adjustment_get_value (adjustment);
1071
1072 if (rect->x < adj_value) {
1073 value = MAX (ctk_adjustment_get_lower (adjustment), rect->x - MARGIN)(((ctk_adjustment_get_lower (adjustment)) > (rect->x - 5
)) ? (ctk_adjustment_get_lower (adjustment)) : (rect->x - 5
))
;
1074 ctk_adjustment_set_value (view->hadjustment, value);
1075 } else if (rect->x + rect->height > adj_value + allocation.width) {
1076 value = MIN (ctk_adjustment_get_upper (adjustment), rect->x + rect->width -(((ctk_adjustment_get_upper (adjustment)) < (rect->x + rect
->width - allocation.width + 5)) ? (ctk_adjustment_get_upper
(adjustment)) : (rect->x + rect->width - allocation.width
+ 5))
1077 allocation.width + MARGIN)(((ctk_adjustment_get_upper (adjustment)) < (rect->x + rect
->width - allocation.width + 5)) ? (ctk_adjustment_get_upper
(adjustment)) : (rect->x + rect->width - allocation.width
+ 5))
;
1078 ctk_adjustment_set_value (view->hadjustment, value);
1079 }
1080}
1081
1082/*** Geometry computations ***/
1083
1084static void
1085compute_border (EvView *view, CtkBorder *border)
1086{
1087 CtkWidget *widget = CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
;
1088 CtkStyleContext *context = ctk_widget_get_style_context (widget);
1089 CtkStateFlags state = ctk_widget_get_state_flags (widget);
1090
1091 ctk_style_context_save (context);
1092 ctk_style_context_add_class (context, EV_STYLE_CLASS_DOCUMENT_PAGE"document-page");
1093 ctk_style_context_get_border (context, state, border);
1094 ctk_style_context_restore (context);
1095}
1096
1097void
1098_get_page_size_for_scale_and_rotation (EvDocument *document,
1099 gint page,
1100 gdouble scale,
1101 gint rotation,
1102 gint *page_width,
1103 gint *page_height)
1104{
1105 gdouble w, h;
1106 gint width, height;
1107
1108 ev_document_get_page_size (document, page, &w, &h);
1109
1110 width = (gint)(w * scale + 0.5);
1111 height = (gint)(h * scale + 0.5);
1112
1113 if (page_width)
1114 *page_width = (rotation == 0 || rotation == 180) ? width : height;
1115 if (page_height)
1116 *page_height = (rotation == 0 || rotation == 180) ? height : width;
1117}
1118
1119static void
1120ev_view_get_page_size (EvView *view,
1121 gint page,
1122 gint *page_width,
1123 gint *page_height)
1124{
1125 _get_page_size_for_scale_and_rotation (view->document,
1126 page,
1127 view->scale,
1128 view->rotation,
1129 page_width,
1130 page_height);
1131}
1132
1133static void
1134ev_view_get_max_page_size (EvView *view,
1135 gint *max_width,
1136 gint *max_height)
1137{
1138 double w, h;
1139 gint width, height;
1140
1141 ev_document_get_max_page_size (view->document, &w, &h);
1142
1143 width = (gint)(w * view->scale + 0.5);
1144 height = (gint)(h * view->scale + 0.5);
1145
1146 if (max_width)
1147 *max_width = (view->rotation == 0 || view->rotation == 180) ? width : height;
1148 if (max_height)
1149 *max_height = (view->rotation == 0 || view->rotation == 180) ? height : width;
1150}
1151
1152static void
1153get_page_y_offset (EvView *view, int page, int *y_offset)
1154{
1155 int offset = 0;
1156 CtkBorder border;
1157 gboolean odd_left;
1158
1159 g_return_if_fail (y_offset != NULL)do { if ((y_offset != ((void*)0))) { } else { g_return_if_fail_warning
("LectorView", ((const char*) (__func__)), "y_offset != NULL"
); return; } } while (0)
;
1160
1161 compute_border (view, &border);
1162
1163 if (is_dual_page (view, &odd_left)) {
1164 ev_view_get_height_to_page (view, page, NULL((void*)0), &offset);
1165 offset += ((page + !odd_left) / 2 + 1) * view->spacing +
1166 ((page + !odd_left) / 2 ) * (border.top + border.bottom);
1167 } else {
1168 ev_view_get_height_to_page (view, page, &offset, NULL((void*)0));
1169 offset += (page + 1) * view->spacing + page * (border.top + border.bottom);
1170 }
1171
1172 *y_offset = offset;
1173 return;
1174}
1175
1176gboolean
1177ev_view_get_page_extents (EvView *view,
1178 gint page,
1179 CdkRectangle *page_area,
1180 CtkBorder *border)
1181{
1182 CtkWidget *widget;
1183 int width, height;
1184 CtkAllocation allocation;
1185
1186 widget = CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
;
1187 ctk_widget_get_allocation (widget, &allocation);
1188
1189 /* Get the size of the page */
1190 ev_view_get_page_size (view, page, &width, &height);
1191 compute_border (view, border);
1192 page_area->width = width + border->left + border->right;
1193 page_area->height = height + border->top + border->bottom;
1194
1195 if (view->continuous) {
1196 gint max_width;
1197 gint x, y;
1198 gboolean odd_left;
1199
1200 ev_view_get_max_page_size (view, &max_width, NULL((void*)0));
1201 max_width = max_width + border->left + border->right;
1202 /* Get the location of the bounding box */
1203 if (is_dual_page (view, &odd_left)) {
1204 x = view->spacing + ((page % 2 == !odd_left) ? 0 : 1) * (max_width + view->spacing);
1205 x = x + MAX (0, allocation.width - (max_width * 2 + view->spacing * 3))(((0) > (allocation.width - (max_width * 2 + view->spacing
* 3))) ? (0) : (allocation.width - (max_width * 2 + view->
spacing * 3)))
/ 2;
1206 if (page % 2 == !odd_left)
1207 x = x + (max_width - width - border->left - border->right);
1208 } else {
1209 x = view->spacing;
1210 x = x + MAX (0, allocation.width - (width + view->spacing * 2))(((0) > (allocation.width - (width + view->spacing * 2)
)) ? (0) : (allocation.width - (width + view->spacing * 2)
))
/ 2;
1211 }
1212
1213 get_page_y_offset (view, page, &y);
1214
1215 page_area->x = x;
1216 page_area->y = y;
1217 } else {
1218 gint x, y;
1219 gboolean odd_left;
1220
1221 if (is_dual_page (view, &odd_left)) {
1222 gint width_2, height_2;
1223 gint max_width = width;
1224 gint max_height = height;
1225 CtkBorder overall_border;
1226 gint other_page;
1227
1228 other_page = (page % 2 == !odd_left) ? page + 1: page - 1;
1229
1230 /* First, we get the bounding box of the two pages */
1231 if (other_page < ev_document_get_n_pages (view->document)
1232 && (0 <= other_page)) {
1233 ev_view_get_page_size (view, other_page,
1234 &width_2, &height_2);
1235 if (width_2 > width)
1236 max_width = width_2;
1237 if (height_2 > height)
1238 max_height = height_2;
1239 }
1240 compute_border (view, &overall_border);
1241
1242 /* Find the offsets */
1243 x = view->spacing;
1244 y = view->spacing;
1245
1246 /* Adjust for being the left or right page */
1247 if (page % 2 == !odd_left)
1248 x = x + max_width - width;
1249 else
1250 x = x + (max_width + overall_border.left + overall_border.right) + view->spacing;
1251
1252 y = y + (max_height - height)/2;
1253
1254 /* Adjust for extra allocation */
1255 x = x + MAX (0, allocation.width -(((0) > (allocation.width - ((max_width + overall_border.left
+ overall_border.right) * 2 + view->spacing * 3))) ? (0) :
(allocation.width - ((max_width + overall_border.left + overall_border
.right) * 2 + view->spacing * 3)))
1256 ((max_width + overall_border.left + overall_border.right) * 2 + view->spacing * 3))(((0) > (allocation.width - ((max_width + overall_border.left
+ overall_border.right) * 2 + view->spacing * 3))) ? (0) :
(allocation.width - ((max_width + overall_border.left + overall_border
.right) * 2 + view->spacing * 3)))
/2;
1257 y = y + MAX (0, allocation.height - (height + view->spacing * 2))(((0) > (allocation.height - (height + view->spacing * 2
))) ? (0) : (allocation.height - (height + view->spacing *
2)))
/2;
1258 } else {
1259 x = view->spacing;
1260 y = view->spacing;
1261
1262 /* Adjust for extra allocation */
1263 x = x + MAX (0, allocation.width - (width + border->left + border->right + view->spacing * 2))(((0) > (allocation.width - (width + border->left + border
->right + view->spacing * 2))) ? (0) : (allocation.width
- (width + border->left + border->right + view->spacing
* 2)))
/2;
1264 y = y + MAX (0, allocation.height - (height + border->top + border->bottom + view->spacing * 2))(((0) > (allocation.height - (height + border->top + border
->bottom + view->spacing * 2))) ? (0) : (allocation.height
- (height + border->top + border->bottom + view->spacing
* 2)))
/2;
1265 }
1266
1267 page_area->x = x;
1268 page_area->y = y;
1269 }
1270
1271 return TRUE(!(0));
1272}
1273
1274static void
1275get_doc_page_size (EvView *view,
1276 gint page,
1277 gdouble *width,
1278 gdouble *height)
1279{
1280 double w, h;
1281
1282 ev_document_get_page_size (view->document, page, &w, &h);
1283 if (view->rotation == 0 || view->rotation == 180) {
1284 if (width) *width = w;
1285 if (height) *height = h;
1286 } else {
1287 if (width) *width = h;
1288 if (height) *height = w;
1289 }
1290}
1291
1292void
1293_ev_view_transform_view_point_to_doc_point (EvView *view,
1294 CdkPoint *view_point,
1295 CdkRectangle *page_area,
1296 double *doc_point_x,
1297 double *doc_point_y)
1298{
1299 *doc_point_x = (double) (view_point->x - page_area->x) / view->scale;
1300 *doc_point_y = (double) (view_point->y - page_area->y) / view->scale;
1301}
1302
1303void
1304_ev_view_transform_view_rect_to_doc_rect (EvView *view,
1305 CdkRectangle *view_rect,
1306 CdkRectangle *page_area,
1307 EvRectangle *doc_rect)
1308{
1309 doc_rect->x1 = (double) (view_rect->x - page_area->x) / view->scale;
1310 doc_rect->y1 = (double) (view_rect->y - page_area->y) / view->scale;
1311 doc_rect->x2 = doc_rect->x1 + (double) view_rect->width / view->scale;
1312 doc_rect->y2 = doc_rect->y1 + (double) view_rect->height / view->scale;
1313}
1314
1315void
1316_ev_view_transform_doc_point_to_view_point (EvView *view,
1317 int page,
1318 EvPoint *doc_point,
1319 CdkPoint *view_point)
1320{
1321 CdkRectangle page_area;
1322 CtkBorder border;
1323 double x, y, view_x, view_y;
1324 gdouble width, height;
1325
1326 get_doc_page_size (view, page, &width, &height);
1327
1328 if (view->rotation == 0) {
1329 x = doc_point->x;
1330 y = doc_point->y;
1331 } else if (view->rotation == 90) {
1332 x = width - doc_point->y;
1333 y = doc_point->x;
1334 } else if (view->rotation == 180) {
1335 x = width - doc_point->x;
1336 y = height - doc_point->y;
1337 } else if (view->rotation == 270) {
1338 x = doc_point->y;
1339 y = height - doc_point->x;
1340 } else {
1341 g_assert_not_reached ()do { g_assertion_message_expr ("LectorView", "ev-view.c", 1341
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1342 }
1343
1344 ev_view_get_page_extents (view, page, &page_area, &border);
1345
1346 view_x = CLAMP (x * view->scale, 0, page_area.width)(((x * view->scale) > (page_area.width)) ? (page_area.width
) : (((x * view->scale) < (0)) ? (0) : (x * view->scale
)))
;
1347 view_y = CLAMP (y * view->scale, 0, page_area.height)(((y * view->scale) > (page_area.height)) ? (page_area.
height) : (((y * view->scale) < (0)) ? (0) : (y * view->
scale)))
;
1348 view_point->x = view_x + page_area.x;
1349 view_point->y = view_y + page_area.y;
1350}
1351
1352void
1353_ev_view_transform_doc_rect_to_view_rect (EvView *view,
1354 int page,
1355 EvRectangle *doc_rect,
1356 CdkRectangle *view_rect)
1357{
1358 CdkRectangle page_area;
1359 CtkBorder border;
1360 double x, y, w, h;
1361 gdouble width, height;
1362
1363 get_doc_page_size (view, page, &width, &height);
1364
1365 if (view->rotation == 0) {
1366 x = doc_rect->x1;
1367 y = doc_rect->y1;
1368 w = doc_rect->x2 - doc_rect->x1;
1369 h = doc_rect->y2 - doc_rect->y1;
1370 } else if (view->rotation == 90) {
1371 x = width - doc_rect->y2;
1372 y = doc_rect->x1;
1373 w = doc_rect->y2 - doc_rect->y1;
1374 h = doc_rect->x2 - doc_rect->x1;
1375 } else if (view->rotation == 180) {
1376 x = width - doc_rect->x2;
1377 y = height - doc_rect->y2;
1378 w = doc_rect->x2 - doc_rect->x1;
1379 h = doc_rect->y2 - doc_rect->y1;
1380 } else if (view->rotation == 270) {
1381 x = doc_rect->y1;
1382 y = height - doc_rect->x2;
1383 w = doc_rect->y2 - doc_rect->y1;
1384 h = doc_rect->x2 - doc_rect->x1;
1385 } else {
1386 g_assert_not_reached ()do { g_assertion_message_expr ("LectorView", "ev-view.c", 1386
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1387 }
1388
1389 ev_view_get_page_extents (view, page, &page_area, &border);
1390
1391 view_rect->x = x * view->scale + page_area.x;
1392 view_rect->y = y * view->scale + page_area.y;
1393 view_rect->width = w * view->scale;
1394 view_rect->height = h * view->scale;
1395}
1396
1397static void
1398find_page_at_location (EvView *view,
1399 gdouble x,
1400 gdouble y,
1401 gint *page,
1402 gint *x_offset,
1403 gint *y_offset)
1404{
1405 int i;
1406
1407 if (view->document == NULL((void*)0))
1408 return;
1409
1410 g_assert (page)do { if (page) ; else g_assertion_message_expr ("LectorView",
"ev-view.c", 1410, ((const char*) (__func__)), "page"); } while
(0)
;
1411 g_assert (x_offset)do { if (x_offset) ; else g_assertion_message_expr ("LectorView"
, "ev-view.c", 1411, ((const char*) (__func__)), "x_offset");
} while (0)
;
1412 g_assert (y_offset)do { if (y_offset) ; else g_assertion_message_expr ("LectorView"
, "ev-view.c", 1412, ((const char*) (__func__)), "y_offset");
} while (0)
;
1413
1414 for (i = view->start_page; i >= 0 && i <= view->end_page; i++) {
1415 CdkRectangle page_area;
1416 CtkBorder border;
1417
1418 if (! ev_view_get_page_extents (view, i, &page_area, &border))
1419 continue;
1420
1421 if ((x >= page_area.x + border.left) &&
1422 (x < page_area.x + page_area.width - border.right) &&
1423 (y >= page_area.y + border.top) &&
1424 (y < page_area.y + page_area.height - border.bottom)) {
1425 *page = i;
1426 *x_offset = x - (page_area.x + border.left);
1427 *y_offset = y - (page_area.y + border.top);
1428 return;
1429 }
1430 }
1431
1432 *page = -1;
1433}
1434
1435static gboolean
1436location_in_text (EvView *view,
1437 gdouble x,
1438 gdouble y)
1439{
1440 cairo_region_t *region;
1441 gint page = -1;
1442 gint x_offset = 0, y_offset = 0;
1443
1444 find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
1445
1446 if (page == -1)
1447 return FALSE(0);
1448
1449 region = ev_page_cache_get_text_mapping (view->page_cache, page);
1450
1451 if (region)
1452 return cairo_region_contains_point (region, x_offset / view->scale, y_offset / view->scale);
1453 else
1454 return FALSE(0);
1455}
1456
1457static gboolean
1458location_in_selected_text (EvView *view,
1459 gdouble x,
1460 gdouble y)
1461{
1462 cairo_region_t *region;
1463 gint page = -1;
1464 gint x_offset = 0, y_offset = 0;
1465
1466 find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
1467
1468 if (page == -1)
1469 return FALSE(0);
1470
1471 region = ev_pixbuf_cache_get_selection_region (view->pixbuf_cache, page, view->scale);
1472
1473 if (region)
1474 return cairo_region_contains_point (region, x_offset, y_offset);
1475 else
1476 return FALSE(0);
1477}
1478
1479static gboolean
1480get_doc_point_from_offset (EvView *view,
1481 gint page,
1482 gint x_offset,
1483 gint y_offset,
1484 gint *x_new,
1485 gint *y_new)
1486{
1487 gdouble width, height;
1488 double x, y;
1489
1490 get_doc_page_size (view, page, &width, &height);
1491
1492 x_offset = x_offset / view->scale;
1493 y_offset = y_offset / view->scale;
1494
1495 if (view->rotation == 0) {
1496 x = x_offset;
1497 y = y_offset;
1498 } else if (view->rotation == 90) {
1499 x = y_offset;
1500 y = width - x_offset;
1501 } else if (view->rotation == 180) {
1502 x = width - x_offset;
1503 y = height - y_offset;
1504 } else if (view->rotation == 270) {
1505 x = height - y_offset;
1506 y = x_offset;
1507 } else {
1508 g_assert_not_reached ()do { g_assertion_message_expr ("LectorView", "ev-view.c", 1508
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1509 }
1510
1511 *x_new = x;
1512 *y_new = y;
1513
1514 return TRUE(!(0));
1515}
1516
1517static gboolean
1518get_doc_point_from_location (EvView *view,
1519 gdouble x,
1520 gdouble y,
1521 gint *page,
1522 gint *x_new,
1523 gint *y_new)
1524{
1525 gint x_offset = 0, y_offset = 0;
1526
1527 x += view->scroll_x;
1528 y += view->scroll_y;
1529 find_page_at_location (view, x, y, page, &x_offset, &y_offset);
1530 if (*page == -1)
1531 return FALSE(0);
1532
1533 return get_doc_point_from_offset (view, *page, x_offset, y_offset, x_new, y_new);
1534}
1535
1536static void
1537ev_view_get_area_from_mapping (EvView *view,
1538 guint page,
1539 EvMappingList *mapping_list,
1540 gconstpointer data,
1541 CdkRectangle *area)
1542{
1543 EvMapping *mapping;
1544
1545 mapping = ev_mapping_list_find (mapping_list, data);
1546 _ev_view_transform_doc_rect_to_view_rect (view, page, &mapping->area, area);
1547 area->x -= view->scroll_x;
1548 area->y -= view->scroll_y;
1549}
1550
1551static void
1552ev_view_put (EvView *view,
1553 CtkWidget *child_widget,
1554 gint x,
1555 gint y,
1556 guint page,
1557 EvRectangle *doc_rect)
1558{
1559 EvViewChild *child;
1560
1561 child = g_slice_new (EvViewChild)((EvViewChild*) g_slice_alloc (sizeof (EvViewChild)));
1562
1563 child->widget = child_widget;
1564 child->x = x;
1565 child->y = y;
1566 child->page = page;
1567 child->doc_rect = *doc_rect;
1568
1569 ctk_widget_set_parent (child_widget, CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
1570 view->children = g_list_append (view->children, child);
1571}
1572
1573static void
1574ev_view_put_to_doc_rect (EvView *view,
1575 CtkWidget *child_widget,
1576 guint page,
1577 EvRectangle *doc_rect)
1578{
1579 CdkRectangle area;
1580
1581 _ev_view_transform_doc_rect_to_view_rect (view, page, doc_rect, &area);
1582 area.x -= view->scroll_x;
1583 area.y -= view->scroll_y;
1584 ev_view_put (view, child_widget, area.x, area.y, page, doc_rect);
1585}
1586
1587/*** Hyperref ***/
1588static EvMapping *
1589get_link_mapping_at_location (EvView *view,
1590 gdouble x,
1591 gdouble y,
1592 gint *page)
1593{
1594 gint x_new = 0, y_new = 0;
1595 EvMappingList *link_mapping;
1596
1597 if (!EV_IS_DOCUMENT_LINKS (view->document)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(view->document)); GType __t = ((ev_document_links_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
1598 return NULL((void*)0);
1599
1600 if (!get_doc_point_from_location (view, x, y, page, &x_new, &y_new))
1601 return NULL((void*)0);
1602
1603 link_mapping = ev_page_cache_get_link_mapping (view->page_cache, *page);
1604 if (link_mapping)
1605 return ev_mapping_list_get (link_mapping, x_new, y_new);
1606
1607 return NULL((void*)0);
1608}
1609
1610static EvLink *
1611ev_view_get_link_at_location (EvView *view,
1612 gdouble x,
1613 gdouble y)
1614{
1615 EvMapping *mapping;
1616 gint page;
1617
1618 mapping = get_link_mapping_at_location (view, x, y, &page);
1619
1620 return mapping ? mapping->data : NULL((void*)0);
1621}
1622
1623static void
1624goto_fitr_dest (EvView *view, EvLinkDest *dest)
1625{
1626 EvPoint doc_point;
1627 gdouble zoom, left, top;
1628 gboolean change_left, change_top;
1629 CtkAllocation allocation;
1630
1631 ctk_widget_get_allocation (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
, &allocation);
1632
1633 left = ev_link_dest_get_left (dest, &change_left);
1634 top = ev_link_dest_get_top (dest, &change_top);
1635
1636 zoom = zoom_for_size_fit_page (ev_link_dest_get_right (dest) - left,
1637 ev_link_dest_get_bottom (dest) - top,
1638 allocation.width,
1639 allocation.height);
1640
1641 ev_document_model_set_sizing_mode (view->model, EV_SIZING_FREE);
1642 ev_document_model_set_scale (view->model, zoom);
1643
1644 doc_point.x = change_left ? left : 0;
1645 doc_point.y = change_top ? top : 0;
1646 view->pending_point = doc_point;
1647
1648 ev_view_change_page (view, ev_link_dest_get_page (dest));
1649}
1650
1651static void
1652goto_fitv_dest (EvView *view, EvLinkDest *dest)
1653{
1654 EvPoint doc_point;
1655 gdouble doc_width, doc_height;
1656 gint page;
1657 double zoom, left;
1658 gboolean change_left;
1659 CtkAllocation allocation;
1660
1661 ctk_widget_get_allocation (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
, &allocation);
1662
1663 page = ev_link_dest_get_page (dest);
1664 ev_document_get_page_size (view->document, page, &doc_width, &doc_height);
1665
1666 left = ev_link_dest_get_left (dest, &change_left);
1667 doc_point.x = change_left ? left : 0;
1668 doc_point.y = 0;
1669
1670 zoom = zoom_for_size_fit_height (doc_width - doc_point.x , doc_height,
1671 allocation.width,
1672 allocation.height);
1673
1674 ev_document_model_set_sizing_mode (view->model, EV_SIZING_FREE);
1675 ev_document_model_set_scale (view->model, zoom);
1676
1677 view->pending_point = doc_point;
1678
1679 ev_view_change_page (view, page);
1680}
1681
1682static void
1683goto_fith_dest (EvView *view, EvLinkDest *dest)
1684{
1685 EvPoint doc_point;
1686 gdouble doc_width, doc_height;
1687 gint page;
1688 gdouble zoom, top;
1689 gboolean change_top;
1690 CtkAllocation allocation;
1691
1692 ctk_widget_get_allocation (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
, &allocation);
1693
1694 page = ev_link_dest_get_page (dest);
1695 ev_document_get_page_size (view->document, page, &doc_width, &doc_height);
1696
1697 top = ev_link_dest_get_top (dest, &change_top);
1698
1699 doc_point.x = 0;
1700 doc_point.y = change_top ? top : 0;
1701
1702 zoom = zoom_for_size_fit_width (doc_width, top,
1703 allocation.width,
1704 allocation.height);
1705
1706 ev_document_model_set_sizing_mode (view->model, EV_SIZING_FIT_WIDTH);
1707 ev_document_model_set_scale (view->model, zoom);
1708
1709 view->pending_point = doc_point;
1710
1711 ev_view_change_page (view, page);
1712}
1713
1714static void
1715goto_fit_dest (EvView *view, EvLinkDest *dest)
1716{
1717 double zoom;
1718 gdouble doc_width, doc_height;
1719 int page;
1720 CtkAllocation allocation;
1721
1722 ctk_widget_get_allocation (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
, &allocation);
1723
1724 page = ev_link_dest_get_page (dest);
1725 ev_document_get_page_size (view->document, page, &doc_width, &doc_height);
1726
1727 zoom = zoom_for_size_fit_page (doc_width, doc_height,
1728 allocation.width,
1729 allocation.height);
1730
1731 ev_document_model_set_sizing_mode (view->model, EV_SIZING_FIT_PAGE);
1732 ev_document_model_set_scale (view->model, zoom);
1733
1734 ev_view_change_page (view, page);
1735}
1736
1737static void
1738goto_xyz_dest (EvView *view, EvLinkDest *dest)
1739{
1740 EvPoint doc_point;
1741 gint page;
1742 gdouble zoom, left, top;
1743 gboolean change_zoom, change_left, change_top;
1744
1745 zoom = ev_link_dest_get_zoom (dest, &change_zoom);
1746 page = ev_link_dest_get_page (dest);
1747
1748 if (change_zoom && zoom > 1) {
1749 ev_document_model_set_sizing_mode (view->model, EV_SIZING_FREE);
1750 ev_document_model_set_scale (view->model, zoom);
1751 }
1752
1753 left = ev_link_dest_get_left (dest, &change_left);
1754 top = ev_link_dest_get_top (dest, &change_top);
1755
1756 doc_point.x = change_left ? left : 0;
1757 doc_point.y = change_top ? top : 0;
1758 view->pending_point = doc_point;
1759
1760 ev_view_change_page (view, page);
1761}
1762
1763static void
1764goto_dest (EvView *view, EvLinkDest *dest)
1765{
1766 EvLinkDestType type;
1767 int page, n_pages, current_page;
1768
1769 page = ev_link_dest_get_page (dest);
1770 n_pages = ev_document_get_n_pages (view->document);
1771
1772 if (page < 0 || page >= n_pages)
1773 return;
1774
1775 current_page = view->current_page;
1776
1777 type = ev_link_dest_get_dest_type (dest);
1778
1779 switch (type) {
1780 case EV_LINK_DEST_TYPE_PAGE:
1781 ev_document_model_set_page (view->model, page);
1782 break;
1783 case EV_LINK_DEST_TYPE_FIT:
1784 goto_fit_dest (view, dest);
1785 break;
1786 case EV_LINK_DEST_TYPE_FITH:
1787 goto_fith_dest (view, dest);
1788 break;
1789 case EV_LINK_DEST_TYPE_FITV:
1790 goto_fitv_dest (view, dest);
1791 break;
1792 case EV_LINK_DEST_TYPE_FITR:
1793 goto_fitr_dest (view, dest);
1794 break;
1795 case EV_LINK_DEST_TYPE_XYZ:
1796 goto_xyz_dest (view, dest);
1797 break;
1798 case EV_LINK_DEST_TYPE_PAGE_LABEL:
1799 ev_document_model_set_page_by_label (view->model, ev_link_dest_get_page_label (dest));
1800 break;
1801 default:
1802 g_assert_not_reached ()do { g_assertion_message_expr ("LectorView", "ev-view.c", 1802
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1803 }
1804
1805 if (current_page != view->current_page)
1806 ev_document_model_set_page (view->model, view->current_page);
1807}
1808
1809static void
1810ev_view_goto_dest (EvView *view, EvLinkDest *dest)
1811{
1812 EvLinkDestType type;
1813
1814 type = ev_link_dest_get_dest_type (dest);
1815
1816 if (type == EV_LINK_DEST_TYPE_NAMED) {
1817 EvLinkDest *dest2;
1818 const gchar *named_dest;
1819
1820 named_dest = ev_link_dest_get_named_dest (dest);
1821 dest2 = ev_document_links_find_link_dest (EV_DOCUMENT_LINKS (view->document)((((EvDocumentLinks*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view->document)), ((ev_document_links_get_type ()))))
))
,
1822 named_dest);
1823 if (dest2) {
1824 goto_dest (view, dest2);
1825 g_object_unref (dest2);
1826 }
1827
1828 return;
1829 }
1830
1831 goto_dest (view, dest);
1832}
1833
1834void
1835ev_view_handle_link (EvView *view, EvLink *link)
1836{
1837 EvLinkAction *action = NULL((void*)0);
1838 EvLinkActionType type;
1839
1840 action = ev_link_get_action (link);
1841 if (!action)
1842 return;
1843
1844 type = ev_link_action_get_action_type (action);
1845
1846 switch (type) {
1847 case EV_LINK_ACTION_TYPE_GOTO_DEST: {
1848 EvLinkDest *dest;
1849
1850 g_signal_emit (view, signals[SIGNAL_HANDLE_LINK], 0, link);
1851
1852 dest = ev_link_action_get_dest (action);
1853 ev_view_goto_dest (view, dest);
1854 }
1855 break;
1856 case EV_LINK_ACTION_TYPE_LAYERS_STATE: {
1857 GList *show, *hide, *toggle;
1858 GList *l;
1859 EvDocumentLayers *document_layers;
1860
1861 document_layers = EV_DOCUMENT_LAYERS (view->document)((((EvDocumentLayers*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((view->document)), ((ev_document_layers_get_type
()))))))
;
1862
1863 show = ev_link_action_get_show_list (action);
1864 for (l = show; l; l = g_list_next (l)((l) ? (((GList *)(l))->next) : ((void*)0))) {
1865 ev_document_layers_show_layer (document_layers, EV_LAYER (l->data)((((EvLayer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((ev_layer_get_type()))))))
);
1866 }
1867
1868 hide = ev_link_action_get_hide_list (action);
1869 for (l = hide; l; l = g_list_next (l)((l) ? (((GList *)(l))->next) : ((void*)0))) {
1870 ev_document_layers_hide_layer (document_layers, EV_LAYER (l->data)((((EvLayer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((ev_layer_get_type()))))))
);
1871 }
1872
1873 toggle = ev_link_action_get_toggle_list (action);
1874 for (l = toggle; l; l = g_list_next (l)((l) ? (((GList *)(l))->next) : ((void*)0))) {
1875 EvLayer *layer = EV_LAYER (l->data)((((EvLayer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((l->data)), ((ev_layer_get_type()))))))
;
1876
1877 if (ev_document_layers_layer_is_visible (document_layers, layer)) {
1878 ev_document_layers_hide_layer (document_layers, layer);
1879 } else {
1880 ev_document_layers_show_layer (document_layers, layer);
1881 }
1882 }
1883
1884 g_signal_emit (view, signals[SIGNAL_LAYERS_CHANGED], 0);
1885 ev_view_reload_page (view, view->current_page, NULL((void*)0));
1886 }
1887 break;
1888 case EV_LINK_ACTION_TYPE_GOTO_REMOTE:
1889 case EV_LINK_ACTION_TYPE_EXTERNAL_URI:
1890 case EV_LINK_ACTION_TYPE_LAUNCH:
1891 case EV_LINK_ACTION_TYPE_NAMED:
1892 g_signal_emit (view, signals[SIGNAL_EXTERNAL_LINK], 0, action);
1893 break;
1894 }
1895}
1896
1897static char *
1898tip_from_action_named (EvLinkAction *action)
1899{
1900 const gchar *name = ev_link_action_get_name (action);
1901
1902 if (g_ascii_strcasecmp (name, "FirstPage") == 0) {
1903 return g_strdup (_("Go to first page"))g_strdup_inline (((char *) g_dgettext ("lector", "Go to first page"
)))
;
1904 } else if (g_ascii_strcasecmp (name, "PrevPage") == 0) {
1905 return g_strdup (_("Go to previous page"))g_strdup_inline (((char *) g_dgettext ("lector", "Go to previous page"
)))
;
1906 } else if (g_ascii_strcasecmp (name, "NextPage") == 0) {
1907 return g_strdup (_("Go to next page"))g_strdup_inline (((char *) g_dgettext ("lector", "Go to next page"
)))
;
1908 } else if (g_ascii_strcasecmp (name, "LastPage") == 0) {
1909 return g_strdup (_("Go to last page"))g_strdup_inline (((char *) g_dgettext ("lector", "Go to last page"
)))
;
1910 } else if (g_ascii_strcasecmp (name, "GoToPage") == 0) {
1911 return g_strdup (_("Go to page"))g_strdup_inline (((char *) g_dgettext ("lector", "Go to page"
)))
;
1912 } else if (g_ascii_strcasecmp (name, "Find") == 0) {
1913 return g_strdup (_("Find"))g_strdup_inline (((char *) g_dgettext ("lector", "Find")));
1914 }
1915
1916 return NULL((void*)0);
1917}
1918
1919static char *
1920tip_from_link (EvView *view, EvLink *link)
1921{
1922 EvLinkAction *action;
1923 EvLinkActionType type;
1924 char *msg = NULL((void*)0);
1925 char *page_label;
1926 const char *title;
1927
1928 action = ev_link_get_action (link);
1929 title = ev_link_get_title (link);
1930
1931 if (!action)
1932 return title ? g_strdup (title)g_strdup_inline (title) : NULL((void*)0);
1933
1934 type = ev_link_action_get_action_type (action);
1935
1936 switch (type) {
1937 case EV_LINK_ACTION_TYPE_GOTO_DEST:
1938 page_label = ev_document_links_get_dest_page_label (EV_DOCUMENT_LINKS (view->document)((((EvDocumentLinks*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view->document)), ((ev_document_links_get_type ()))))
))
,
1939 ev_link_action_get_dest (action));
1940 if (page_label) {
1941 msg = g_strdup_printf (_("Go to page %s")((char *) g_dgettext ("lector", "Go to page %s")), page_label);
1942 g_free (page_label);
1943 }
1944 break;
1945 case EV_LINK_ACTION_TYPE_GOTO_REMOTE:
1946 if (title) {
1947 msg = g_strdup_printf (_("Go to %s on file “%s”")((char *) g_dgettext ("lector", "Go to %s on file “%s”")), title,
1948 ev_link_action_get_filename (action));
1949 } else {
1950 msg = g_strdup_printf (_("Go to file “%s”")((char *) g_dgettext ("lector", "Go to file “%s”")),
1951 ev_link_action_get_filename (action));
1952 }
1953 break;
1954 case EV_LINK_ACTION_TYPE_EXTERNAL_URI:
1955 msg = g_strdup (ev_link_action_get_uri (action))g_strdup_inline (ev_link_action_get_uri (action));
1956 break;
1957 case EV_LINK_ACTION_TYPE_LAUNCH:
1958 msg = g_strdup_printf (_("Launch %s")((char *) g_dgettext ("lector", "Launch %s")),
1959 ev_link_action_get_filename (action));
1960 break;
1961 case EV_LINK_ACTION_TYPE_NAMED:
1962 msg = tip_from_action_named (action);
1963 break;
1964 default:
1965 if (title)
1966 msg = g_strdup (title)g_strdup_inline (title);
1967 break;
1968 }
1969
1970 return msg;
1971}
1972
1973static void
1974ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y)
1975{
1976 EvLink *link;
1977 EvFormField *field;
1978 EvAnnotation *annot = NULL((void*)0);
1979
1980 if (view->cursor == EV_VIEW_CURSOR_HIDDEN)
1981 return;
1982
1983 if (view->adding_annot) {
1984 if (view->cursor != EV_VIEW_CURSOR_ADD)
1985 ev_view_set_cursor (view, EV_VIEW_CURSOR_ADD);
1986 return;
1987 }
1988
1989 if (view->drag_info.in_drag) {
1990 if (view->cursor != EV_VIEW_CURSOR_DRAG)
1991 ev_view_set_cursor (view, EV_VIEW_CURSOR_DRAG);
1992 return;
1993 }
1994
1995 if (view->scroll_info.autoscrolling) {
1996 if (view->cursor != EV_VIEW_CURSOR_AUTOSCROLL)
1997 ev_view_set_cursor (view, EV_VIEW_CURSOR_AUTOSCROLL);
1998 return;
1999 }
2000
2001 link = ev_view_get_link_at_location (view, x, y);
2002 if (link) {
2003 ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK);
2004 } else if ((field = ev_view_get_form_field_at_location (view, x, y))) {
2005 if (field->is_read_only) {
2006 if (view->cursor == EV_VIEW_CURSOR_LINK ||
2007 view->cursor == EV_VIEW_CURSOR_IBEAM ||
2008 view->cursor == EV_VIEW_CURSOR_DRAG)
2009 ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
2010 } else if (EV_IS_FORM_FIELD_TEXT (field)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(field)); GType __t = ((ev_form_field_text_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
2011 ev_view_set_cursor (view, EV_VIEW_CURSOR_IBEAM);
2012 } else {
2013 ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK);
2014 }
2015 } else if ((annot = ev_view_get_annotation_at_location (view, x, y))) {
2016 ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK);
2017 } else if (location_in_text (view, x + view->scroll_x, y + view->scroll_y)) {
2018 ev_view_set_cursor (view, EV_VIEW_CURSOR_IBEAM);
2019 } else {
2020 if (view->cursor == EV_VIEW_CURSOR_LINK ||
2021 view->cursor == EV_VIEW_CURSOR_IBEAM ||
2022 view->cursor == EV_VIEW_CURSOR_DRAG ||
2023 view->cursor == EV_VIEW_CURSOR_AUTOSCROLL ||
2024 view->cursor == EV_VIEW_CURSOR_ADD)
2025 ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
2026 }
2027
2028 if (link || annot)
2029 g_object_set (view, "has-tooltip", TRUE(!(0)), NULL((void*)0));
2030}
2031
2032/*** Images ***/
2033static EvImage *
2034ev_view_get_image_at_location (EvView *view,
2035 gdouble x,
2036 gdouble y)
2037{
2038 gint page = -1;
2039 gint x_new = 0, y_new = 0;
2040 EvMappingList *image_mapping;
2041
2042 if (!EV_IS_DOCUMENT_IMAGES (view->document)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(view->document)); GType __t = ((ev_document_images_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
2043 return NULL((void*)0);
2044
2045 if (!get_doc_point_from_location (view, x, y, &page, &x_new, &y_new))
2046 return NULL((void*)0);
2047
2048 image_mapping = ev_page_cache_get_image_mapping (view->page_cache, page);
2049
2050 if (image_mapping)
2051 return ev_mapping_list_get_data (image_mapping, x_new, y_new);
2052 else
2053 return NULL((void*)0);
2054}
2055
2056/*** Focus ***/
2057static gboolean
2058ev_view_get_focused_area (EvView *view,
2059 CdkRectangle *area)
2060{
2061 if (!view->focused_element)
2062 return FALSE(0);
2063
2064 _ev_view_transform_doc_rect_to_view_rect (view,
2065 view->focused_element_page,
2066 &view->focused_element->area,
2067 area);
2068 area->x -= view->scroll_x + 1;
2069 area->y -= view->scroll_y + 1;
2070 area->width += 1;
2071 area->height += 1;
2072
2073 return TRUE(!(0));
2074}
2075
2076void
2077_ev_view_set_focused_element (EvView *view,
2078 EvMapping *element_mapping,
2079 gint page)
2080{
2081 CdkRectangle view_rect;
2082 cairo_region_t *region = NULL((void*)0);
2083
2084 if (view->focused_element == element_mapping)
2085 return;
2086
2087 if (ev_view_get_focused_area (view, &view_rect))
2088 region = cairo_region_create_rectangle (&view_rect);
2089
2090 view->focused_element = element_mapping;
2091 view->focused_element_page = page;
2092
2093 if (ev_view_get_focused_area (view, &view_rect)) {
2094 if (!region)
2095 region = cairo_region_create_rectangle (&view_rect);
2096 else
2097 cairo_region_union_rectangle (region, &view_rect);
2098
2099 ev_document_model_set_page (view->model, page);
2100 view_rect.x += view->scroll_x;
2101 view_rect.y += view->scroll_y;
2102 ensure_rectangle_is_visible (view, &view_rect);
2103 }
2104
2105 if (region) {
2106 cdk_window_invalidate_region (ctk_widget_get_window (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
),
2107 region, TRUE(!(0)));
2108 cairo_region_destroy (region);
2109 }
2110}
2111
2112/*** Forms ***/
2113static EvMapping *
2114get_form_field_mapping_at_location (EvView *view,
2115 gdouble x,
2116 gdouble y,
2117 gint *page)
2118{
2119 gint x_new = 0, y_new = 0;
2120 EvMappingList *forms_mapping;
2121
2122 if (!EV_IS_DOCUMENT_FORMS (view->document)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(view->document)); GType __t = ((ev_document_forms_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
2123 return NULL((void*)0);
2124
2125 if (!get_doc_point_from_location (view, x, y, page, &x_new, &y_new))
2126 return NULL((void*)0);
2127
2128 forms_mapping = ev_page_cache_get_form_field_mapping (view->page_cache, *page);
2129
2130 if (forms_mapping)
2131 return ev_mapping_list_get (forms_mapping, x_new, y_new);
2132
2133 return NULL((void*)0);
2134}
2135
2136static EvFormField *
2137ev_view_get_form_field_at_location (EvView *view,
2138 gdouble x,
2139 gdouble y)
2140{
2141 EvMapping *field_mapping;
2142 gint page;
2143
2144 field_mapping = get_form_field_mapping_at_location (view, x, y, &page);
2145
2146 return field_mapping ? field_mapping->data : NULL((void*)0);
2147}
2148
2149static cairo_region_t *
2150ev_view_form_field_get_region (EvView *view,
2151 EvFormField *field)
2152{
2153 CdkRectangle view_area;
2154 EvMappingList *forms_mapping;
2155
2156 forms_mapping = ev_page_cache_get_form_field_mapping (view->page_cache,
2157 field->page->index);
2158 ev_view_get_area_from_mapping (view, field->page->index,
2159 forms_mapping,
2160 field, &view_area);
2161
2162 return cairo_region_create_rectangle (&view_area);
2163}
2164
2165static gboolean
2166ev_view_forms_remove_widgets (EvView *view)
2167{
2168 ev_view_remove_all (view);
2169
2170 return FALSE(0);
2171}
2172
2173static void
2174ev_view_form_field_destroy (CtkWidget *widget,
2175 EvView *view)
2176{
2177 g_idle_add ((GSourceFunc)ev_view_forms_remove_widgets, view);
2178}
2179
2180static void
2181ev_view_form_field_button_toggle (EvView *view,
2182 EvFormField *field)
2183{
2184 EvMappingList *forms_mapping;
2185 cairo_region_t *region;
2186 gboolean state;
2187 GList *l;
2188 EvFormFieldButton *field_button = EV_FORM_FIELD_BUTTON (field)((((EvFormFieldButton*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((field)), ((ev_form_field_button_get_type()
))))))
;
2189
2190 if (field_button->type == EV_FORM_FIELD_BUTTON_PUSH)
2191 return;
2192
2193 state = ev_document_forms_form_field_button_get_state (EV_DOCUMENT_FORMS (view->document)((((EvDocumentForms*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view->document)), ((ev_document_forms_get_type ()))))
))
,
2194 field);
2195
2196 /* FIXME: it actually depends on NoToggleToOff flags */
2197 if (field_button->type == EV_FORM_FIELD_BUTTON_RADIO && state && field_button->state)
2198 return;
2199
2200 region = ev_view_form_field_get_region (view, field);
2201
2202 /* For radio buttons and checkbox buttons that are in a set
2203 * we need to update also the region for the current selected item
2204 */
2205 forms_mapping = ev_page_cache_get_form_field_mapping (view->page_cache,
2206 field->page->index);
2207
2208 for (l = ev_mapping_list_get_list (forms_mapping); l; l = g_list_next (l)((l) ? (((GList *)(l))->next) : ((void*)0))) {
2209 EvFormField *button = ((EvMapping *)(l->data))->data;
2210 cairo_region_t *button_region;
2211
2212 if (button->id == field->id)
2213 continue;
2214
2215 /* FIXME: only buttons in the same group should be updated */
2216 if (!EV_IS_FORM_FIELD_BUTTON (button)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(button)); GType __t = ((ev_form_field_button_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
||
2217 EV_FORM_FIELD_BUTTON (button)((((EvFormFieldButton*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((button)), ((ev_form_field_button_get_type(
)))))))
->type != field_button->type ||
2218 EV_FORM_FIELD_BUTTON (button)((((EvFormFieldButton*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((button)), ((ev_form_field_button_get_type(
)))))))
->state != TRUE(!(0)))
2219 continue;
2220
2221 button_region = ev_view_form_field_get_region (view, button);
2222 cairo_region_union (region, button_region);
2223 cairo_region_destroy (button_region);
2224 }
2225
2226 /* Update state */
2227 ev_document_forms_form_field_button_set_state (EV_DOCUMENT_FORMS (view->document)((((EvDocumentForms*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view->document)), ((ev_document_forms_get_type ()))))
))
,
2228 field,
2229 !state);
2230 field_button->state = !state;
2231
2232 ev_view_reload_page (view, field->page->index, region);
2233 cairo_region_destroy (region);
2234}
2235
2236static CtkWidget *
2237ev_view_form_field_button_create_widget (EvView *view,
2238 EvFormField *field)
2239{
2240 EvMappingList *form_mapping;
2241 EvMapping *mapping;
2242
2243 form_mapping = ev_page_cache_get_form_field_mapping (view->page_cache,
2244 field->page->index);
2245 mapping = ev_mapping_list_find (form_mapping, field);
2246 _ev_view_set_focused_element (view, mapping, field->page->index);
2247
2248 return NULL((void*)0);
2249}
2250
2251static void
2252ev_view_form_field_text_save (EvView *view,
2253 CtkWidget *widget)
2254{
2255 EvFormField *field;
2256
2257 if (!view->document)
2258 return;
2259
2260 field = g_object_get_data (G_OBJECT (widget)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), (((GType) ((20) << (2))))))))
, "form-field");
2261
2262 if (field->changed) {
2263 EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field)((((EvFormFieldText*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((field)), ((ev_form_field_text_get_type()))))))
;
2264 cairo_region_t *field_region;
2265
2266 field_region = ev_view_form_field_get_region (view, field);
2267
2268 ev_document_forms_form_field_text_set_text (EV_DOCUMENT_FORMS (view->document)((((EvDocumentForms*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view->document)), ((ev_document_forms_get_type ()))))
))
,
2269 field, field_text->text);
2270 field->changed = FALSE(0);
2271 ev_view_reload_page (view, field->page->index, field_region);
2272 cairo_region_destroy (field_region);
2273 }
2274}
2275
2276static void
2277ev_view_form_field_text_changed (CtkWidget *widget,
2278 EvFormField *field)
2279{
2280 EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field)((((EvFormFieldText*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((field)), ((ev_form_field_text_get_type()))))))
;
2281 gchar *text = NULL((void*)0);
2282
2283 if (CTK_IS_ENTRY (widget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(widget)); GType __t = ((ctk_entry_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
2284 text = g_strdup (ctk_entry_get_text (CTK_ENTRY (widget)))g_strdup_inline (ctk_entry_get_text (((((CtkEntry*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((widget)), ((ctk_entry_get_type ())))))))
)
;
2285 } else if (CTK_IS_TEXT_BUFFER (widget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(widget)); GType __t = ((ctk_text_buffer_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
2286 CtkTextIter start, end;
2287
2288 ctk_text_buffer_get_bounds (CTK_TEXT_BUFFER (widget)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_buffer_get_type ()))))))
, &start, &end);
2289 text = ctk_text_buffer_get_text (CTK_TEXT_BUFFER (widget)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_text_buffer_get_type ()))))))
,
2290 &start, &end, FALSE(0));
2291 }
2292
2293 if (!field_text->text ||
2294 (field_text->text && g_ascii_strcasecmp (field_text->text, text) != 0)) {
2295 g_free (field_text->text);
2296 field_text->text = text;
2297 field->changed = TRUE(!(0));
2298 }
2299}
2300
2301static gboolean
2302ev_view_form_field_text_focus_out (CtkWidget *widget,
2303 CdkEventFocus *event,
2304 EvView *view)
2305{
2306 ev_view_form_field_text_save (view, widget);
2307
2308 return FALSE(0);
2309}
2310
2311static CtkWidget *
2312ev_view_form_field_text_create_widget (EvView *view,
2313 EvFormField *field)
2314{
2315 EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field)((((EvFormFieldText*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((field)), ((ev_form_field_text_get_type()))))))
;
2316 CtkWidget *text = NULL((void*)0);
2317 gchar *txt;
2318
2319 txt = ev_document_forms_form_field_text_get_text (EV_DOCUMENT_FORMS (view->document)((((EvDocumentForms*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view->document)), ((ev_document_forms_get_type ()))))
))
,
2320 field);
2321
2322 switch (field_text->type) {
2323 case EV_FORM_FIELD_TEXT_FILE_SELECT:
2324 /* TODO */
2325 case EV_FORM_FIELD_TEXT_NORMAL:
2326 text = ctk_entry_new ();
2327 ctk_entry_set_has_frame (CTK_ENTRY (text)((((CtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text)), ((ctk_entry_get_type ()))))))
, FALSE(0));
2328 ctk_entry_set_max_length (CTK_ENTRY (text)((((CtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text)), ((ctk_entry_get_type ()))))))
, field_text->max_len);
2329 ctk_entry_set_visibility (CTK_ENTRY (text)((((CtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text)), ((ctk_entry_get_type ()))))))
, !field_text->is_password);
2330
2331 if (txt) {
2332 ctk_entry_set_text (CTK_ENTRY (text)((((CtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text)), ((ctk_entry_get_type ()))))))
, txt);
2333 g_free (txt);
2334 }
2335
2336 g_signal_connect (text, "focus-out-event",g_signal_connect_data ((text), ("focus-out-event"), (((GCallback
) (ev_view_form_field_text_focus_out))), (view), ((void*)0), (
GConnectFlags) 0)
2337 G_CALLBACK (ev_view_form_field_text_focus_out),g_signal_connect_data ((text), ("focus-out-event"), (((GCallback
) (ev_view_form_field_text_focus_out))), (view), ((void*)0), (
GConnectFlags) 0)
2338 view)g_signal_connect_data ((text), ("focus-out-event"), (((GCallback
) (ev_view_form_field_text_focus_out))), (view), ((void*)0), (
GConnectFlags) 0)
;
2339 g_signal_connect (text, "changed",g_signal_connect_data ((text), ("changed"), (((GCallback) (ev_view_form_field_text_changed
))), (field), ((void*)0), (GConnectFlags) 0)
2340 G_CALLBACK (ev_view_form_field_text_changed),g_signal_connect_data ((text), ("changed"), (((GCallback) (ev_view_form_field_text_changed
))), (field), ((void*)0), (GConnectFlags) 0)
2341 field)g_signal_connect_data ((text), ("changed"), (((GCallback) (ev_view_form_field_text_changed
))), (field), ((void*)0), (GConnectFlags) 0)
;
2342 g_signal_connect_after (text, "activate",g_signal_connect_data ((text), ("activate"), (((GCallback) (ev_view_form_field_destroy
))), (view), ((void*)0), G_CONNECT_AFTER)
2343 G_CALLBACK (ev_view_form_field_destroy),g_signal_connect_data ((text), ("activate"), (((GCallback) (ev_view_form_field_destroy
))), (view), ((void*)0), G_CONNECT_AFTER)
2344 view)g_signal_connect_data ((text), ("activate"), (((GCallback) (ev_view_form_field_destroy
))), (view), ((void*)0), G_CONNECT_AFTER)
;
2345 break;
2346 case EV_FORM_FIELD_TEXT_MULTILINE: {
2347 CtkTextBuffer *buffer;
2348
2349 text = ctk_text_view_new ();
2350 buffer = ctk_text_view_get_buffer (CTK_TEXT_VIEW (text)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text)), ((ctk_text_view_get_type ()))))))
);
2351
2352 if (txt) {
2353 ctk_text_buffer_set_text (buffer, txt, -1);
2354 g_free (txt);
2355 }
2356
2357 g_signal_connect (text, "focus-out-event",g_signal_connect_data ((text), ("focus-out-event"), (((GCallback
) (ev_view_form_field_text_focus_out))), (view), ((void*)0), (
GConnectFlags) 0)
2358 G_CALLBACK (ev_view_form_field_text_focus_out),g_signal_connect_data ((text), ("focus-out-event"), (((GCallback
) (ev_view_form_field_text_focus_out))), (view), ((void*)0), (
GConnectFlags) 0)
2359 view)g_signal_connect_data ((text), ("focus-out-event"), (((GCallback
) (ev_view_form_field_text_focus_out))), (view), ((void*)0), (
GConnectFlags) 0)
;
2360 g_signal_connect (buffer, "changed",g_signal_connect_data ((buffer), ("changed"), (((GCallback) (
ev_view_form_field_text_changed))), (field), ((void*)0), (GConnectFlags
) 0)
2361 G_CALLBACK (ev_view_form_field_text_changed),g_signal_connect_data ((buffer), ("changed"), (((GCallback) (
ev_view_form_field_text_changed))), (field), ((void*)0), (GConnectFlags
) 0)
2362 field)g_signal_connect_data ((buffer), ("changed"), (((GCallback) (
ev_view_form_field_text_changed))), (field), ((void*)0), (GConnectFlags
) 0)
;
2363 }
2364 break;
2365 }
2366
2367 g_object_weak_ref (G_OBJECT (text)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((text)), (((GType) ((20) << (2))))))))
,
2368 (GWeakNotify)ev_view_form_field_text_save,
2369 view);
2370
2371 return text;
2372}
2373
2374static void
2375ev_view_form_field_choice_save (EvView *view,
2376 CtkWidget *widget)
2377{
2378 EvFormField *field;
2379
2380 if (!view->document)
2381 return;
2382
2383 field = g_object_get_data (G_OBJECT (widget)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), (((GType) ((20) << (2))))))))
, "form-field");
2384
2385 if (field->changed) {
2386 GList *l;
2387 EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field)((((EvFormFieldChoice*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((field)), ((ev_form_field_choice_get_type()
))))))
;
2388 cairo_region_t *field_region;
2389
2390 field_region = ev_view_form_field_get_region (view, field);
2391
2392 if (field_choice->is_editable) {
2393 ev_document_forms_form_field_choice_set_text (EV_DOCUMENT_FORMS (view->document)((((EvDocumentForms*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view->document)), ((ev_document_forms_get_type ()))))
))
,
2394 field, field_choice->text);
2395 } else {
2396 ev_document_forms_form_field_choice_unselect_all (EV_DOCUMENT_FORMS (view->document)((((EvDocumentForms*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view->document)), ((ev_document_forms_get_type ()))))
))
, field);
2397 for (l = field_choice->selected_items; l; l = g_list_next (l)((l) ? (((GList *)(l))->next) : ((void*)0))) {
2398 ev_document_forms_form_field_choice_select_item (EV_DOCUMENT_FORMS (view->document)((((EvDocumentForms*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view->document)), ((ev_document_forms_get_type ()))))
))
,
2399 field,
2400 GPOINTER_TO_INT (l->data)((gint) (glong) (l->data)));
2401 }
2402 }
2403 field->changed = FALSE(0);
2404 ev_view_reload_page (view, field->page->index, field_region);
2405 cairo_region_destroy (field_region);
2406 }
2407}
2408
2409static void
2410ev_view_form_field_choice_changed (CtkWidget *widget,
2411 EvFormField *field)
2412{
2413 EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field)((((EvFormFieldChoice*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((field)), ((ev_form_field_choice_get_type()
))))))
;
2414
2415 if (CTK_IS_COMBO_BOX (widget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(widget)); GType __t = ((ctk_combo_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
2416 gint item;
2417
2418 item = ctk_combo_box_get_active (CTK_COMBO_BOX (widget)((((CtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_combo_box_get_type ()))))))
);
2419 if (!field_choice->selected_items ||
2420 GPOINTER_TO_INT (field_choice->selected_items->data)((gint) (glong) (field_choice->selected_items->data)) != item) {
2421 g_list_free (field_choice->selected_items);
2422 field_choice->selected_items = NULL((void*)0);
2423 field_choice->selected_items = g_list_prepend (field_choice->selected_items,
2424 GINT_TO_POINTER (item)((gpointer) (glong) (item)));
2425 field->changed = TRUE(!(0));
2426 }
2427
2428 if (ctk_combo_box_get_has_entry (CTK_COMBO_BOX (widget)((((CtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_combo_box_get_type ()))))))
)) {
2429 const gchar *text;
2430
2431 text = ctk_entry_get_text (CTK_ENTRY (ctk_bin_get_child (CTK_BIN (widget)))((((CtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((ctk_bin_get_child (((((CtkBin*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((widget)), ((ctk_bin_get_type ())))))))))
, ((ctk_entry_get_type ()))))))
);
2432 if (!field_choice->text ||
2433 (field_choice->text && g_ascii_strcasecmp (field_choice->text, text) != 0)) {
2434 g_free (field_choice->text);
2435 field_choice->text = g_strdup(text)g_strdup_inline (text);
2436 field->changed = TRUE(!(0));
2437 }
2438 }
2439 } else if (CTK_IS_TREE_SELECTION (widget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(widget)); GType __t = ((ctk_tree_selection_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
2440 CtkTreeSelection *selection = CTK_TREE_SELECTION (widget)((((CtkTreeSelection*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((widget)), ((ctk_tree_selection_get_type ())
)))))
;
2441 CtkTreeModel *model;
2442 GList *items, *l;
2443
2444 items = ctk_tree_selection_get_selected_rows (selection, &model);
2445 g_list_free (field_choice->selected_items);
2446 field_choice->selected_items = NULL((void*)0);
2447
2448 for (l = items; l && l->data; l = g_list_next (l)((l) ? (((GList *)(l))->next) : ((void*)0))) {
2449 CtkTreeIter iter;
2450 CtkTreePath *path = (CtkTreePath *)l->data;
2451 gint item;
2452
2453 ctk_tree_model_get_iter (model, &iter, path);
2454 ctk_tree_model_get (model, &iter, 1, &item, -1);
2455
2456 field_choice->selected_items = g_list_prepend (field_choice->selected_items,
2457 GINT_TO_POINTER (item)((gpointer) (glong) (item)));
2458
2459 ctk_tree_path_free (path);
2460 }
2461
2462 g_list_free (items);
2463
2464 field->changed = TRUE(!(0));
2465 }
2466}
2467
2468static CtkWidget *
2469ev_view_form_field_choice_create_widget (EvView *view,
2470 EvFormField *field)
2471{
2472 EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field)((((EvFormFieldChoice*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((field)), ((ev_form_field_choice_get_type()
))))))
;
2473 CtkWidget *choice;
2474 CtkTreeModel *model;
2475 gint n_items, i;
2476 gint selected_item = 0;
2477
2478 n_items = ev_document_forms_form_field_choice_get_n_items (EV_DOCUMENT_FORMS (view->document)((((EvDocumentForms*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view->document)), ((ev_document_forms_get_type ()))))
))
,
2479 field);
2480 model = CTK_TREE_MODEL (ctk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT))((((CtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((ctk_list_store_new (2, ((GType) ((16) << (2))), ((
GType) ((6) << (2)))))), ((ctk_tree_model_get_type ()))
))))
;
2481 for (i = 0; i < n_items; i++) {
2482 CtkTreeIter iter;
2483 gchar *item;
2484
2485 item = ev_document_forms_form_field_choice_get_item (EV_DOCUMENT_FORMS (view->document)((((EvDocumentForms*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view->document)), ((ev_document_forms_get_type ()))))
))
,
2486 field, i);
2487 if (ev_document_forms_form_field_choice_is_item_selected (
2488 EV_DOCUMENT_FORMS (view->document)((((EvDocumentForms*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view->document)), ((ev_document_forms_get_type ()))))
))
, field, i)) {
2489 selected_item = i;
2490 /* FIXME: we need a get_selected_items function in poppler */
2491 field_choice->selected_items = g_list_prepend (field_choice->selected_items,
2492 GINT_TO_POINTER (i)((gpointer) (glong) (i)));
2493 }
2494
2495 if (item) {
2496 ctk_list_store_append (CTK_LIST_STORE (model)((((CtkListStore*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((model)), ((ctk_list_store_get_type ()))))))
, &iter);
2497 ctk_list_store_set (CTK_LIST_STORE (model)((((CtkListStore*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((model)), ((ctk_list_store_get_type ()))))))
, &iter,
2498 0, item,
2499 1, i,
2500 -1);
2501 g_free (item);
2502 }
2503 }
2504
2505 if (field_choice->type == EV_FORM_FIELD_CHOICE_LIST) {
2506 CtkCellRenderer *renderer;
2507 CtkWidget *tree_view;
2508 CtkTreeSelection *selection;
2509
2510 tree_view = ctk_tree_view_new_with_model (model);
2511 ctk_tree_view_set_headers_visible (CTK_TREE_VIEW (tree_view)((((CtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tree_view)), ((ctk_tree_view_get_type ()))))))
, FALSE(0));
2512
2513 selection = ctk_tree_view_get_selection (CTK_TREE_VIEW (tree_view)((((CtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tree_view)), ((ctk_tree_view_get_type ()))))))
);
2514 if (field_choice->multi_select) {
2515 ctk_tree_selection_set_mode (selection, CTK_SELECTION_MULTIPLE);
2516 }
2517
2518 /* TODO: set selected items */
2519
2520 renderer = ctk_cell_renderer_text_new ();
2521 ctk_tree_view_insert_column_with_attributes (CTK_TREE_VIEW (tree_view)((((CtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tree_view)), ((ctk_tree_view_get_type ()))))))
,
2522 0,
2523 "choix", renderer,
2524 "text", 0,
2525 NULL((void*)0));
2526
2527 choice = ctk_scrolled_window_new (NULL((void*)0), NULL((void*)0));
2528 ctk_scrolled_window_set_policy (CTK_SCROLLED_WINDOW (choice)((((CtkScrolledWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((choice)), ((ctk_scrolled_window_get_type (
)))))))
,
2529 CTK_POLICY_AUTOMATIC,
2530 CTK_POLICY_AUTOMATIC);
2531 ctk_container_add (CTK_CONTAINER (choice)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((choice)), ((ctk_container_get_type ()))))))
, tree_view);
2532 ctk_widget_show (tree_view);
2533
2534 g_signal_connect (selection, "changed",g_signal_connect_data ((selection), ("changed"), (((GCallback
) (ev_view_form_field_choice_changed))), (field), ((void*)0),
(GConnectFlags) 0)
2535 G_CALLBACK (ev_view_form_field_choice_changed),g_signal_connect_data ((selection), ("changed"), (((GCallback
) (ev_view_form_field_choice_changed))), (field), ((void*)0),
(GConnectFlags) 0)
2536 field)g_signal_connect_data ((selection), ("changed"), (((GCallback
) (ev_view_form_field_choice_changed))), (field), ((void*)0),
(GConnectFlags) 0)
;
2537 g_signal_connect_after (selection, "changed",g_signal_connect_data ((selection), ("changed"), (((GCallback
) (ev_view_form_field_destroy))), (view), ((void*)0), G_CONNECT_AFTER
)
2538 G_CALLBACK (ev_view_form_field_destroy),g_signal_connect_data ((selection), ("changed"), (((GCallback
) (ev_view_form_field_destroy))), (view), ((void*)0), G_CONNECT_AFTER
)
2539 view)g_signal_connect_data ((selection), ("changed"), (((GCallback
) (ev_view_form_field_destroy))), (view), ((void*)0), G_CONNECT_AFTER
)
;
2540 } else if (field_choice->is_editable) { /* ComboBoxEntry */
2541 gchar *text;
2542
2543 choice = ctk_combo_box_new_with_model_and_entry (model);
2544 ctk_combo_box_set_entry_text_column (CTK_COMBO_BOX (choice)((((CtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((choice)), ((ctk_combo_box_get_type ()))))))
, 0);
2545 text = ev_document_forms_form_field_choice_get_text (EV_DOCUMENT_FORMS (view->document)((((EvDocumentForms*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view->document)), ((ev_document_forms_get_type ()))))
))
, field);
2546 if (text) {
2547 ctk_entry_set_text (CTK_ENTRY (ctk_bin_get_child (CTK_BIN (choice)))((((CtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((ctk_bin_get_child (((((CtkBin*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((choice)), ((ctk_bin_get_type ())))))))))
, ((ctk_entry_get_type ()))))))
, text);
2548 g_free (text);
2549 }
2550
2551 g_signal_connect (choice, "changed",g_signal_connect_data ((choice), ("changed"), (((GCallback) (
ev_view_form_field_choice_changed))), (field), ((void*)0), (GConnectFlags
) 0)
2552 G_CALLBACK (ev_view_form_field_choice_changed),g_signal_connect_data ((choice), ("changed"), (((GCallback) (
ev_view_form_field_choice_changed))), (field), ((void*)0), (GConnectFlags
) 0)
2553 field)g_signal_connect_data ((choice), ("changed"), (((GCallback) (
ev_view_form_field_choice_changed))), (field), ((void*)0), (GConnectFlags
) 0)
;
2554 g_signal_connect_after (ctk_bin_get_child (CTK_BIN (choice)),g_signal_connect_data ((ctk_bin_get_child (((((CtkBin*) (void
*) g_type_check_instance_cast ((GTypeInstance*) ((choice)), (
(ctk_bin_get_type ())))))))), ("activate"), (((GCallback) (ev_view_form_field_destroy
))), (view), ((void*)0), G_CONNECT_AFTER)
2555 "activate",g_signal_connect_data ((ctk_bin_get_child (((((CtkBin*) (void
*) g_type_check_instance_cast ((GTypeInstance*) ((choice)), (
(ctk_bin_get_type ())))))))), ("activate"), (((GCallback) (ev_view_form_field_destroy
))), (view), ((void*)0), G_CONNECT_AFTER)
2556 G_CALLBACK (ev_view_form_field_destroy),g_signal_connect_data ((ctk_bin_get_child (((((CtkBin*) (void
*) g_type_check_instance_cast ((GTypeInstance*) ((choice)), (
(ctk_bin_get_type ())))))))), ("activate"), (((GCallback) (ev_view_form_field_destroy
))), (view), ((void*)0), G_CONNECT_AFTER)
2557 view)g_signal_connect_data ((ctk_bin_get_child (((((CtkBin*) (void
*) g_type_check_instance_cast ((GTypeInstance*) ((choice)), (
(ctk_bin_get_type ())))))))), ("activate"), (((GCallback) (ev_view_form_field_destroy
))), (view), ((void*)0), G_CONNECT_AFTER)
;
2558 } else { /* ComboBoxText */
2559 CtkCellRenderer *renderer;
2560
2561 choice = ctk_combo_box_new_with_model (model);
2562 renderer = ctk_cell_renderer_text_new ();
2563 ctk_cell_layout_pack_start (CTK_CELL_LAYOUT (choice)((((CtkCellLayout*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((choice)), ((ctk_cell_layout_get_type ()))))))
,
2564 renderer, TRUE(!(0)));
2565 ctk_cell_layout_set_attributes (CTK_CELL_LAYOUT (choice)((((CtkCellLayout*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((choice)), ((ctk_cell_layout_get_type ()))))))
,
2566 renderer,
2567 "text", 0,
2568 NULL((void*)0));
2569 ctk_combo_box_set_active (CTK_COMBO_BOX (choice)((((CtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((choice)), ((ctk_combo_box_get_type ()))))))
, selected_item);
2570 ctk_combo_box_popup (CTK_COMBO_BOX (choice)((((CtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((choice)), ((ctk_combo_box_get_type ()))))))
);
2571
2572 g_signal_connect (choice, "changed",g_signal_connect_data ((choice), ("changed"), (((GCallback) (
ev_view_form_field_choice_changed))), (field), ((void*)0), (GConnectFlags
) 0)
2573 G_CALLBACK (ev_view_form_field_choice_changed),g_signal_connect_data ((choice), ("changed"), (((GCallback) (
ev_view_form_field_choice_changed))), (field), ((void*)0), (GConnectFlags
) 0)
2574 field)g_signal_connect_data ((choice), ("changed"), (((GCallback) (
ev_view_form_field_choice_changed))), (field), ((void*)0), (GConnectFlags
) 0)
;
2575 g_signal_connect_after (choice, "changed",g_signal_connect_data ((choice), ("changed"), (((GCallback) (
ev_view_form_field_destroy))), (view), ((void*)0), G_CONNECT_AFTER
)
2576 G_CALLBACK (ev_view_form_field_destroy),g_signal_connect_data ((choice), ("changed"), (((GCallback) (
ev_view_form_field_destroy))), (view), ((void*)0), G_CONNECT_AFTER
)
2577 view)g_signal_connect_data ((choice), ("changed"), (((GCallback) (
ev_view_form_field_destroy))), (view), ((void*)0), G_CONNECT_AFTER
)
;
2578 }
2579
2580 g_object_unref (model);
2581
2582 g_object_weak_ref (G_OBJECT (choice)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((choice)), (((GType) ((20) << (2))))))))
,
2583 (GWeakNotify)ev_view_form_field_choice_save,
2584 view);
2585
2586 return choice;
2587}
2588
2589void
2590_ev_view_focus_form_field (EvView *view,
2591 EvFormField *field)
2592{
2593 CtkWidget *field_widget = NULL((void*)0);
2594 EvMappingList *form_field_mapping;
2595 EvMapping *mapping;
2596
2597 _ev_view_set_focused_element (view, NULL((void*)0), -1);
2598
2599 if (field->is_read_only)
2600 return;
2601
2602 if (EV_IS_FORM_FIELD_BUTTON (field)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(field)); GType __t = ((ev_form_field_button_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
2603 field_widget = ev_view_form_field_button_create_widget (view, field);
2604 } else if (EV_IS_FORM_FIELD_TEXT (field)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(field)); GType __t = ((ev_form_field_text_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
2605 field_widget = ev_view_form_field_text_create_widget (view, field);
2606 } else if (EV_IS_FORM_FIELD_CHOICE (field)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(field)); GType __t = ((ev_form_field_choice_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
2607 field_widget = ev_view_form_field_choice_create_widget (view, field);
2608 } else if (EV_IS_FORM_FIELD_SIGNATURE (field)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(field)); GType __t = ((ev_form_field_signature_get_type()));
gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
))))
) {
2609 /* TODO */
2610 }
2611
2612 /* Form field doesn't require a widget */
2613 if (!field_widget)
2614 return;
2615
2616 g_object_set_data_full (G_OBJECT (field_widget)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((field_widget)), (((GType) ((20) << (2))))))))
, "form-field",
2617 g_object_ref (field)((__typeof__ (field)) (g_object_ref) (field)),
2618 (GDestroyNotify)g_object_unref);
2619
2620 form_field_mapping = ev_page_cache_get_form_field_mapping (view->page_cache,
2621 field->page->index);
2622 mapping = ev_mapping_list_find (form_field_mapping, field);
2623 ev_view_put_to_doc_rect (view, field_widget, field->page->index, &mapping->area);
2624 ctk_widget_show (field_widget);
2625 ctk_widget_grab_focus (field_widget);
2626}
2627
2628static void
2629ev_view_handle_form_field (EvView *view,
2630 EvFormField *field)
2631{
2632 if (field->is_read_only)
2633 return;
2634
2635 _ev_view_focus_form_field (view, field);
2636
2637 if (field->activation_link)
2638 ev_view_handle_link (view, field->activation_link);
2639
2640 if (EV_IS_FORM_FIELD_BUTTON (field)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(field)); GType __t = ((ev_form_field_button_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
2641 ev_view_form_field_button_toggle (view, field);
2642
2643}
2644
2645/* Annotations */
2646static EvViewWindowChild *
2647ev_view_get_window_child (EvView *view,
2648 CtkWidget *window)
2649{
2650 GList *children = view->window_children;
2651
2652 while (children) {
2653 EvViewWindowChild *child;
2654
2655 child = (EvViewWindowChild *)children->data;
2656 children = children->next;
2657
2658 if (child->window == window)
2659 return child;
2660 }
2661
2662 return NULL((void*)0);
2663}
2664
2665static void
2666ev_view_window_child_move (EvView *view,
2667 EvViewWindowChild *child,
2668 gint x,
2669 gint y)
2670{
2671 CtkAllocation allocation;
2672 gint width, height;
2673
2674 ctk_widget_get_allocation (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
, &allocation);
2675 ctk_window_get_size (CTK_WINDOW (child->window)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child->window)), ((ctk_window_get_type ()))))))
, &width, &height);
2676
2677 child->x = x;
2678 child->y = y;
2679 ctk_window_move (CTK_WINDOW (child->window)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child->window)), ((ctk_window_get_type ()))))))
,
2680 CLAMP (x, child->parent_x,(((x) > (child->parent_x + allocation.width - width)) ?
(child->parent_x + allocation.width - width) : (((x) <
(child->parent_x)) ? (child->parent_x) : (x)))
2681 child->parent_x + allocation.width - width)(((x) > (child->parent_x + allocation.width - width)) ?
(child->parent_x + allocation.width - width) : (((x) <
(child->parent_x)) ? (child->parent_x) : (x)))
,
2682 CLAMP (y, child->parent_y,(((y) > (child->parent_y + allocation.height - height))
? (child->parent_y + allocation.height - height) : (((y) <
(child->parent_y)) ? (child->parent_y) : (y)))
2683 child->parent_y + allocation.height - height)(((y) > (child->parent_y + allocation.height - height))
? (child->parent_y + allocation.height - height) : (((y) <
(child->parent_y)) ? (child->parent_y) : (y)))
);
2684}
2685
2686static void
2687ev_view_window_child_move_with_parent (EvView *view,
2688 CtkWidget *window)
2689{
2690 EvViewWindowChild *child;
2691 gint root_x, root_y;
2692
2693 child = ev_view_get_window_child (view, window);
2694 cdk_window_get_origin (ctk_widget_get_window (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
),
2695 &root_x, &root_y);
2696 if (root_x != child->parent_x || root_y != child->parent_y) {
2697 gint dest_x, dest_y;
2698
2699 dest_x = child->x + (root_x - child->parent_x);
2700 dest_y = child->y + (root_y - child->parent_y);
2701 child->parent_x = root_x;
2702 child->parent_y = root_y;
2703 ev_view_window_child_move (view, child, dest_x, dest_y);
2704 }
2705
2706 if (child->visible && !ctk_widget_get_visible (window))
2707 ctk_widget_show (window);
2708}
2709
2710static void
2711ev_view_window_child_put (EvView *view,
2712 CtkWidget *window,
2713 guint page,
2714 gint x,
2715 gint y,
2716 gdouble orig_x,
2717 gdouble orig_y)
2718{
2719 EvViewWindowChild *child;
2720 gint root_x, root_y;
2721
2722 cdk_window_get_origin (ctk_widget_get_window (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
),
2723 &root_x, &root_y);
2724
2725 child = g_new0 (EvViewWindowChild, 1)((EvViewWindowChild *) g_malloc0_n ((1), sizeof (EvViewWindowChild
)))
;
2726 child->window = window;
2727 child->page = page;
2728 child->orig_x = orig_x;
2729 child->orig_y = orig_y;
2730 child->parent_x = root_x;
2731 child->parent_y = root_y;
2732 child->visible = ev_annotation_window_is_open (EV_ANNOTATION_WINDOW (window)((((EvAnnotationWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((window)), ((ev_annotation_window_get_type(
)))))))
);
2733 ev_view_window_child_move (view, child, x + root_x, y + root_y);
2734
2735 if (child->visible)
2736 ctk_widget_show (window);
2737 else
2738 ctk_widget_hide (window);
2739
2740 view->window_children = g_list_append (view->window_children, child);
2741}
2742
2743static EvViewWindowChild *
2744ev_view_find_window_child_for_annot (EvView *view,
2745 guint page,
2746 EvAnnotation *annot)
2747{
2748 GList *children = view->window_children;
2749
2750 while (children) {
2751 EvViewWindowChild *child;
2752 EvAnnotation *wannot;
2753
2754 child = (EvViewWindowChild *)children->data;
2755 children = children->next;
2756
2757 if (child->page != page)
2758 continue;
2759
2760 wannot = ev_annotation_window_get_annotation (EV_ANNOTATION_WINDOW (child->window)((((EvAnnotationWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((child->window)), ((ev_annotation_window_get_type
()))))))
);
2761 if (ev_annotation_equal (wannot, annot))
2762 return child;
2763 }
2764
2765 return NULL((void*)0);
2766}
2767
2768static void
2769ev_view_window_children_free (EvView *view)
2770{
2771 GList *l;
2772
2773 if (!view->window_children)
2774 return;
2775
2776 for (l = view->window_children; l && l->data; l = g_list_next (l)((l) ? (((GList *)(l))->next) : ((void*)0))) {
2777 EvViewWindowChild *child;
2778
2779 child = (EvViewWindowChild *)l->data;
2780 ctk_widget_destroy (CTK_WIDGET (child->window)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child->window)), ((ctk_widget_get_type ()))))))
);
2781 g_free (child);
2782 }
2783 g_list_free (view->window_children);
2784 view->window_children = NULL((void*)0);
2785 view->window_child_focus = NULL((void*)0);
2786}
2787
2788static void
2789annotation_window_grab_focus (CtkWidget *widget,
2790 EvView *view)
2791{
2792 if (view->window_child_focus)
2793 ev_annotation_window_ungrab_focus (EV_ANNOTATION_WINDOW (view->window_child_focus->window)((((EvAnnotationWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((view->window_child_focus->window)), (
(ev_annotation_window_get_type()))))))
);
2794 view->window_child_focus = ev_view_get_window_child (view, widget);
2795}
2796
2797static void
2798annotation_window_closed (EvAnnotationWindow *window,
2799 EvView *view)
2800{
2801 EvViewWindowChild *child;
2802
2803 child = ev_view_get_window_child (view, CTK_WIDGET (window)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((ctk_widget_get_type ()))))))
);
2804 child->visible = FALSE(0);
2805}
2806
2807static void
2808annotation_window_moved (EvAnnotationWindow *window,
2809 gint x,
2810 gint y,
2811 EvView *view)
2812{
2813 EvViewWindowChild *child;
2814 CdkRectangle page_area;
2815 CtkBorder border;
2816 CdkRectangle view_rect;
2817 EvRectangle doc_rect;
2818 gint width, height;
2819
2820 child = ev_view_get_window_child (view, CTK_WIDGET (window)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((ctk_widget_get_type ()))))))
);
2821 if (child->x == x && child->y == y)
2822 return;
2823
2824 child->moved = TRUE(!(0));
2825 child->x = x;
2826 child->y = y;
2827
2828 /* Window has been moved by the user,
2829 * we have to set a new origin in doc coords
2830 */
2831 ctk_window_get_size (CTK_WINDOW (window)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((ctk_window_get_type ()))))))
, &width, &height);
2832 view_rect.x = (x - child->parent_x) + view->scroll_x;
2833 view_rect.y = (y - child->parent_y) + view->scroll_y;
2834 view_rect.width = width;
2835 view_rect.height = height;
2836
2837 ev_view_get_page_extents (view, child->page, &page_area, &border);
2838 _ev_view_transform_view_rect_to_doc_rect (view, &view_rect, &page_area, &doc_rect);
2839 child->orig_x = doc_rect.x1;
2840 child->orig_y = doc_rect.y1;
2841}
2842
2843static void
2844ev_view_annotation_save_contents (EvView *view,
2845 GParamSpec *pspec,
2846 EvAnnotation *annot)
2847{
2848 if (!view->document)
2849 return;
2850
2851 ev_document_doc_mutex_lock ();
2852 ev_document_annotations_save_annotation (EV_DOCUMENT_ANNOTATIONS (view->document)((((EvDocumentAnnotations*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((view->document)), ((ev_document_annotations_get_type
()))))))
,
2853 annot, EV_ANNOTATIONS_SAVE_CONTENTS);
2854 ev_document_doc_mutex_unlock ();
2855}
2856
2857static CtkWidget *
2858ev_view_create_annotation_window (EvView *view,
2859 EvAnnotation *annot,
2860 CtkWindow *parent)
2861{
2862 CtkWidget *window;
2863 EvRectangle doc_rect;
2864 CdkRectangle view_rect;
2865 guint page;
2866
2867 window = ev_annotation_window_new (annot, parent);
2868 g_signal_connect (window, "grab_focus",g_signal_connect_data ((window), ("grab_focus"), (((GCallback
) (annotation_window_grab_focus))), (view), ((void*)0), (GConnectFlags
) 0)
2869 G_CALLBACK (annotation_window_grab_focus),g_signal_connect_data ((window), ("grab_focus"), (((GCallback
) (annotation_window_grab_focus))), (view), ((void*)0), (GConnectFlags
) 0)
2870 view)g_signal_connect_data ((window), ("grab_focus"), (((GCallback
) (annotation_window_grab_focus))), (view), ((void*)0), (GConnectFlags
) 0)
;
2871 g_signal_connect (window, "closed",g_signal_connect_data ((window), ("closed"), (((GCallback) (annotation_window_closed
))), (view), ((void*)0), (GConnectFlags) 0)
2872 G_CALLBACK (annotation_window_closed),g_signal_connect_data ((window), ("closed"), (((GCallback) (annotation_window_closed
))), (view), ((void*)0), (GConnectFlags) 0)
2873 view)g_signal_connect_data ((window), ("closed"), (((GCallback) (annotation_window_closed
))), (view), ((void*)0), (GConnectFlags) 0)
;
2874 g_signal_connect (window, "moved",g_signal_connect_data ((window), ("moved"), (((GCallback) (annotation_window_moved
))), (view), ((void*)0), (GConnectFlags) 0)
2875 G_CALLBACK (annotation_window_moved),g_signal_connect_data ((window), ("moved"), (((GCallback) (annotation_window_moved
))), (view), ((void*)0), (GConnectFlags) 0)
2876 view)g_signal_connect_data ((window), ("moved"), (((GCallback) (annotation_window_moved
))), (view), ((void*)0), (GConnectFlags) 0)
;
2877 g_signal_connect_swapped (annot, "notify::contents",g_signal_connect_data ((annot), ("notify::contents"), (((GCallback
) (ev_view_annotation_save_contents))), (view), ((void*)0), G_CONNECT_SWAPPED
)
2878 G_CALLBACK (ev_view_annotation_save_contents),g_signal_connect_data ((annot), ("notify::contents"), (((GCallback
) (ev_view_annotation_save_contents))), (view), ((void*)0), G_CONNECT_SWAPPED
)
2879 view)g_signal_connect_data ((annot), ("notify::contents"), (((GCallback
) (ev_view_annotation_save_contents))), (view), ((void*)0), G_CONNECT_SWAPPED
)
;
2880 g_object_set_data (G_OBJECT (annot)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((annot)), (((GType) ((20) << (2))))))))
, "popup", window);
2881
2882 page = ev_annotation_get_page_index (annot);
2883 ev_annotation_window_get_rectangle (EV_ANNOTATION_WINDOW (window)((((EvAnnotationWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((window)), ((ev_annotation_window_get_type(
)))))))
, &doc_rect);
2884 _ev_view_transform_doc_rect_to_view_rect (view, page, &doc_rect, &view_rect);
2885 view_rect.x -= view->scroll_x;
2886 view_rect.y -= view->scroll_y;
2887
2888 ev_view_window_child_put (view, window, page,
2889 view_rect.x, view_rect.y,
2890 doc_rect.x1, doc_rect.y1);
2891
2892 return window;
2893}
2894
2895static void
2896show_annotation_windows (EvView *view,
2897 gint page)
2898{
2899 EvMappingList *annots;
2900 GList *l;
2901 CtkWindow *parent;
2902
2903 parent = CTK_WINDOW (ctk_widget_get_toplevel (CTK_WIDGET (view)))((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((ctk_widget_get_toplevel (((((CtkWidget*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((view)), ((ctk_widget_get_type ()))))))))
), ((ctk_window_get_type ()))))))
;
2904
2905 annots = ev_page_cache_get_annot_mapping (view->page_cache, page);
2906
2907 for (l = ev_mapping_list_get_list (annots); l && l->data; l = g_list_next (l)((l) ? (((GList *)(l))->next) : ((void*)0))) {
2908 EvAnnotation *annot;
2909 EvViewWindowChild *child;
2910 CtkWidget *window;
2911
2912 annot = ((EvMapping *)(l->data))->data;
2913
2914 if (!EV_IS_ANNOTATION_MARKUP (annot)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(annot)); GType __t = ((ev_annotation_markup_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
2915 continue;
2916
2917 if (!ev_annotation_markup_has_popup (EV_ANNOTATION_MARKUP (annot)((((EvAnnotationMarkup*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((annot)), ((ev_annotation_markup_get_type (
)))))))
))
2918 continue;
2919
2920 window = g_object_get_data (G_OBJECT (annot)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((annot)), (((GType) ((20) << (2))))))))
, "popup");
2921 if (window) {
2922 ev_view_window_child_move_with_parent (view, window);
2923 continue;
2924 }
2925
2926 /* Look if we already have a popup for this annot */
2927 child = ev_view_find_window_child_for_annot (view, page, annot);
2928 window = child ? child->window : NULL((void*)0);
2929 if (window) {
2930 ev_annotation_window_set_annotation (EV_ANNOTATION_WINDOW (window)((((EvAnnotationWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((window)), ((ev_annotation_window_get_type(
)))))))
, annot);
2931 g_object_set_data (G_OBJECT (annot)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((annot)), (((GType) ((20) << (2))))))))
, "popup", window);
2932 ev_view_window_child_move_with_parent (view, window);
2933 } else {
2934 ev_view_create_annotation_window (view, annot, parent);
2935 }
2936 }
2937}
2938
2939static void
2940hide_annotation_windows (EvView *view,
2941 gint page)
2942{
2943 EvMappingList *annots;
2944 GList *l;
2945
2946 annots = ev_page_cache_get_annot_mapping (view->page_cache, page);
2947
2948 for (l = ev_mapping_list_get_list (annots); l && l->data; l = g_list_next (l)((l) ? (((GList *)(l))->next) : ((void*)0))) {
2949 EvAnnotation *annot;
2950 CtkWidget *window;
2951
2952 annot = ((EvMapping *)(l->data))->data;
2953
2954 if (!EV_IS_ANNOTATION_MARKUP (annot)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(annot)); GType __t = ((ev_annotation_markup_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
2955 continue;
2956
2957 window = g_object_get_data (G_OBJECT (annot)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((annot)), (((GType) ((20) << (2))))))))
, "popup");
2958 if (window)
2959 ctk_widget_hide (window);
2960 }
2961}
2962
2963static EvMapping *
2964get_annotation_mapping_at_location (EvView *view,
2965 gdouble x,
2966 gdouble y,
2967 gint *page)
2968{
2969 gint x_new = 0, y_new = 0;
2970 EvMappingList *annotations_mapping;
2971
2972 if (!EV_IS_DOCUMENT_ANNOTATIONS (view->document)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(view->document)); GType __t = ((ev_document_annotations_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
2973 return NULL((void*)0);
2974
2975 if (!get_doc_point_from_location (view, x, y, page, &x_new, &y_new))
2976 return NULL((void*)0);
2977
2978 annotations_mapping = ev_page_cache_get_annot_mapping (view->page_cache, *page);
2979
2980 if (annotations_mapping)
2981 return ev_mapping_list_get (annotations_mapping, x_new, y_new);
2982
2983 return NULL((void*)0);
2984}
2985
2986static EvAnnotation *
2987ev_view_get_annotation_at_location (EvView *view,
2988 gdouble x,
2989 gdouble y)
2990{
2991 EvMapping *annotation_mapping;
2992 gint page;
2993
2994 annotation_mapping = get_annotation_mapping_at_location (view, x, y, &page);
2995
2996 return annotation_mapping ? annotation_mapping->data : NULL((void*)0);
2997}
2998
2999static void
3000ev_view_annotation_show_popup_window (EvView *view,
3001 CtkWidget *window)
3002{
3003 EvViewWindowChild *child;
3004
3005 if (!window)
3006 return;
3007
3008 child = ev_view_get_window_child (view, window);
3009 if (!child->visible) {
3010 child->visible = TRUE(!(0));
3011 ev_view_window_child_move (view, child, child->x, child->y);
3012 ctk_widget_show (window);
3013 }
3014}
3015
3016static void
3017ev_view_handle_annotation (EvView *view,
3018 EvAnnotation *annot,
3019 gdouble x,
3020 gdouble y,
3021 guint32 timestamp)
3022{
3023 if (EV_IS_ANNOTATION_MARKUP (annot)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(annot)); GType __t = ((ev_annotation_markup_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
3024 CtkWidget *window;
3025
3026 window = g_object_get_data (G_OBJECT (annot)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((annot)), (((GType) ((20) << (2))))))))
, "popup");
3027 ev_view_annotation_show_popup_window (view, window);
3028 }
3029
3030 if (EV_IS_ANNOTATION_ATTACHMENT (annot)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(annot)); GType __t = ((ev_annotation_attachment_get_type()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
))))
) {
3031 EvAttachment *attachment;
3032
3033 attachment = ev_annotation_attachment_get_attachment (EV_ANNOTATION_ATTACHMENT (annot)((((EvAnnotationAttachment*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((annot)), ((ev_annotation_attachment_get_type
()))))))
);
3034 if (attachment) {
3035 GError *error = NULL((void*)0);
3036
3037 ev_attachment_open (attachment,
3038 ctk_widget_get_screen (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
),
3039 timestamp,
3040 &error);
3041
3042 if (error) {
3043 g_warning ("%s", error->message);
3044 g_error_free (error);
3045 }
3046 }
3047 }
3048}
3049
3050static void
3051ev_view_create_annotation (EvView *view,
3052 EvAnnotationType annot_type,
3053 gint x,
3054 gint y)
3055{
3056 EvAnnotation *annot;
3057 CdkPoint point;
3058 CdkRectangle page_area;
3059 CtkBorder border;
3060 EvRectangle doc_rect, popup_rect;
3061 EvPage *page;
3062 CdkColor color = { 0, 65535, 65535, 0 };
3063 CdkRectangle view_rect;
3064 cairo_region_t *region;
3065
3066 point.x = x;
3067 point.y = y;
3068 ev_view_get_page_extents (view, view->current_page, &page_area, &border);
3069 _ev_view_transform_view_point_to_doc_point (view, &point, &page_area,
3070 &doc_rect.x1, &doc_rect.y1);
3071 doc_rect.x2 = doc_rect.x1 + 24;
3072 doc_rect.y2 = doc_rect.y1 + 24;
3073
3074 ev_document_doc_mutex_lock ();
3075 page = ev_document_get_page (view->document, view->current_page);
3076 switch (annot_type) {
3077 case EV_ANNOTATION_TYPE_TEXT:
3078 annot = ev_annotation_text_new (page);
3079 break;
3080 case EV_ANNOTATION_TYPE_ATTACHMENT:
3081 /* TODO */
3082 g_object_unref (page);
3083 ev_document_doc_mutex_unlock ();
3084 return;
3085 default:
3086 g_assert_not_reached ()do { g_assertion_message_expr ("LectorView", "ev-view.c", 3086
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
3087 }
3088 g_object_unref (page);
3089
3090 ev_annotation_set_color (annot, &color);
3091
3092 if (EV_IS_ANNOTATION_MARKUP (annot)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(annot)); GType __t = ((ev_annotation_markup_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
3093 popup_rect.x1 = doc_rect.x2;
3094 popup_rect.x2 = popup_rect.x1 + 200;
3095 popup_rect.y1 = doc_rect.y2;
3096 popup_rect.y2 = popup_rect.y1 + 150;
3097 g_object_set (annot,
3098 "rectangle", &popup_rect,
3099 "has_popup", TRUE(!(0)),
3100 "popup_is_open", FALSE(0),
3101 "label", g_get_real_name (),
3102 "opacity", 1.0,
3103 NULL((void*)0));
3104 }
3105 ev_document_annotations_add_annotation (EV_DOCUMENT_ANNOTATIONS (view->document)((((EvDocumentAnnotations*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((view->document)), ((ev_document_annotations_get_type
()))))))
,
3106 annot, &doc_rect);
3107 ev_document_doc_mutex_unlock ();
3108
3109 /* If the page didn't have annots, mark the cache as dirty */
3110 if (!ev_page_cache_get_annot_mapping (view->page_cache, view->current_page))
3111 ev_page_cache_mark_dirty (view->page_cache, view->current_page, EV_PAGE_DATA_INCLUDE_ANNOTS);
3112
3113 if (EV_IS_ANNOTATION_MARKUP (annot)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(annot)); GType __t = ((ev_annotation_markup_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
3114 CtkWindow *parent;
3115 CtkWidget *window;
3116
3117 parent = CTK_WINDOW (ctk_widget_get_toplevel (CTK_WIDGET (view)))((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((ctk_widget_get_toplevel (((((CtkWidget*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((view)), ((ctk_widget_get_type ()))))))))
), ((ctk_window_get_type ()))))))
;
3118 window = ev_view_create_annotation_window (view, annot, parent);
3119
3120 /* Show the annot window the first time */
3121 ev_view_annotation_show_popup_window (view, window);
3122 }
3123
3124 _ev_view_transform_doc_rect_to_view_rect (view, view->current_page, &doc_rect, &view_rect);
3125 view_rect.x -= view->scroll_x;
3126 view_rect.y -= view->scroll_y;
3127 region = cairo_region_create_rectangle (&view_rect);
3128 ev_view_reload_page (view, view->current_page, region);
3129 cairo_region_destroy (region);
3130
3131 g_signal_emit (view, signals[SIGNAL_ANNOT_ADDED], 0, annot);
3132}
3133
3134void
3135ev_view_focus_annotation (EvView *view,
3136 EvMapping *annot_mapping)
3137{
3138
3139 if (!EV_IS_DOCUMENT_ANNOTATIONS (view->document)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(view->document)); GType __t = ((ev_document_annotations_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
3140 return;
3141
3142 _ev_view_set_focused_element (view, annot_mapping,
3143 ev_annotation_get_page_index (EV_ANNOTATION (annot_mapping->data)((((EvAnnotation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((annot_mapping->data)), ((ev_annotation_get_type()))))
))
));
3144}
3145
3146void
3147ev_view_begin_add_annotation (EvView *view,
3148 EvAnnotationType annot_type)
3149{
3150 if (annot_type == EV_ANNOTATION_TYPE_UNKNOWN)
3151 return;
3152
3153 if (view->adding_annot)
3154 return;
3155
3156 view->adding_annot = TRUE(!(0));
3157 view->adding_annot_type = annot_type;
3158 ev_view_set_cursor (view, EV_VIEW_CURSOR_ADD);
3159}
3160
3161void
3162ev_view_cancel_add_annotation (EvView *view)
3163{
3164 gint x, y;
3165
3166 if (!view->adding_annot)
3167 return;
3168
3169 view->adding_annot = FALSE(0);
3170 ev_document_misc_get_pointer_position (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
, &x, &y);
3171 ev_view_handle_cursor_over_xy (view, x, y);
3172}
3173
3174void
3175ev_view_remove_annotation (EvView *view,
3176 EvAnnotation *annot)
3177{
3178 guint page;
3179
3180 g_return_if_fail (EV_IS_VIEW (view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ev_view_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("LectorView", ((const char*
) (__func__)), "EV_IS_VIEW (view)"); return; } } while (0)
;
3181 g_return_if_fail (EV_IS_ANNOTATION (annot))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((annot)); GType __t = ((ev_annotation_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("LectorView", ((const char*
) (__func__)), "EV_IS_ANNOTATION (annot)"); return; } } while
(0)
;
3182
3183 g_object_ref (annot)((__typeof__ (annot)) (g_object_ref) (annot));
3184
3185 page = ev_annotation_get_page_index (annot);
3186
3187 if (EV_IS_ANNOTATION_MARKUP (annot)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(annot)); GType __t = ((ev_annotation_markup_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
3188 EvViewWindowChild *child;
3189
3190 child = ev_view_find_window_child_for_annot (view, page, annot);
3191 if (child) {
3192 view->window_children = g_list_remove (view->window_children, child);
3193 ctk_widget_destroy (child->window);
3194 g_free (child);
3195 }
3196 }
3197 _ev_view_set_focused_element (view, NULL((void*)0), -1);
3198
3199 ev_document_doc_mutex_lock ();
3200 ev_document_annotations_remove_annotation (EV_DOCUMENT_ANNOTATIONS (view->document)((((EvDocumentAnnotations*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((view->document)), ((ev_document_annotations_get_type
()))))))
,
3201 annot);
3202 ev_document_doc_mutex_unlock ();
3203
3204 ev_page_cache_mark_dirty (view->page_cache, page, EV_PAGE_DATA_INCLUDE_ANNOTS);
3205
3206 /* FIXME: only redraw the annot area */
3207 ev_view_reload_page (view, page, NULL((void*)0));
3208
3209 g_signal_emit (view, signals[SIGNAL_ANNOT_REMOVED], 0, annot);
3210 g_object_unref (annot);
3211}
3212
3213static gboolean
3214ev_view_synctex_backward_search (EvView *view,
3215 gdouble x,
3216 gdouble y)
3217{
3218 gint page = -1;
3219 gint x_new = 0, y_new = 0;
3220 EvSourceLink *link;
3221
3222 if (!ev_document_has_synctex (view->document))
3223 return FALSE(0);
3224
3225 if (!get_doc_point_from_location (view, x, y, &page, &x_new, &y_new))
3226 return FALSE(0);
3227
3228 link = ev_document_synctex_backward_search (view->document, page, x_new, y_new);
3229 if (link) {
3230 g_signal_emit (view, signals[SIGNAL_SYNC_SOURCE], 0, link);
3231 ev_source_link_free (link);
3232
3233 return TRUE(!(0));
3234 }
3235
3236 return FALSE(0);
3237}
3238
3239/* Caret navigation */
3240#define CURSOR_ON_MULTIPLIER2 2
3241#define CURSOR_OFF_MULTIPLIER1 1
3242#define CURSOR_PEND_MULTIPLIER3 3
3243#define CURSOR_DIVIDER3 3
3244
3245static inline gboolean
3246cursor_is_in_visible_page (EvView *view)
3247{
3248 return (view->cursor_page == view->current_page ||
3249 (view->cursor_page >= view->start_page &&
3250 view->cursor_page <= view->end_page));
3251}
3252
3253static gboolean
3254cursor_should_blink (EvView *view)
3255{
3256 if (view->caret_enabled &&
3257 view->rotation == 0 &&
3258 cursor_is_in_visible_page (view) &&
3259 ctk_widget_has_focus (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
) &&
3260 view->pixbuf_cache &&
3261 !ev_pixbuf_cache_get_selection_region (view->pixbuf_cache, view->cursor_page, view->scale)) {
3262 CtkSettings *settings;
3263 gboolean blink;
3264
3265 settings = ctk_widget_get_settings (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
3266 g_object_get (settings, "ctk-cursor-blink", &blink, NULL((void*)0));
3267
3268 return blink;
3269 }
3270
3271 return FALSE(0);
3272}
3273
3274static gint
3275get_cursor_blink_time (EvView *view)
3276{
3277 CtkSettings *settings = ctk_widget_get_settings (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
3278 gint time;
3279
3280 g_object_get (settings, "ctk-cursor-blink-time", &time, NULL((void*)0));
3281
3282 return time;
3283}
3284
3285static gint
3286get_cursor_blink_timeout_id (EvView *view)
3287{
3288 CtkSettings *settings = ctk_widget_get_settings (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
3289 gint timeout;
3290
3291 g_object_get (settings, "ctk-cursor-blink-timeout", &timeout, NULL((void*)0));
3292
3293 return timeout;
3294}
3295
3296static gboolean
3297get_caret_cursor_area (EvView *view,
3298 gint page,
3299 gint offset,
3300 CdkRectangle *area)
3301{
3302 EvRectangle *areas = NULL((void*)0);
3303 EvRectangle *doc_rect;
3304 guint n_areas = 0;
3305 gfloat cursor_aspect_ratio;
3306 gint stem_width;
3307
3308 if (!view->caret_enabled || view->rotation != 0)
3309 return FALSE(0);
3310
3311 if (!view->page_cache)
3312 return FALSE(0);
3313
3314 ev_page_cache_get_text_layout (view->page_cache, page, &areas, &n_areas);
3315 if (!areas)
3316 return FALSE(0);
3317
3318 if (offset > n_areas)
3319 return FALSE(0);
3320
3321 doc_rect = areas + offset;
3322 if (offset == n_areas ||
3323 ((doc_rect->x1 == doc_rect->x2 || doc_rect->y1 == doc_rect->y2) && offset > 0)) {
3324 EvRectangle *prev;
3325 EvRectangle last_rect;
3326
3327 /* Special characters like \n have an empty bounding box
3328 * and the end of a page doesn't have any bounding box,
3329 * use the size of the previous area.
3330 */
3331 prev = areas + offset - 1;
3332 last_rect.x1 = prev->x2;
3333 last_rect.y1 = prev->y1;
3334 last_rect.x2 = prev->x2 + (prev->x2 - prev->x1);
3335 last_rect.y2 = prev->y2;
3336
3337 _ev_view_transform_doc_rect_to_view_rect (view, page, &last_rect, area);
3338 } else {
3339 _ev_view_transform_doc_rect_to_view_rect (view, page, doc_rect, area);
3340 }
3341
3342 area->x -= view->scroll_x;
3343 area->y -= view->scroll_y;
3344
3345 ctk_style_context_get_style (ctk_widget_get_style_context (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
),
3346 "cursor-aspect-ratio", &cursor_aspect_ratio,
3347 NULL((void*)0));
3348 stem_width = area->height * cursor_aspect_ratio + 1;
3349 area->x -= (stem_width / 2);
3350 area->width = stem_width;
3351
3352 return TRUE(!(0));
3353}
3354
3355static void
3356show_cursor (EvView *view)
3357{
3358 CtkWidget *widget;
3359 CdkRectangle view_rect;
3360
3361 if (view->cursor_visible)
3362 return;
3363
3364 widget = CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
;
3365 view->cursor_visible = TRUE(!(0));
3366 if (ctk_widget_has_focus (widget) &&
3367 get_caret_cursor_area (view, view->cursor_page, view->cursor_offset, &view_rect)) {
3368 ctk_widget_queue_draw_area (widget,
3369 view_rect.x, view_rect.y,
3370 view_rect.width, view_rect.height);
3371 }
3372}
3373
3374static void
3375hide_cursor (EvView *view)
3376{
3377 CtkWidget *widget;
3378 CdkRectangle view_rect;
3379
3380 if (!view->cursor_visible)
3381 return;
3382
3383 widget = CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
;
3384 view->cursor_visible = FALSE(0);
3385 if (ctk_widget_has_focus (widget) &&
3386 get_caret_cursor_area (view, view->cursor_page, view->cursor_offset, &view_rect)) {
3387 ctk_widget_queue_draw_area (widget,
3388 view_rect.x, view_rect.y,
3389 view_rect.width, view_rect.height);
3390 }
3391}
3392
3393static gboolean
3394blink_cb (EvView *view)
3395{
3396 gint blink_timeout;
3397 guint blink_time;
3398
3399 blink_timeout = get_cursor_blink_timeout_id (view);
3400 if (view->cursor_blink_time > 1000 * blink_timeout && blink_timeout < G_MAXINT2147483647 / 1000) {
3401 /* We've blinked enough without the user doing anything, stop blinking */
3402 show_cursor (view);
3403 view->cursor_blink_timeout_id = 0;
3404
3405 return FALSE(0);
3406 }
3407
3408 blink_time = get_cursor_blink_time (view);
3409 if (view->cursor_visible) {
3410 hide_cursor (view);
3411 blink_time *= CURSOR_OFF_MULTIPLIER1;
3412 } else {
3413 show_cursor (view);
3414 view->cursor_blink_time += blink_time;
3415 blink_time *= CURSOR_ON_MULTIPLIER2;
3416 }
3417
3418 view->cursor_blink_timeout_id = cdk_threads_add_timeout (blink_time / CURSOR_DIVIDER3, (GSourceFunc)blink_cb, view);
3419
3420 return FALSE(0);
3421}
3422
3423static void
3424ev_view_check_cursor_blink (EvView *view)
3425{
3426 if (cursor_should_blink (view)) {
3427 if (view->cursor_blink_timeout_id == 0) {
3428 show_cursor (view);
3429 view->cursor_blink_timeout_id = cdk_threads_add_timeout (get_cursor_blink_time (view) * CURSOR_ON_MULTIPLIER2 / CURSOR_DIVIDER3,
3430 (GSourceFunc)blink_cb, view);
3431 }
3432
3433 return;
3434 }
3435
3436 if (view->cursor_blink_timeout_id > 0) {
3437 g_source_remove (view->cursor_blink_timeout_id);
3438 view->cursor_blink_timeout_id = 0;
3439 }
3440
3441 view->cursor_visible = TRUE(!(0));
3442 view->cursor_blink_time = 0;
3443}
3444
3445static void
3446ev_view_pend_cursor_blink (EvView *view)
3447{
3448 if (!cursor_should_blink (view))
3449 return;
3450
3451 if (view->cursor_blink_timeout_id > 0)
3452 g_source_remove (view->cursor_blink_timeout_id);
3453
3454 show_cursor (view);
3455 view->cursor_blink_timeout_id = cdk_threads_add_timeout (get_cursor_blink_time (view) * CURSOR_PEND_MULTIPLIER3 / CURSOR_DIVIDER3,
3456 (GSourceFunc)blink_cb, view);
3457}
3458
3459gboolean
3460ev_view_supports_caret_navigation (EvView *view)
3461{
3462 EvDocumentTextInterface *iface;
3463
3464 if (!view->document || !EV_IS_DOCUMENT_TEXT (view->document)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(view->document)); GType __t = ((ev_document_text_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
3465 return FALSE(0);
3466
3467 iface = EV_DOCUMENT_TEXT_GET_IFACE (view->document)((((EvDocumentTextInterface*) g_type_interface_peek (((GTypeInstance
*) ((view->document)))->g_class, ((ev_document_text_get_type
()))))))
;
3468 if (!iface->get_text_layout || !iface->get_text)
3469 return FALSE(0);
3470
3471 return TRUE(!(0));
3472}
3473
3474void
3475ev_view_set_caret_navigation_enabled (EvView *view,
3476 gboolean enabled)
3477{
3478 g_return_if_fail (EV_IS_VIEW (view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ev_view_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("LectorView", ((const char*
) (__func__)), "EV_IS_VIEW (view)"); return; } } while (0)
;
3479
3480 if (view->caret_enabled != enabled) {
3481 view->caret_enabled = enabled;
3482 ev_view_check_cursor_blink (view);
3483
3484 if (cursor_is_in_visible_page (view))
3485 ctk_widget_queue_draw (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
3486 }
3487}
3488
3489gboolean
3490ev_view_is_caret_navigation_enabled (EvView *view)
3491{
3492 g_return_val_if_fail (EV_IS_VIEW (view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ev_view_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("LectorView", ((const char*
) (__func__)), "EV_IS_VIEW (view)"); return ((0)); } } while (
0)
;
3493
3494 return view->caret_enabled;
3495}
3496
3497void
3498ev_view_set_caret_cursor_position (EvView *view,
3499 guint page,
3500 guint offset)
3501{
3502 g_return_if_fail (EV_IS_VIEW (view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ev_view_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("LectorView", ((const char*
) (__func__)), "EV_IS_VIEW (view)"); return; } } while (0)
;
3503 g_return_if_fail (EV_IS_DOCUMENT (view->document))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view->document)); GType __t = ((ev_document_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("LectorView"
, ((const char*) (__func__)), "EV_IS_DOCUMENT (view->document)"
); return; } } while (0)
;
3504 g_return_if_fail (page < ev_document_get_n_pages (view->document))do { if ((page < ev_document_get_n_pages (view->document
))) { } else { g_return_if_fail_warning ("LectorView", ((const
char*) (__func__)), "page < ev_document_get_n_pages (view->document)"
); return; } } while (0)
;
3505
3506 if (view->cursor_page != page || view->cursor_offset != offset) {
3507 view->cursor_page = page;
3508 view->cursor_offset = offset;
3509
3510 g_signal_emit (view, signals[SIGNAL_CURSOR_MOVED], 0,
3511 view->cursor_page, view->cursor_offset);
3512
3513 if (view->caret_enabled && cursor_is_in_visible_page (view))
3514 ctk_widget_queue_draw (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
3515 }
3516}
3517
3518/*** CtkWidget implementation ***/
3519
3520static void
3521ev_view_size_request_continuous_dual_page (EvView *view,
3522 CtkRequisition *requisition)
3523{
3524 gint n_pages;
3525
3526 n_pages = ev_document_get_n_pages (view->document) + 1;
3527 get_page_y_offset (view, n_pages, &requisition->height);
3528
3529 switch (view->sizing_mode) {
3530 case EV_SIZING_FIT_WIDTH:
3531 case EV_SIZING_FIT_PAGE:
3532 case EV_SIZING_AUTOMATIC:
3533 requisition->width = 1;
3534
3535 break;
3536 case EV_SIZING_FREE: {
3537 gint max_width;
3538 CtkBorder border;
3539
3540 ev_view_get_max_page_size (view, &max_width, NULL((void*)0));
3541 compute_border (view, &border);
3542 requisition->width = (max_width + border.left + border.right) * 2 + (view->spacing * 3);
3543 }
3544 break;
3545 default:
3546 g_assert_not_reached ()do { g_assertion_message_expr ("LectorView", "ev-view.c", 3546
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
3547 }
3548}
3549
3550static void
3551ev_view_size_request_continuous (EvView *view,
3552 CtkRequisition *requisition)
3553{
3554 gint n_pages;
3555
3556 n_pages = ev_document_get_n_pages (view->document);
3557 get_page_y_offset (view, n_pages, &requisition->height);
3558
3559 switch (view->sizing_mode) {
3560 case EV_SIZING_FIT_WIDTH:
3561 case EV_SIZING_FIT_PAGE:
3562 case EV_SIZING_AUTOMATIC:
3563 requisition->width = 1;
3564
3565 break;
3566 case EV_SIZING_FREE: {
3567 gint max_width;
3568 CtkBorder border;
3569
3570 ev_view_get_max_page_size (view, &max_width, NULL((void*)0));
3571 compute_border (view, &border);
3572 requisition->width = max_width + (view->spacing * 2) + border.left + border.right;
3573 }
3574 break;
3575 default:
3576 g_assert_not_reached ()do { g_assertion_message_expr ("LectorView", "ev-view.c", 3576
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
3577 }
3578}
3579
3580static void
3581ev_view_size_request_dual_page (EvView *view,
3582 CtkRequisition *requisition)
3583{
3584 CtkBorder border;
3585 gint width, height;
3586
3587 if (view->sizing_mode == EV_SIZING_FIT_PAGE) {
3588 requisition->width = 1;
3589 requisition->height = 1;
3590
3591 return;
3592 }
3593
3594 /* Find the largest of the two. */
3595 ev_view_get_page_size (view,
3596 view->current_page,
3597 &width, &height);
3598 if (view->current_page + 1 < ev_document_get_n_pages (view->document)) {
3599 gint width_2, height_2;
3600 ev_view_get_page_size (view,
3601 view->current_page + 1,
3602 &width_2, &height_2);
3603 if (width_2 > width) {
3604 width = width_2;
3605 height = height_2;
3606 }
3607 }
3608 compute_border (view, &border);
3609
3610 requisition->width = view->sizing_mode == EV_SIZING_FIT_WIDTH ? 1 :
3611 ((width + border.left + border.right) * 2) + (view->spacing * 3);
3612 requisition->height = (height + border.top + border.bottom) + (view->spacing * 2);
3613}
3614
3615static void
3616ev_view_size_request_single_page (EvView *view,
3617 CtkRequisition *requisition)
3618{
3619 CtkBorder border;
3620 gint width, height;
3621
3622 if (view->sizing_mode == EV_SIZING_FIT_PAGE) {
3623 requisition->width = 1;
3624 requisition->height = 1;
3625
3626 return;
3627 }
3628
3629 ev_view_get_page_size (view, view->current_page, &width, &height);
3630 compute_border (view, &border);
3631
3632 requisition->width = view->sizing_mode == EV_SIZING_FIT_WIDTH ? 1 :
3633 width + border.left + border.right + (2 * view->spacing);
3634 requisition->height = height + border.top + border.bottom + (2 * view->spacing);
3635}
3636
3637static void
3638ev_view_size_request (CtkWidget *widget,
3639 CtkRequisition *requisition)
3640{
3641 EvView *view = EV_VIEW (widget)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ev_view_get_type ()))))))
;
3642 gboolean dual_page;
3643
3644 if (view->document == NULL((void*)0)) {
3645 view->requisition.width = 1;
3646 view->requisition.height = 1;
3647
3648 *requisition = view->requisition;
3649
3650 return;
3651 }
3652
3653 /* Get zoom for size here when not called from
3654 * ev_view_size_allocate()
3655 */
3656 if (!view->internal_size_request &&
3657 (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
3658 view->sizing_mode == EV_SIZING_FIT_PAGE ||
3659 view->sizing_mode == EV_SIZING_AUTOMATIC)) {
3660 CtkAllocation allocation;
3661
3662 ctk_widget_get_allocation (widget, &allocation);
3663 ev_view_zoom_for_size (view,
3664 allocation.width,
3665 allocation.height);
3666 }
3667
3668 dual_page = is_dual_page (view, NULL((void*)0));
3669 if (view->continuous && dual_page)
3670 ev_view_size_request_continuous_dual_page (view, &view->requisition);
3671 else if (view->continuous)
3672 ev_view_size_request_continuous (view, &view->requisition);
3673 else if (dual_page)
3674 ev_view_size_request_dual_page (view, &view->requisition);
3675 else
3676 ev_view_size_request_single_page (view, &view->requisition);
3677
3678 *requisition = view->requisition;
3679}
3680
3681static void
3682ev_view_get_preferred_width (CtkWidget *widget,
3683 gint *minimum,
3684 gint *natural)
3685{
3686 CtkRequisition requisition;
3687
3688 ev_view_size_request (widget, &requisition);
3689
3690 *minimum = *natural = requisition.width;
3691}
3692
3693static void
3694ev_view_get_preferred_height (CtkWidget *widget,
3695 gint *minimum,
3696 gint *natural)
3697{
3698 CtkRequisition requisition;
3699
3700 ev_view_size_request (widget, &requisition);
3701
3702 *minimum = *natural = requisition.height;
3703}
3704
3705static void
3706ev_view_size_allocate (CtkWidget *widget,
3707 CtkAllocation *allocation)
3708{
3709 EvView *view = EV_VIEW (widget)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ev_view_get_type ()))))))
;
3710 GList *l;
3711 gint root_x, root_y;
3712
3713 ctk_widget_set_allocation (widget, allocation);
3714
3715 if (ctk_widget_get_realized (widget))
3716 cdk_window_move_resize (ctk_widget_get_window (widget),
3717 allocation->x,
3718 allocation->y,
3719 allocation->width,
3720 allocation->height);
3721
3722 if (!view->document)
3723 return;
3724
3725 if (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
3726 view->sizing_mode == EV_SIZING_FIT_PAGE ||
3727 view->sizing_mode == EV_SIZING_AUTOMATIC) {
3728 CtkRequisition req;
3729
3730 ev_view_zoom_for_size (view,
3731 allocation->width,
3732 allocation->height);
3733 view->internal_size_request = TRUE(!(0));
3734 ev_view_size_request (widget, &req);
3735 view->internal_size_request = FALSE(0);
3736 }
3737
3738 view_set_adjustment_values (view, CTK_ORIENTATION_HORIZONTAL);
3739 view_set_adjustment_values (view, CTK_ORIENTATION_VERTICAL);
3740
3741 if (view->document)
3742 view_update_range_and_current_page (view);
3743
3744 view->pending_scroll = SCROLL_TO_KEEP_POSITION;
3745 view->pending_resize = FALSE(0);
3746 view->pending_point.x = 0;
3747 view->pending_point.y = 0;
3748
3749 for (l = view->children; l && l->data; l = g_list_next (l)((l) ? (((GList *)(l))->next) : ((void*)0))) {
3750 CdkRectangle view_area;
3751 EvViewChild *child = (EvViewChild *)l->data;
3752
3753 if (!ctk_widget_get_visible (child->widget))
3754 continue;
3755
3756 _ev_view_transform_doc_rect_to_view_rect (view, child->page, &child->doc_rect, &view_area);
3757 view_area.x -= view->scroll_x;
3758 view_area.y -= view->scroll_y;
3759
3760 ctk_widget_set_size_request (child->widget, view_area.width, view_area.height);
3761 ctk_widget_size_allocate (child->widget, &view_area);
3762 }
3763
3764 if (view->window_children)
3765 cdk_window_get_origin (ctk_widget_get_window (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
),
3766 &root_x, &root_y);
3767
3768 for (l = view->window_children; l && l->data; l = g_list_next (l)((l) ? (((GList *)(l))->next) : ((void*)0))) {
3769 EvViewWindowChild *child;
3770 EvRectangle doc_rect;
3771 CdkRectangle view_rect;
3772
3773 child = (EvViewWindowChild *)l->data;
3774
3775 ev_annotation_window_get_rectangle (EV_ANNOTATION_WINDOW (child->window)((((EvAnnotationWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((child->window)), ((ev_annotation_window_get_type
()))))))
, &doc_rect);
3776 if (child->moved) {
3777 doc_rect.x1 = child->orig_x;
3778 doc_rect.y1 = child->orig_y;
3779 }
3780 _ev_view_transform_doc_rect_to_view_rect (view, child->page, &doc_rect, &view_rect);
3781 view_rect.x -= view->scroll_x;
3782 view_rect.y -= view->scroll_y;
3783
3784 if (view_rect.x != child->orig_x || view_rect.y != child->orig_y) {
3785 child->parent_x = root_x;
3786 child->parent_y = root_y;
3787 ev_view_window_child_move (view, child, view_rect.x + root_x, view_rect.y + root_y);
3788 }
3789 }
3790}
3791
3792static gboolean
3793ev_view_scroll_event (CtkWidget *widget, CdkEventScroll *event)
3794{
3795 EvView *view = EV_VIEW (widget)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ev_view_get_type ()))))))
;
3796 guint state;
3797 gboolean fit_width, fit_height;
3798
3799 state = event->state & ctk_accelerator_get_default_mod_mask ();
3800
3801 if (state == CDK_CONTROL_MASK) {
3802 ev_document_model_set_sizing_mode (view->model, EV_SIZING_FREE);
3803 view->zoom_center_x = event->x;
3804 view->zoom_center_y = event->y;
3805 switch (event->direction) {
3806 case CDK_SCROLL_DOWN:
3807 case CDK_SCROLL_RIGHT:
3808 if (ev_view_can_zoom_out (view))
3809 ev_view_zoom_out (view);
3810 break;
3811 case CDK_SCROLL_UP:
3812 case CDK_SCROLL_LEFT:
3813 if (ev_view_can_zoom_in (view))
3814 ev_view_zoom_in (view);
3815 break;
3816 case CDK_SCROLL_SMOOTH: {
3817 gdouble delta = event->delta_x + event->delta_y;
3818 gdouble factor = pow (delta < 0 ? ZOOM_IN_FACTOR1.2 : ZOOM_OUT_FACTOR(1.0/1.2), fabs (delta));
3819
3820 if ((factor < 1.0 && ev_view_can_zoom_out (view)) ||
3821 (factor >= 1.0 && ev_view_can_zoom_in (view)))
3822 ev_view_zoom (view, factor);
3823 }
3824 break;
3825 }
3826
3827 return TRUE(!(0));
3828 }
3829
3830 view->jump_to_find_result = FALSE(0);
3831
3832 /* Shift+Wheel scrolls the in the perpendicular direction */
3833 if (state & CDK_SHIFT_MASK) {
3834 if (event->direction == CDK_SCROLL_UP)
3835 event->direction = CDK_SCROLL_LEFT;
3836 else if (event->direction == CDK_SCROLL_LEFT)
3837 event->direction = CDK_SCROLL_UP;
3838 else if (event->direction == CDK_SCROLL_DOWN)
3839 event->direction = CDK_SCROLL_RIGHT;
3840 else if (event->direction == CDK_SCROLL_RIGHT)
3841 event->direction = CDK_SCROLL_DOWN;
3842 else if (event->direction == CDK_SCROLL_SMOOTH) {
3843 /* Swap the deltas for perpendicular direction */
3844 gdouble tmp_delta = event->delta_x;
3845
3846 event->delta_x = event->delta_y;
3847 event->delta_y = tmp_delta;
3848 }
3849
3850 event->state &= ~CDK_SHIFT_MASK;
3851 state &= ~CDK_SHIFT_MASK;
3852 }
3853
3854 fit_width = ev_view_page_fits (view, CTK_ORIENTATION_HORIZONTAL);
3855 fit_height = ev_view_page_fits (view, CTK_ORIENTATION_VERTICAL);
3856 if (state == 0 && !view->continuous && (fit_width || fit_height)) {
3857 switch (event->direction) {
3858 case CDK_SCROLL_DOWN:
3859 if (fit_height) {
3860 ev_view_next_page (view);
3861 return TRUE(!(0));
3862 }
3863 break;
3864 case CDK_SCROLL_RIGHT:
3865 if (fit_width) {
3866 ev_view_next_page (view);
3867 return TRUE(!(0));
3868 }
3869 break;
3870 case CDK_SCROLL_UP:
3871 if (fit_height) {
3872 ev_view_previous_page (view);
3873 return TRUE(!(0));
3874 }
3875 break;
3876 case CDK_SCROLL_LEFT:
3877 if (fit_width) {
3878 ev_view_previous_page (view);
3879 return TRUE(!(0));
3880 }
3881 break;
3882 case CDK_SCROLL_SMOOTH: {
3883 gdouble decrement;
3884 if ((fit_width && fit_height) ||
3885 ((fit_height && event->delta_x == 0.0) ||
3886 (fit_width && event->delta_y == 0.0))) {
3887 /* Emulate normal scrolling by summing the deltas */
3888 view->total_delta += event->delta_x + event->delta_y;
3889
3890 decrement = view->total_delta < 0 ? -1.0 : 1.0;
3891 for (; fabs (view->total_delta) >= 1.0; view->total_delta -= decrement) {
3892 if (decrement < 0)
3893 ev_view_previous_page (view);
3894 else
3895 ev_view_next_page (view);
3896 }
3897
3898 return TRUE(!(0));
3899 }
3900 }
3901 break;
3902 }
3903
3904 return FALSE(0);
3905 }
3906
3907 return FALSE(0);
3908}
3909
3910static EvViewSelection *
3911find_selection_for_page (EvView *view,
3912 gint page)
3913{
3914 GList *list;
3915
3916 for (list = view->selection_info.selections; list != NULL((void*)0); list = list->next) {
3917 EvViewSelection *selection;
3918
3919 selection = (EvViewSelection *) list->data;
3920
3921 if (selection->page == page)
3922 return selection;
3923 }
3924
3925 return NULL((void*)0);
3926}
3927
3928static void
3929ev_view_realize (CtkWidget *widget)
3930{
3931 CtkAllocation allocation;
3932 CdkWindow *window;
3933 CdkWindowAttr attributes;
3934 gint attributes_mask;
3935
3936 ctk_widget_set_realized (widget, TRUE(!(0)));
3937
3938 ctk_widget_get_allocation (widget, &allocation);
3939
3940 attributes.window_type = CDK_WINDOW_CHILD;
3941 attributes.x = allocation.x;
3942 attributes.y = allocation.y;
3943 attributes.width = allocation.width;
3944 attributes.height = allocation.height;
3945 attributes.wclass = CDK_INPUT_OUTPUT;
3946 attributes.visual = ctk_widget_get_visual (widget);
3947 attributes.event_mask = ctk_widget_get_events (widget);
3948
3949 attributes_mask = CDK_WA_X | CDK_WA_Y | CDK_WA_VISUAL;
3950
3951 window = cdk_window_new (ctk_widget_get_parent_window (widget),
3952 &attributes, attributes_mask);
3953 ctk_widget_set_window (widget, window);
3954 cdk_window_set_user_data (window, widget);
3955}
3956
3957static void
3958get_cursor_color (CtkStyleContext *context,
3959 CdkRGBA *color)
3960{
3961 CdkColor *style_color;
3962
3963 ctk_style_context_get_style (context,
3964 "cursor-color",
3965 &style_color,
3966 NULL((void*)0));
3967
3968 if (style_color) {
3969 color->red = style_color->red / 65535.0;
3970 color->green = style_color->green / 65535.0;
3971 color->blue = style_color->blue / 65535.0;
3972 color->alpha = 1;
3973
3974 cdk_color_free (style_color);
3975 } else {
3976 ctk_style_context_save (context);
3977 ctk_style_context_get_color (context, CTK_STATE_FLAG_NORMAL, color);
3978 ctk_style_context_restore (context);
3979 }
3980}
3981
3982/* This is based on the deprecated function ctk_draw_insertion_cursor. */
3983static void
3984draw_caret_cursor (EvView *view,
3985 cairo_t *cr)
3986{
3987 CdkRectangle view_rect;
3988 CdkRGBA cursor_color;
3989
3990 if (!get_caret_cursor_area (view, view->cursor_page, view->cursor_offset, &view_rect))
3991 return;
3992
3993 get_cursor_color (ctk_widget_get_style_context (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
), &cursor_color);
3994
3995 cairo_save (cr);
3996 cdk_cairo_set_source_rgba (cr, &cursor_color);
3997 cairo_rectangle (cr, view_rect.x, view_rect.y, view_rect.width, view_rect.height);
3998 cairo_fill (cr);
3999 cairo_restore (cr);
4000}
4001
4002static gboolean
4003should_draw_caret_cursor (EvView *view,
4004 gint page)
4005{
4006 return (view->caret_enabled &&
4007 view->cursor_page == page &&
4008 view->cursor_visible &&
4009 ctk_widget_has_focus (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
) &&
4010 !ev_pixbuf_cache_get_selection_region (view->pixbuf_cache, page, view->scale));
4011}
4012
4013static void
4014draw_focus (EvView *view,
4015 cairo_t *cr,
4016 gint page,
4017 CdkRectangle *clip)
4018{
4019 CtkWidget *widget = CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
;
4020 CdkRectangle rect;
4021 CdkRectangle intersect;
4022
4023 if (view->focused_element_page != page)
4024 return;
4025
4026 if (!ev_view_get_focused_area (view, &rect))
4027 return;
4028
4029 if (cdk_rectangle_intersect (&rect, clip, &intersect)) {
4030 ctk_render_focus (ctk_widget_get_style_context (widget),
4031 cr,
4032 intersect.x,
4033 intersect.y,
4034 intersect.width,
4035 intersect.height);
4036 }
4037}
4038
4039static gboolean
4040ev_view_draw (CtkWidget *widget,
4041 cairo_t *cr)
4042{
4043 EvView *view = EV_VIEW (widget)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ev_view_get_type ()))))))
;
4044 cairo_rectangle_int_t clip_rect;
4045 CdkRectangle *area = &clip_rect;
4046 gint i;
4047
4048 ctk_render_background (ctk_widget_get_style_context (widget),
4049 cr,
4050 0, 0,
4051 ctk_widget_get_allocated_width (widget),
4052 ctk_widget_get_allocated_height (widget));
4053
4054 if (view->document == NULL((void*)0))
4055 return FALSE(0);
4056
4057 if (!cdk_cairo_get_clip_rectangle (cr, &clip_rect))
4058 return FALSE(0);
4059
4060 for (i = view->start_page; i >= 0 && i <= view->end_page; i++) {
4061 CdkRectangle page_area;
4062 CtkBorder border;
4063 gboolean page_ready = TRUE(!(0));
4064
4065 if (!ev_view_get_page_extents (view, i, &page_area, &border))
4066 continue;
4067
4068 page_area.x -= view->scroll_x;
4069 page_area.y -= view->scroll_y;
4070
4071 draw_one_page (view, i, cr, &page_area, &border, area, &page_ready);
4072
4073 if (page_ready && should_draw_caret_cursor (view, i))
4074 draw_caret_cursor (view, cr);
4075 if (page_ready && view->find_pages && view->highlight_find_results)
4076 highlight_find_results (view, cr, i);
4077 if (page_ready && EV_IS_DOCUMENT_ANNOTATIONS (view->document)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(view->document)); GType __t = ((ev_document_annotations_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
4078 show_annotation_windows (view, i);
4079 if (page_ready && view->focused_element)
4080 draw_focus (view, cr, i, &clip_rect);
4081 if (page_ready && view->synctex_result)
4082 highlight_forward_search_results (view, cr, i);
4083 }
4084
4085 if (CTK_WIDGET_CLASS (ev_view_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ev_view_parent_class)), ((ctk_widget_get_type ()))))))
->draw)
4086 (* CTK_WIDGET_CLASS (ev_view_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ev_view_parent_class)), ((ctk_widget_get_type ()))))))
->draw) (widget, cr);
4087
4088 return FALSE(0);
4089}
4090
4091static void
4092ev_view_set_focused_element_at_location (EvView *view,
4093 gdouble x,
4094 gdouble y)
4095{
4096 EvMapping *mapping;
4097 EvFormField *field;
4098 gint page;
4099
4100 mapping = get_annotation_mapping_at_location (view, x, y, &page);
4101 if (mapping) {
4102 _ev_view_set_focused_element (view, mapping, page);
4103 return;
4104 }
4105
4106 mapping = get_link_mapping_at_location (view, x, y, &page);
4107 if (mapping) {
4108 _ev_view_set_focused_element (view, mapping, page);
4109 return;
4110 }
4111
4112 if ((field = ev_view_get_form_field_at_location (view, x, y))) {
4113 ev_view_remove_all (view);
4114 _ev_view_focus_form_field (view, field);
4115 return;
4116 }
4117
4118 _ev_view_set_focused_element (view, NULL((void*)0), -1);
4119}
4120
4121static gboolean
4122ev_view_do_popup_menu (EvView *view,
4123 gdouble x,
4124 gdouble y)
4125{
4126 GList *items = NULL((void*)0);
4127 EvLink *link;
4128 EvImage *image;
4129 EvAnnotation *annot;
4130
4131 image = ev_view_get_image_at_location (view, x, y);
4132 if (image)
4133 items = g_list_prepend (items, image);
4134
4135 link = ev_view_get_link_at_location (view, x, y);
4136 if (link)
4137 items = g_list_prepend (items, link);
4138
4139 annot = ev_view_get_annotation_at_location (view, x, y);
4140 if (annot)
4141 items = g_list_prepend (items, annot);
4142
4143 g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, items);
4144
4145 g_list_free (items);
4146
4147 return TRUE(!(0));
4148}
4149
4150static gboolean
4151ev_view_popup_menu (CtkWidget *widget)
4152{
4153 gint x, y;
4154
4155 ev_document_misc_get_pointer_position (widget, &x, &y);
4156 return ev_view_do_popup_menu (EV_VIEW (widget)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ev_view_get_type ()))))))
, x, y);
4157}
4158
4159static void
4160get_link_area (EvView *view,
4161 gint x,
4162 gint y,
4163 EvLink *link,
4164 CdkRectangle *area)
4165{
4166 EvMappingList *link_mapping;
4167 gint page;
4168 gint x_offset = 0, y_offset = 0;
4169
4170 x += view->scroll_x;
4171 y += view->scroll_y;
4172
4173 find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
4174
4175 link_mapping = ev_page_cache_get_link_mapping (view->page_cache, page);
4176 ev_view_get_area_from_mapping (view, page,
4177 link_mapping,
4178 link, area);
4179}
4180
4181static void
4182get_annot_area (EvView *view,
4183 gint x,
4184 gint y,
4185 EvAnnotation *annot,
4186 CdkRectangle *area)
4187{
4188 EvMappingList *annot_mapping;
4189 gint page;
4190 gint x_offset = 0, y_offset = 0;
4191
4192 x += view->scroll_x;
4193 y += view->scroll_y;
4194
4195 find_page_at_location (view, x, y, &page, &x_offset, &y_offset);
4196
4197 annot_mapping = ev_page_cache_get_annot_mapping (view->page_cache, page);
4198 ev_view_get_area_from_mapping (view, page,
4199 annot_mapping,
4200 annot, area);
4201}
4202
4203static gboolean
4204ev_view_query_tooltip (CtkWidget *widget,
4205 gint x,
4206 gint y,
4207 gboolean keyboard_tip,
4208 CtkTooltip *tooltip)
4209{
4210 EvView *view = EV_VIEW (widget)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ev_view_get_type ()))))))
;
4211 EvLink *link;
4212 EvAnnotation *annot;
4213 gchar *text;
4214
4215 annot = ev_view_get_annotation_at_location (view, x, y);
4216 if (annot) {
4217 const gchar *contents;
4218
4219 if ((contents = ev_annotation_get_contents (annot))) {
4220 CdkRectangle annot_area;
4221
4222 get_annot_area (view, x, y, annot, &annot_area);
4223 ctk_tooltip_set_text (tooltip, contents);
4224 ctk_tooltip_set_tip_area (tooltip, &annot_area);
4225
4226 return TRUE(!(0));
4227 }
4228 }
4229
4230 link = ev_view_get_link_at_location (view, x, y);
4231 if (!link)
4232 return FALSE(0);
4233
4234 text = tip_from_link (view, link);
4235 if (text && g_utf8_validate (text, -1, NULL((void*)0))) {
4236 CdkRectangle link_area;
4237
4238 get_link_area (view, x, y, link, &link_area);
4239 ctk_tooltip_set_text (tooltip, text);
4240 ctk_tooltip_set_tip_area (tooltip, &link_area);
4241 g_free (text);
4242
4243 return TRUE(!(0));
4244 }
4245 g_free (text);
4246
4247 return FALSE(0);
4248}
4249
4250static void
4251start_selection_for_event (EvView *view,
4252 CdkEventButton *event)
4253{
4254 clear_selection (view);
4255
4256 view->selection_info.start.x = event->x + view->scroll_x;
4257 view->selection_info.start.y = event->y + view->scroll_y;
4258
4259 switch (event->type) {
4260 case CDK_2BUTTON_PRESS:
4261 view->selection_info.style = EV_SELECTION_STYLE_WORD;
4262 break;
4263 case CDK_3BUTTON_PRESS:
4264 view->selection_info.style = EV_SELECTION_STYLE_LINE;
4265 break;
4266 default:
4267 view->selection_info.style = EV_SELECTION_STYLE_GLYPH;
4268 return;
4269 }
4270
4271 /* In case of WORD or LINE, compute selections now */
4272 compute_selections (view,
4273 view->selection_info.style,
4274 &(view->selection_info.start),
4275 &(view->selection_info.start));
4276}
4277
4278gint
4279_ev_view_get_caret_cursor_offset_at_doc_point (EvView *view,
4280 gint page,
4281 gdouble doc_x,
4282 gdouble doc_y)
4283{
4284 EvRectangle *areas = NULL((void*)0);
4285 guint n_areas = 0;
4286 gint offset = -1;
4287 gint first_line_offset;
4288 gint last_line_offset = -1;
4289 EvRectangle *rect;
4290 guint i;
4291
4292 ev_page_cache_get_text_layout (view->page_cache, page, &areas, &n_areas);
4293 if (!areas)
4294 return -1;
4295
4296 i = 0;
4297 while (i < n_areas && offset == -1) {
4298 rect = areas + i;
4299
4300 first_line_offset = -1;
4301 while (doc_y >= rect->y1 && doc_y <= rect->y2) {
4302 if (first_line_offset == -1) {
4303 if (doc_x <= rect->x1) {
4304 /* Location is before the start of the line */
4305 if (last_line_offset != -1) {
4306 EvRectangle *last = areas + last_line_offset;
4307 gint dx1, dx2;
4308
4309 /* If there's a previous line, check distances */
4310
4311 dx1 = doc_x - last->x2;
4312 dx2 = rect->x1 - doc_x;
4313
4314 if (dx1 < dx2)
4315 offset = last_line_offset;
4316 else
4317 offset = i;
4318 } else {
4319 offset = i;
4320 }
4321
4322 last_line_offset = i + 1;
4323 break;
4324 }
4325 first_line_offset = i;
4326 }
4327 last_line_offset = i + 1;
4328
4329 if (doc_x >= rect->x1 && doc_x <= rect->x2) {
4330 /* Location is inside the line. Position the caret before
4331 * or after the character, depending on whether the point
4332 * falls within the left or right half of the bounding box.
4333 */
4334 if (doc_x <= rect->x1 + (rect->x2 - rect->x1) / 2)
4335 offset = i;
4336 else
4337 offset = i + 1;
4338 break;
4339 }
4340
4341 i++;
4342 rect = areas + i;
4343 }
4344
4345 if (first_line_offset == -1)
4346 i++;
4347 }
4348
4349 if (last_line_offset == -1)
4350 return -1;
4351
4352 if (offset == -1)
4353 offset = last_line_offset;
4354
4355 return offset;
4356}
4357
4358static gboolean
4359position_caret_cursor_at_doc_point (EvView *view,
4360 gint page,
4361 gdouble doc_x,
4362 gdouble doc_y)
4363{
4364 gint offset;
4365
4366 offset = _ev_view_get_caret_cursor_offset_at_doc_point (view, page, doc_x, doc_y);
4367 if (offset == -1)
4368 return FALSE(0);
4369
4370 if (view->cursor_offset != offset || view->cursor_page != page) {
4371 view->cursor_offset = offset;
4372 view->cursor_page = page;
4373
4374 return TRUE(!(0));
4375 }
4376
4377 return FALSE(0);
4378}
4379
4380static gboolean
4381position_caret_cursor_at_location (EvView *view,
4382 gdouble x,
4383 gdouble y)
4384{
4385 gint page;
4386 gint doc_x, doc_y;
4387
4388 if (!view->caret_enabled || view->rotation != 0)
4389 return FALSE(0);
4390
4391 if (!view->page_cache)
4392 return FALSE(0);
4393
4394 /* Get the offset from the doc point */
4395 if (!get_doc_point_from_location (view, x, y, &page, &doc_x, &doc_y))
4396 return FALSE(0);
4397
4398 return position_caret_cursor_at_doc_point (view, page, doc_x, doc_y);
4399}
4400
4401static gboolean
4402position_caret_cursor_for_event (EvView *view,
4403 CdkEventButton *event,
4404 gboolean redraw)
4405{
4406 CdkRectangle area;
4407 CdkRectangle prev_area = { 0, 0, 0, 0 };
4408
4409 if (redraw)
4410 get_caret_cursor_area (view, view->cursor_page, view->cursor_offset, &prev_area);
4411
4412 if (!position_caret_cursor_at_location (view, event->x, event->y))
4413 return FALSE(0);
4414
4415 if (!get_caret_cursor_area (view, view->cursor_page, view->cursor_offset, &area))
4416 return FALSE(0);
4417
4418 view->cursor_line_offset = area.x;
4419
4420 g_signal_emit (view, signals[SIGNAL_CURSOR_MOVED], 0, view->cursor_page, view->cursor_offset);
4421
4422 if (redraw) {
4423 cairo_region_t *damage_region;
4424
4425 damage_region = cairo_region_create_rectangle (&prev_area);
4426 cairo_region_union_rectangle (damage_region, &area);
4427 cdk_window_invalidate_region (ctk_widget_get_window (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
),
4428 damage_region, TRUE(!(0)));
4429 cairo_region_destroy (damage_region);
4430 }
4431
4432 return TRUE(!(0));
4433}
4434
4435static gboolean
4436ev_view_button_press_event (CtkWidget *widget,
4437 CdkEventButton *event)
4438{
4439 EvView *view = EV_VIEW (widget)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ev_view_get_type ()))))))
;
4440
4441 if (!view->document || ev_document_get_n_pages (view->document) <= 0)
4442 return FALSE(0);
4443
4444 if (ctk_gesture_is_recognized (view->zoom_gesture))
4445 return TRUE(!(0));
4446
4447 if (!ctk_widget_has_focus (widget)) {
4448 ctk_widget_grab_focus (widget);
4449 }
4450
4451 if (view->window_child_focus) {
4452 EvAnnotationWindow *window;
4453
4454 window = EV_ANNOTATION_WINDOW (view->window_child_focus->window)((((EvAnnotationWindow*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((view->window_child_focus->window)), (
(ev_annotation_window_get_type()))))))
;
4455 ev_annotation_window_ungrab_focus (window);
4456 view->window_child_focus = NULL((void*)0);
4457 }
4458
4459 view->pressed_button = event->button;
4460 view->selection_info.in_drag = FALSE(0);
4461
4462 if (view->adding_annot)
4463 return FALSE(0);
4464
4465 if (view->scroll_info.autoscrolling)
4466 return TRUE(!(0));
4467
4468 switch (event->button) {
4469 case 1: {
4470 EvImage *image;
4471 EvAnnotation *annot;
4472 EvFormField *field;
4473 EvMapping *link;
4474 gint page;
4475
4476 if (event->state & CDK_CONTROL_MASK)
4477 return ev_view_synctex_backward_search (view, event->x , event->y);
4478
4479 if (EV_IS_SELECTION (view->document)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(view->document)); GType __t = ((ev_selection_get_type ())
); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
&& view->selection_info.selections) {
4480 if (event->type == CDK_3BUTTON_PRESS) {
4481 start_selection_for_event (view, event);
4482 } else if (event->state & CDK_SHIFT_MASK) {
4483 CdkPoint end_point;
4484
4485 end_point.x = event->x + view->scroll_x;
4486 end_point.y = event->y + view->scroll_y;
4487 extend_selection (view, &view->selection_info.start, &end_point);
4488 } else if (location_in_selected_text (view,
4489 event->x + view->scroll_x,
4490 event->y + view->scroll_y)) {
4491 view->selection_info.in_drag = TRUE(!(0));
4492 } else {
4493 start_selection_for_event (view, event);
4494 if (position_caret_cursor_for_event (view, event, TRUE(!(0)))) {
4495 view->cursor_blink_time = 0;
4496 ev_view_pend_cursor_blink (view);
4497 }
4498 }
4499 } else if ((annot = ev_view_get_annotation_at_location (view, event->x, event->y))) {
4500 ev_view_handle_annotation (view, annot, event->x, event->y, event->time);
4501 } else if ((field = ev_view_get_form_field_at_location (view, event->x, event->y))) {
4502 ev_view_remove_all (view);
4503 ev_view_handle_form_field (view, field);
4504 } else if ((link = get_link_mapping_at_location (view, event->x, event->y, &page))){
4505 _ev_view_set_focused_element (view, link, page);
4506 } else if (!location_in_text (view, event->x + view->scroll_x, event->y + view->scroll_y) &&
4507 (image = ev_view_get_image_at_location (view, event->x, event->y))) {
4508 if (view->image_dnd_info.image)
4509 g_object_unref (view->image_dnd_info.image);
4510 view->image_dnd_info.image = g_object_ref (image)((__typeof__ (image)) (g_object_ref) (image));
4511 view->image_dnd_info.in_drag = TRUE(!(0));
4512
4513 view->image_dnd_info.start.x = event->x + view->scroll_x;
4514 view->image_dnd_info.start.y = event->y + view->scroll_y;
4515 } else {
4516 ev_view_remove_all (view);
4517 _ev_view_set_focused_element (view, NULL((void*)0), -1);
4518
4519 if (view->synctex_result) {
4520 g_free (view->synctex_result);
4521 view->synctex_result = NULL((void*)0);
4522 ctk_widget_queue_draw (widget);
4523 }
4524
4525 if (EV_IS_SELECTION (view->document)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(view->document)); GType __t = ((ev_selection_get_type ())
); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
4526 start_selection_for_event (view, event);
4527
4528 if (position_caret_cursor_for_event (view, event, TRUE(!(0)))) {
4529 view->cursor_blink_time = 0;
4530 ev_view_pend_cursor_blink (view);
4531 }
4532 }
4533 }
4534 return TRUE(!(0));
4535 case 2:
4536 /* use root coordinates as reference point because
4537 * scrolling changes window relative coordinates */
4538 view->drag_info.start.x = event->x_root;
4539 view->drag_info.start.y = event->y_root;
4540 view->drag_info.hadj = ctk_adjustment_get_value (view->hadjustment);
4541 view->drag_info.vadj = ctk_adjustment_get_value (view->vadjustment);
4542
4543 ev_view_set_cursor (view, EV_VIEW_CURSOR_DRAG);
4544 ev_view_set_focused_element_at_location (view, event->x, event->y);
4545 return TRUE(!(0));
4546 case 3:
4547 view->scroll_info.start_y = event->y;
4548 ev_view_set_focused_element_at_location (view, event->x, event->y);
4549 return ev_view_do_popup_menu (view, event->x, event->y);
4550 }
4551
4552 return FALSE(0);
4553}
4554
4555static void
4556ev_view_remove_all (EvView *view)
4557{
4558 ctk_container_foreach (CTK_CONTAINER (view)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_container_get_type ()))))))
, (CtkCallback) ctk_widget_destroy, NULL((void*)0));
4559 GList *children, *child;
4560
4561 children = ctk_container_get_children (CTK_CONTAINER (view)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_container_get_type ()))))))
);
4562 for (child = children; child && child->data; child = g_list_next (child)((child) ? (((GList *)(child))->next) : ((void*)0))) {
4563 ctk_container_remove (CTK_CONTAINER (view)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_container_get_type ()))))))
,
4564 CTK_WIDGET (child->data)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child->data)), ((ctk_widget_get_type ()))))))
);
4565 }
4566 g_list_free (children);
4567}
4568
4569/*** Drag and Drop ***/
4570static void
4571ev_view_drag_data_get (CtkWidget *widget,
4572 CdkDragContext *context,
4573 CtkSelectionData *selection_data,
4574 guint info,
4575 guint time)
4576{
4577 EvView *view = EV_VIEW (widget)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ev_view_get_type ()))))))
;
4578
4579 switch (info) {
4580 case TARGET_DND_TEXT:
4581 if (EV_IS_SELECTION (view->document)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(view->document)); GType __t = ((ev_selection_get_type ())
); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
&&
4582 view->selection_info.selections) {
4583 gchar *text;
4584
4585 text = get_selected_text (view);
4586 ctk_selection_data_set_text (selection_data,
4587 text,
4588 strlen (text));
4589 g_free (text);
4590 }
4591 break;
4592 case TARGET_DND_IMAGE:
4593 if (view->image_dnd_info.image) {
4594 GdkPixbuf *pixbuf;
4595
4596 ev_document_doc_mutex_lock ();
4597 pixbuf = ev_document_images_get_image (EV_DOCUMENT_IMAGES (view->document)((((EvDocumentImages*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((view->document)), ((ev_document_images_get_type
()))))))
,
4598 view->image_dnd_info.image);
4599 ev_document_doc_mutex_unlock ();
4600
4601 ctk_selection_data_set_pixbuf (selection_data, pixbuf);
4602 g_object_unref (pixbuf);
4603 }
4604 break;
4605 case TARGET_DND_URI:
4606 if (view->image_dnd_info.image) {
4607 GdkPixbuf *pixbuf;
4608 const gchar *tmp_uri;
4609 gchar *uris[2];
4610
4611 ev_document_doc_mutex_lock ();
4612 pixbuf = ev_document_images_get_image (EV_DOCUMENT_IMAGES (view->document)((((EvDocumentImages*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((view->document)), ((ev_document_images_get_type
()))))))
,
4613 view->image_dnd_info.image);
4614 ev_document_doc_mutex_unlock ();
4615
4616 tmp_uri = ev_image_save_tmp (view->image_dnd_info.image, pixbuf);
4617 g_object_unref (pixbuf);
4618
4619 uris[0] = (gchar *)tmp_uri;
4620 uris[1] = NULL((void*)0);
4621 ctk_selection_data_set_uris (selection_data, uris);
4622 }
4623 }
4624}
4625
4626static gboolean
4627ev_view_drag_motion (CtkWidget *widget,
4628 CdkDragContext *context,
4629 gint x,
4630 gint y,
4631 guint time)
4632{
4633 if (ctk_drag_get_source_widget (context) == widget)
4634 cdk_drag_status (context, 0, time);
4635 else
4636 cdk_drag_status (context, cdk_drag_context_get_suggested_action (context), time);
4637
4638 return TRUE(!(0));
4639}
4640
4641static gboolean
4642selection_update_idle_cb (EvView *view)
4643{
4644 compute_selections (view,
4645 view->selection_info.style,
4646 &view->selection_info.start,
4647 &view->motion);
4648 view->selection_update_id = 0;
4649 return FALSE(0);
4650}
4651
4652static gboolean
4653selection_scroll_timeout_cb (EvView *view)
4654{
4655 gint x, y, shift = 0;
4656 CtkWidget *widget = CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
;
4657 CtkAllocation allocation;
4658
4659 ctk_widget_get_allocation (widget, &allocation);
4660 ev_document_misc_get_pointer_position (widget, &x, &y);
4661
4662 if (y > allocation.height) {
4663 shift = (y - allocation.height) / 2;
4664 } else if (y < 0) {
4665 shift = y / 2;
4666 }
4667
4668 if (shift)
4669 ctk_adjustment_set_value (view->vadjustment,
4670 CLAMP (ctk_adjustment_get_value (view->vadjustment) + shift,(((ctk_adjustment_get_value (view->vadjustment) + shift) >
(ctk_adjustment_get_upper (view->vadjustment) - ctk_adjustment_get_page_size
(view->vadjustment))) ? (ctk_adjustment_get_upper (view->
vadjustment) - ctk_adjustment_get_page_size (view->vadjustment
)) : (((ctk_adjustment_get_value (view->vadjustment) + shift
) < (ctk_adjustment_get_lower (view->vadjustment))) ? (
ctk_adjustment_get_lower (view->vadjustment)) : (ctk_adjustment_get_value
(view->vadjustment) + shift)))
4671 ctk_adjustment_get_lower (view->vadjustment),(((ctk_adjustment_get_value (view->vadjustment) + shift) >
(ctk_adjustment_get_upper (view->vadjustment) - ctk_adjustment_get_page_size
(view->vadjustment))) ? (ctk_adjustment_get_upper (view->
vadjustment) - ctk_adjustment_get_page_size (view->vadjustment
)) : (((ctk_adjustment_get_value (view->vadjustment) + shift
) < (ctk_adjustment_get_lower (view->vadjustment))) ? (
ctk_adjustment_get_lower (view->vadjustment)) : (ctk_adjustment_get_value
(view->vadjustment) + shift)))
4672 ctk_adjustment_get_upper (view->vadjustment) -(((ctk_adjustment_get_value (view->vadjustment) + shift) >
(ctk_adjustment_get_upper (view->vadjustment) - ctk_adjustment_get_page_size
(view->vadjustment))) ? (ctk_adjustment_get_upper (view->
vadjustment) - ctk_adjustment_get_page_size (view->vadjustment
)) : (((ctk_adjustment_get_value (view->vadjustment) + shift
) < (ctk_adjustment_get_lower (view->vadjustment))) ? (
ctk_adjustment_get_lower (view->vadjustment)) : (ctk_adjustment_get_value
(view->vadjustment) + shift)))
4673 ctk_adjustment_get_page_size (view->vadjustment))(((ctk_adjustment_get_value (view->vadjustment) + shift) >
(ctk_adjustment_get_upper (view->vadjustment) - ctk_adjustment_get_page_size
(view->vadjustment))) ? (ctk_adjustment_get_upper (view->
vadjustment) - ctk_adjustment_get_page_size (view->vadjustment
)) : (((ctk_adjustment_get_value (view->vadjustment) + shift
) < (ctk_adjustment_get_lower (view->vadjustment))) ? (
ctk_adjustment_get_lower (view->vadjustment)) : (ctk_adjustment_get_value
(view->vadjustment) + shift)))
);
4674
4675 if (x > allocation.width) {
4676 shift = (x - allocation.width) / 2;
4677 } else if (x < 0) {
4678 shift = x / 2;
4679 }
4680
4681 if (shift)
4682 ctk_adjustment_set_value (view->hadjustment,
4683 CLAMP (ctk_adjustment_get_value (view->hadjustment) + shift,(((ctk_adjustment_get_value (view->hadjustment) + shift) >
(ctk_adjustment_get_upper (view->hadjustment) - ctk_adjustment_get_page_size
(view->hadjustment))) ? (ctk_adjustment_get_upper (view->
hadjustment) - ctk_adjustment_get_page_size (view->hadjustment
)) : (((ctk_adjustment_get_value (view->hadjustment) + shift
) < (ctk_adjustment_get_lower (view->hadjustment))) ? (
ctk_adjustment_get_lower (view->hadjustment)) : (ctk_adjustment_get_value
(view->hadjustment) + shift)))
4684 ctk_adjustment_get_lower (view->hadjustment),(((ctk_adjustment_get_value (view->hadjustment) + shift) >
(ctk_adjustment_get_upper (view->hadjustment) - ctk_adjustment_get_page_size
(view->hadjustment))) ? (ctk_adjustment_get_upper (view->
hadjustment) - ctk_adjustment_get_page_size (view->hadjustment
)) : (((ctk_adjustment_get_value (view->hadjustment) + shift
) < (ctk_adjustment_get_lower (view->hadjustment))) ? (
ctk_adjustment_get_lower (view->hadjustment)) : (ctk_adjustment_get_value
(view->hadjustment) + shift)))
4685 ctk_adjustment_get_upper (view->hadjustment) -(((ctk_adjustment_get_value (view->hadjustment) + shift) >
(ctk_adjustment_get_upper (view->hadjustment) - ctk_adjustment_get_page_size
(view->hadjustment))) ? (ctk_adjustment_get_upper (view->
hadjustment) - ctk_adjustment_get_page_size (view->hadjustment
)) : (((ctk_adjustment_get_value (view->hadjustment) + shift
) < (ctk_adjustment_get_lower (view->hadjustment))) ? (
ctk_adjustment_get_lower (view->hadjustment)) : (ctk_adjustment_get_value
(view->hadjustment) + shift)))
4686 ctk_adjustment_get_page_size (view->hadjustment))(((ctk_adjustment_get_value (view->hadjustment) + shift) >
(ctk_adjustment_get_upper (view->hadjustment) - ctk_adjustment_get_page_size
(view->hadjustment))) ? (ctk_adjustment_get_upper (view->
hadjustment) - ctk_adjustment_get_page_size (view->hadjustment
)) : (((ctk_adjustment_get_value (view->hadjustment) + shift
) < (ctk_adjustment_get_lower (view->hadjustment))) ? (
ctk_adjustment_get_lower (view->hadjustment)) : (ctk_adjustment_get_value
(view->hadjustment) + shift)))
);
4687
4688 return TRUE(!(0));
4689}
4690
4691static gboolean
4692ev_view_drag_update_momentum (EvView *view)
4693{
4694 int i;
4695 if (!view->drag_info.in_drag)
4696 return FALSE(0);
4697
4698 for (i = DRAG_HISTORY10 - 1; i > 0; i--) {
4699 view->drag_info.buffer[i].x = view->drag_info.buffer[i-1].x;
4700 view->drag_info.buffer[i].y = view->drag_info.buffer[i-1].y;
4701 }
4702
4703 /* Momentum is a moving average of 10ms granularity over
4704 * the last 100ms with each 10ms stored in buffer.
4705 */
4706
4707 view->drag_info.momentum.x = (view->drag_info.buffer[DRAG_HISTORY10 - 1].x - view->drag_info.buffer[0].x);
4708 view->drag_info.momentum.y = (view->drag_info.buffer[DRAG_HISTORY10 - 1].y - view->drag_info.buffer[0].y);
4709
4710 return TRUE(!(0));
4711}
4712
4713static gboolean
4714ev_view_scroll_drag_release (EvView *view)
4715{
4716 gdouble dhadj_value, dvadj_value;
4717 gdouble oldhadjustment, oldvadjustment;
4718 gdouble h_page_size, v_page_size;
4719 gdouble h_upper, v_upper;
4720 CtkAllocation allocation;
4721
4722 view->drag_info.momentum.x /= 1.2;
4723 view->drag_info.momentum.y /= 1.2; /* Alter these constants to change "friction" */
4724
4725 ctk_widget_get_allocation (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
, &allocation);
4726
4727 h_page_size = ctk_adjustment_get_page_size (view->hadjustment);
4728 v_page_size = ctk_adjustment_get_page_size (view->vadjustment);
4729
4730 dhadj_value = h_page_size *
4731 (gdouble)view->drag_info.momentum.x / allocation.width;
4732 dvadj_value = v_page_size *
4733 (gdouble)view->drag_info.momentum.y / allocation.height;
4734
4735 oldhadjustment = ctk_adjustment_get_value (view->hadjustment);
4736 oldvadjustment = ctk_adjustment_get_value (view->vadjustment);
4737
4738 h_upper = ctk_adjustment_get_upper (view->hadjustment);
4739 v_upper = ctk_adjustment_get_upper (view->vadjustment);
4740
4741 /* When we reach the edges, we need either to absorb some momentum and bounce by
4742 * multiplying it on -0.5 or stop scrolling by setting momentum to 0. */
4743 if (((oldhadjustment + dhadj_value) > (h_upper - h_page_size)) ||
4744 ((oldhadjustment + dhadj_value) < 0))
4745 view->drag_info.momentum.x = 0;
4746 if (((oldvadjustment + dvadj_value) > (v_upper - v_page_size)) ||
4747 ((oldvadjustment + dvadj_value) < 0))
4748 view->drag_info.momentum.y = 0;
4749
4750 ctk_adjustment_set_value (view->hadjustment,
4751 MIN (oldhadjustment + dhadj_value,(((oldhadjustment + dhadj_value) < (h_upper - h_page_size)
) ? (oldhadjustment + dhadj_value) : (h_upper - h_page_size))
4752 h_upper - h_page_size)(((oldhadjustment + dhadj_value) < (h_upper - h_page_size)
) ? (oldhadjustment + dhadj_value) : (h_upper - h_page_size))
);
4753 ctk_adjustment_set_value (view->vadjustment,
4754 MIN (oldvadjustment + dvadj_value,(((oldvadjustment + dvadj_value) < (v_upper - v_page_size)
) ? (oldvadjustment + dvadj_value) : (v_upper - v_page_size))
4755 v_upper - v_page_size)(((oldvadjustment + dvadj_value) < (v_upper - v_page_size)
) ? (oldvadjustment + dvadj_value) : (v_upper - v_page_size))
);
4756
4757 if (((view->drag_info.momentum.x < 1) && (view->drag_info.momentum.x > -1)) &&
4758 ((view->drag_info.momentum.y < 1) && (view->drag_info.momentum.y > -1)))
4759 return FALSE(0);
4760 else
4761 return TRUE(!(0));
4762}
4763
4764static gboolean
4765ev_view_motion_notify_event (CtkWidget *widget,
4766 CdkEventMotion *event)
4767{
4768 EvView *view = EV_VIEW (widget)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ev_view_get_type ()))))))
;
4769 CdkWindow *bin_window;
4770 gint x, y;
4771
4772 if (!view->document)
4773 return FALSE(0);
4774
4775 if (ctk_gesture_is_recognized (view->zoom_gesture))
4776 return TRUE(!(0));
4777
4778 bin_window = ctk_widget_get_window (widget);
4779
4780 if (event->is_hint || event->window != bin_window) {
4781 ev_document_misc_get_pointer_position (widget, &x, &y);
4782 } else {
4783 x = event->x;
4784 y = event->y;
4785 }
4786
4787 if (view->scroll_info.autoscrolling) {
4788 view->scroll_info.last_y = y;
4789 return TRUE(!(0));
4790 }
4791
4792 if (view->selection_info.in_drag) {
4793 if (ctk_drag_check_threshold (widget,
4794 view->selection_info.start.x,
4795 view->selection_info.start.y,
4796 x, y)) {
4797 CtkTargetList *target_list = ctk_target_list_new (NULL((void*)0), 0);
4798
4799 ctk_target_list_add_text_targets (target_list, TARGET_DND_TEXT);
4800
4801 ctk_drag_begin_with_coordinates (widget, target_list,
4802 CDK_ACTION_COPY,
4803 1, (CdkEvent *)event,
4804 event->x,
4805 event->y);
4806
4807 view->selection_info.in_drag = FALSE(0);
4808 view->pressed_button = -1;
4809
4810 ctk_target_list_unref (target_list);
4811
4812 return TRUE(!(0));
4813 }
4814 } else if (view->image_dnd_info.in_drag) {
4815 if (ctk_drag_check_threshold (widget,
4816 view->selection_info.start.x,
4817 view->selection_info.start.y,
4818 x, y)) {
4819 CtkTargetList *target_list = ctk_target_list_new (NULL((void*)0), 0);
4820
4821 ctk_target_list_add_uri_targets (target_list, TARGET_DND_URI);
4822 ctk_target_list_add_image_targets (target_list, TARGET_DND_IMAGE, TRUE(!(0)));
4823
4824 ctk_drag_begin_with_coordinates (widget, target_list,
4825 CDK_ACTION_COPY,
4826 1, (CdkEvent *)event,
4827 event->x,
4828 event->y);
4829
4830 view->image_dnd_info.in_drag = FALSE(0);
4831 view->pressed_button = -1;
4832
4833 ctk_target_list_unref (target_list);
4834
4835 return TRUE(!(0));
4836 }
4837 }
4838
4839 switch (view->pressed_button) {
4840 case 1:
4841 /* For the Lector 0.4.x release, we limit selection to un-rotated
4842 * documents only.
4843 */
4844 if (view->rotation != 0)
4845 return FALSE(0);
4846
4847 /* Schedule timeout to scroll during selection and additionally
4848 * scroll once to allow arbitrary speed. */
4849 if (!view->selection_scroll_id)
4850 view->selection_scroll_id = g_timeout_add (SCROLL_TIME150,
4851 (GSourceFunc)selection_scroll_timeout_cb,
4852 view);
4853 else
4854 selection_scroll_timeout_cb (view);
4855
4856 view->motion.x = x + view->scroll_x;
4857 view->motion.y = y + view->scroll_y;
4858
4859 /* Queue an idle to handle the motion. We do this because
4860 * handling any selection events in the motion could be slower
4861 * than new motion events reach us. We always put it in the
4862 * idle to make sure we catch up and don't visibly lag the
4863 * mouse. */
4864 if (!view->selection_update_id)
4865 view->selection_update_id = g_idle_add ((GSourceFunc)selection_update_idle_cb, view);
4866
4867 return TRUE(!(0));
4868 case 2:
4869 if (!view->drag_info.in_drag) {
4870 gboolean start;
4871 int i;
4872
4873 start = ctk_drag_check_threshold (widget,
4874 view->drag_info.start.x,
4875 view->drag_info.start.y,
4876 event->x_root,
4877 event->y_root);
4878 view->drag_info.in_drag = start;
4879 view->drag_info.drag_timeout_id = g_timeout_add (10,
4880 (GSourceFunc)ev_view_drag_update_momentum, view);
4881 /* Set 100 to choose how long it takes to build up momentum */
4882 /* Clear out previous momentum info: */
4883 for (i = 0; i < DRAG_HISTORY10; i++) {
4884 view->drag_info.buffer[i].x = event->x;
4885 view->drag_info.buffer[i].y = event->y;
4886 }
4887 view->drag_info.momentum.x = 0;
4888 view->drag_info.momentum.y = 0;
4889 }
4890
4891 if (view->drag_info.in_drag) {
4892 int dx, dy;
4893 gdouble dhadj_value, dvadj_value;
4894 CtkAllocation allocation;
4895
4896 view->drag_info.buffer[0].x = event->x;
4897 view->drag_info.buffer[0].y = event->y;
4898
4899 dx = event->x_root - view->drag_info.start.x;
4900 dy = event->y_root - view->drag_info.start.y;
4901
4902 ctk_widget_get_allocation (widget, &allocation);
4903
4904 dhadj_value = ctk_adjustment_get_page_size (view->hadjustment) *
4905 (gdouble)dx / allocation.width;
4906 dvadj_value = ctk_adjustment_get_page_size (view->vadjustment) *
4907 (gdouble)dy / allocation.height;
4908
4909 /* clamp scrolling to visible area */
4910 ctk_adjustment_set_value (view->hadjustment,
4911 MIN (view->drag_info.hadj - dhadj_value,(((view->drag_info.hadj - dhadj_value) < (ctk_adjustment_get_upper
(view->hadjustment) - ctk_adjustment_get_page_size (view->
hadjustment))) ? (view->drag_info.hadj - dhadj_value) : (ctk_adjustment_get_upper
(view->hadjustment) - ctk_adjustment_get_page_size (view->
hadjustment)))
4912 ctk_adjustment_get_upper (view->hadjustment) -(((view->drag_info.hadj - dhadj_value) < (ctk_adjustment_get_upper
(view->hadjustment) - ctk_adjustment_get_page_size (view->
hadjustment))) ? (view->drag_info.hadj - dhadj_value) : (ctk_adjustment_get_upper
(view->hadjustment) - ctk_adjustment_get_page_size (view->
hadjustment)))
4913 ctk_adjustment_get_page_size (view->hadjustment))(((view->drag_info.hadj - dhadj_value) < (ctk_adjustment_get_upper
(view->hadjustment) - ctk_adjustment_get_page_size (view->
hadjustment))) ? (view->drag_info.hadj - dhadj_value) : (ctk_adjustment_get_upper
(view->hadjustment) - ctk_adjustment_get_page_size (view->
hadjustment)))
);
4914 ctk_adjustment_set_value (view->vadjustment,
4915 MIN (view->drag_info.vadj - dvadj_value,(((view->drag_info.vadj - dvadj_value) < (ctk_adjustment_get_upper
(view->vadjustment) - ctk_adjustment_get_page_size (view->
vadjustment))) ? (view->drag_info.vadj - dvadj_value) : (ctk_adjustment_get_upper
(view->vadjustment) - ctk_adjustment_get_page_size (view->
vadjustment)))
4916 ctk_adjustment_get_upper (view->vadjustment) -(((view->drag_info.vadj - dvadj_value) < (ctk_adjustment_get_upper
(view->vadjustment) - ctk_adjustment_get_page_size (view->
vadjustment))) ? (view->drag_info.vadj - dvadj_value) : (ctk_adjustment_get_upper
(view->vadjustment) - ctk_adjustment_get_page_size (view->
vadjustment)))
4917 ctk_adjustment_get_page_size (view->vadjustment))(((view->drag_info.vadj - dvadj_value) < (ctk_adjustment_get_upper
(view->vadjustment) - ctk_adjustment_get_page_size (view->
vadjustment))) ? (view->drag_info.vadj - dvadj_value) : (ctk_adjustment_get_upper
(view->vadjustment) - ctk_adjustment_get_page_size (view->
vadjustment)))
);
4918
4919 return TRUE(!(0));
4920 }
4921
4922 break;
4923 default:
4924 ev_view_handle_cursor_over_xy (view, x, y);
4925 }
4926
4927 return FALSE(0);
4928}
4929
4930static gboolean
4931ev_view_button_release_event (CtkWidget *widget,
4932 CdkEventButton *event)
4933{
4934 EvView *view = EV_VIEW (widget)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ev_view_get_type ()))))))
;
4935 EvLink *link = NULL((void*)0);
4936
4937 view->image_dnd_info.in_drag = FALSE(0);
4938
4939 if (ctk_gesture_is_recognized (view->zoom_gesture))
4940 return TRUE(!(0));
4941
4942 if (view->scroll_info.autoscrolling) {
4943 ev_view_autoscroll_stop (view);
4944 view->pressed_button = -1;
4945
4946 return TRUE(!(0));
4947 }
4948
4949 if (view->pressed_button == 1 && event->state & CDK_CONTROL_MASK) {
4950 view->pressed_button = -1;
4951 return TRUE(!(0));
4952 }
4953
4954 if (view->drag_info.in_drag) {
4955 view->drag_info.release_timeout_id =
4956 g_timeout_add (20,
4957 (GSourceFunc)ev_view_scroll_drag_release, view);
4958 }
4959
4960 if (view->document && !view->drag_info.in_drag && view->pressed_button != 3) {
4961 link = ev_view_get_link_at_location (view, event->x, event->y);
4962 }
4963
4964 view->drag_info.in_drag = FALSE(0);
4965
4966 if (view->adding_annot && view->pressed_button == 1) {
4967 view->adding_annot = FALSE(0);
4968 ev_view_handle_cursor_over_xy (view, event->x, event->y);
4969 view->pressed_button = -1;
4970
4971 ev_view_create_annotation (view,
4972 view->adding_annot_type,
4973 event->x + view->scroll_x,
4974 event->y + view->scroll_y);
4975
4976 return FALSE(0);
4977 }
4978
4979 if (view->pressed_button == 2) {
4980 ev_view_handle_cursor_over_xy (view, event->x, event->y);
4981 }
4982
4983 view->pressed_button = -1;
4984
4985 if (view->selection_scroll_id) {
4986 g_source_remove (view->selection_scroll_id);
4987 view->selection_scroll_id = 0;
4988 }
4989 if (view->selection_update_id) {
4990 g_source_remove (view->selection_update_id);
4991 view->selection_update_id = 0;
4992 }
4993
4994 if (view->selection_info.selections) {
4995 clear_link_selected (view);
4996 ev_view_update_primary_selection (view);
4997
4998 position_caret_cursor_for_event (view, event, FALSE(0));
4999
5000 if (view->selection_info.in_drag)
5001 clear_selection (view);
5002 view->selection_info.in_drag = FALSE(0);
5003 } else if (link) {
5004 if (event->button == 2) {
5005 EvLinkAction *action;
5006 EvLinkActionType type;
5007
5008 action = ev_link_get_action (link);
5009 if (!action)
5010 return FALSE(0);
5011
5012 type = ev_link_action_get_action_type (action);
5013 if (type == EV_LINK_ACTION_TYPE_GOTO_DEST) {
5014 g_signal_emit (view,
5015 signals[SIGNAL_EXTERNAL_LINK],
5016 0, action);
5017 }
5018 } else {
5019 ev_view_handle_link (view, link);
5020 }
5021 }
5022
5023 return FALSE(0);
5024}
5025
5026static gboolean
5027ev_view_forward_key_event_to_focused_child (EvView *view,
5028 CdkEventKey *event)
5029{
5030 CtkWidget *child_widget = NULL((void*)0);
5031 CdkEventKey *new_event;
5032 gboolean handled;
5033
5034 if (view->window_child_focus) {
5035 child_widget = view->window_child_focus->window;
5036 } else if (view->children) {
5037 EvViewChild *child = (EvViewChild *)view->children->data;
5038
5039 child_widget = child->widget;
5040 } else {
5041 return FALSE(0);
5042 }
5043
5044 new_event = (CdkEventKey *) cdk_event_copy ((CdkEvent *)event);
5045 g_object_unref (new_event->window);
5046 new_event->window = ctk_widget_get_window (child_widget);
5047 if (new_event->window)
5048 g_object_ref (new_event->window)((__typeof__ (new_event->window)) (g_object_ref) (new_event
->window))
;
5049 ctk_widget_realize (child_widget);
5050 handled = ctk_widget_event (child_widget, (CdkEvent *)new_event);
5051 cdk_event_free ((CdkEvent *)new_event);
5052
5053 return handled;
5054}
5055
5056static gint
5057go_to_next_page (EvView *view,
5058 gint page)
5059{
5060 int n_pages;
5061 gboolean dual_page;
5062
5063 if (!view->document)
5064 return -1;
5065
5066 n_pages = ev_document_get_n_pages (view->document);
5067
5068 dual_page = is_dual_page (view, NULL((void*)0));
5069 page += dual_page ? 2 : 1;
5070
5071 if (page < n_pages)
5072 return page;
5073
5074 if (dual_page && page == n_pages)
5075 return page - 1;
5076
5077 return -1;
5078}
5079
5080static gint
5081go_to_previous_page (EvView *view,
5082 gint page)
5083{
5084 gboolean dual_page;
5085
5086 if (!view->document)
5087 return -1;
5088
5089 dual_page = is_dual_page (view, NULL((void*)0));
5090 page -= dual_page ? 2 : 1;
5091
5092 if (page >= 0)
5093 return page;
5094
5095 if (dual_page && page == -1)
5096 return 0;
5097
5098 return -1;
5099}
5100
5101static gboolean
5102cursor_go_to_page_start (EvView *view)
5103{
5104 view->cursor_offset = 0;
5105
5106 return TRUE(!(0));
5107}
5108
5109static gboolean
5110cursor_go_to_page_end (EvView *view)
5111{
5112 PangoLogAttr *log_attrs = NULL((void*)0);
5113 gulong n_attrs;
5114
5115 if (!view->page_cache)
5116 return FALSE(0);
5117
5118 ev_page_cache_get_text_log_attrs (view->page_cache, view->cursor_page, &log_attrs, &n_attrs);
5119 if (!log_attrs)
5120 return FALSE(0);
5121
5122 view->cursor_offset = n_attrs;
5123
5124 return TRUE(!(0));
5125}
5126
5127static gboolean
5128cursor_go_to_next_page (EvView *view)
5129{
5130 gint new_page;
5131
5132 new_page = go_to_next_page (view, view->cursor_page);
5133 if (new_page != -1) {
5134 view->cursor_page = new_page;
5135 return cursor_go_to_page_start (view);
5136 }
5137
5138 return FALSE(0);
5139}
5140
5141static gboolean
5142cursor_go_to_previous_page (EvView *view)
5143{
5144 gint new_page;
5145
5146 new_page = go_to_previous_page (view, view->cursor_page);
5147 if (new_page != -1) {
5148 view->cursor_page = new_page;
5149 return cursor_go_to_page_end (view);
5150 }
5151 return FALSE(0);
5152}
5153
5154static gboolean
5155cursor_backward_char (EvView *view)
5156{
5157 PangoLogAttr *log_attrs = NULL((void*)0);
5158 gulong n_attrs;
5159
5160 if (!view->page_cache)
5161 return FALSE(0);
5162
5163 ev_page_cache_get_text_log_attrs (view->page_cache, view->cursor_page, &log_attrs, &n_attrs);
5164 if (!log_attrs)
5165 return FALSE(0);
5166
5167 if (view->cursor_offset == 0)
5168 return cursor_go_to_previous_page (view);
5169
5170 do {
5171 view->cursor_offset--;
5172 } while (view->cursor_offset >= 0 && !log_attrs[view->cursor_offset].is_cursor_position);
5173
5174 return TRUE(!(0));
5175}
5176
5177static gboolean
5178cursor_forward_char (EvView *view)
5179{
5180 PangoLogAttr *log_attrs = NULL((void*)0);
5181 gulong n_attrs;
5182
5183 if (!view->page_cache)
5184 return FALSE(0);
5185
5186 ev_page_cache_get_text_log_attrs (view->page_cache, view->cursor_page, &log_attrs, &n_attrs);
5187 if (!log_attrs)
5188 return FALSE(0);
5189
5190 if (view->cursor_offset >= n_attrs)
5191 return cursor_go_to_next_page (view);
5192
5193 do {
5194 view->cursor_offset++;
5195 } while (view->cursor_offset <= n_attrs && !log_attrs[view->cursor_offset].is_cursor_position);
5196
5197 return TRUE(!(0));
5198}
5199
5200static gboolean
5201cursor_backward_word_start (EvView *view)
5202{
5203 PangoLogAttr *log_attrs = NULL((void*)0);
5204 gulong n_attrs;
5205 gint i, j;
5206
5207 if (!view->page_cache)
5208 return FALSE(0);
5209
5210 ev_page_cache_get_text_log_attrs (view->page_cache, view->cursor_page, &log_attrs, &n_attrs);
5211 if (!log_attrs)
5212 return FALSE(0);
5213
5214 /* Skip current word starts */
5215 for (i = view->cursor_offset; i >= 0 && log_attrs[i].is_word_start; i--);
5216 if (i <= 0) {
5217 if (cursor_go_to_previous_page (view))
5218 return cursor_backward_word_start (view);
5219 return FALSE(0);
5220 }
5221
5222 /* Move to the beginning of the word */
5223 for (j = i; j >= 0 && !log_attrs[j].is_word_start; j--);
5224 view->cursor_offset = MAX (0, j)(((0) > (j)) ? (0) : (j));
5225
5226 return TRUE(!(0));
5227}
5228
5229static gboolean
5230cursor_forward_word_end (EvView *view)
5231{
5232 PangoLogAttr *log_attrs = NULL((void*)0);
5233 gulong n_attrs;
5234 gint i, j;
5235
5236 if (!view->page_cache)
5237 return FALSE(0);
5238
5239 ev_page_cache_get_text_log_attrs (view->page_cache, view->cursor_page, &log_attrs, &n_attrs);
5240 if (!log_attrs)
5241 return FALSE(0);
5242
5243 /* Skip current current word ends */
5244 for (i = view->cursor_offset; i < n_attrs && log_attrs[i].is_word_end; i++);
5245 if (i >= n_attrs) {
5246 if (cursor_go_to_next_page (view))
5247 return cursor_forward_word_end (view);
5248 return FALSE(0);
5249 }
5250
5251 /* Move to the end of the word. */
5252 for (j = i; j < n_attrs && !log_attrs[j].is_word_end; j++);
5253 view->cursor_offset = MIN (j, n_attrs)(((j) < (n_attrs)) ? (j) : (n_attrs));
5254
5255 return TRUE(!(0));
5256}
5257
5258static gboolean
5259cursor_go_to_line_start (EvView *view)
5260{
5261 PangoLogAttr *log_attrs = NULL((void*)0);
5262 gulong n_attrs;
5263 gint i;
5264
5265 if (!view->page_cache)
5266 return FALSE(0);
5267
5268 ev_page_cache_get_text_log_attrs (view->page_cache, view->cursor_page, &log_attrs, &n_attrs);
5269 if (!log_attrs)
5270 return FALSE(0);
5271
5272 for (i = view->cursor_offset; i >= 0 && !log_attrs[i].is_mandatory_break; i--);
5273 view->cursor_offset = MAX (0, i)(((0) > (i)) ? (0) : (i));
5274
5275 return TRUE(!(0));
5276}
5277
5278static gboolean
5279cursor_backward_line (EvView *view)
5280{
5281 PangoLogAttr *log_attrs = NULL((void*)0);
5282 gulong n_attrs;
5283
5284 if (!cursor_go_to_line_start (view))
5285 return FALSE(0);
5286
5287 if (view->cursor_offset == 0)
5288 return cursor_go_to_previous_page (view);
5289
5290 ev_page_cache_get_text_log_attrs (view->page_cache, view->cursor_page, &log_attrs, &n_attrs);
5291
5292 do {
5293 view->cursor_offset--;
5294 } while (view->cursor_offset >= 0 && !log_attrs[view->cursor_offset].is_mandatory_break);
5295 view->cursor_offset = MAX (0, view->cursor_offset)(((0) > (view->cursor_offset)) ? (0) : (view->cursor_offset
))
;
5296
5297 return TRUE(!(0));
5298}
5299
5300static gboolean
5301cursor_go_to_line_end (EvView *view)
5302{
5303 PangoLogAttr *log_attrs = NULL((void*)0);
5304 gulong n_attrs;
5305 gint i;
5306
5307 if (!view->page_cache)
5308 return FALSE(0);
5309
5310 ev_page_cache_get_text_log_attrs (view->page_cache, view->cursor_page, &log_attrs, &n_attrs);
5311 if (!log_attrs)
5312 return FALSE(0);
5313
5314 for (i = view->cursor_offset + 1; i <= n_attrs && !log_attrs[i].is_mandatory_break; i++);
5315 view->cursor_offset = MIN (i, n_attrs)(((i) < (n_attrs)) ? (i) : (n_attrs));
5316
5317 if (view->cursor_offset == n_attrs)
5318 return TRUE(!(0));
5319
5320 do {
5321 view->cursor_offset--;
5322 } while (view->cursor_offset >= 0 && !log_attrs[view->cursor_offset].is_cursor_position);
5323
5324 return TRUE(!(0));
5325}
5326
5327static gboolean
5328cursor_forward_line (EvView *view)
5329{
5330 PangoLogAttr *log_attrs = NULL((void*)0);
5331 gulong n_attrs;
5332
5333 if (!cursor_go_to_line_end (view))
5334 return FALSE(0);
5335
5336 ev_page_cache_get_text_log_attrs (view->page_cache, view->cursor_page, &log_attrs, &n_attrs);
5337
5338 if (view->cursor_offset == n_attrs)
5339 return cursor_go_to_next_page (view);
5340
5341 do {
5342 view->cursor_offset++;
5343 } while (view->cursor_offset <= n_attrs && !log_attrs[view->cursor_offset].is_cursor_position);
5344
5345 return TRUE(!(0));
5346}
5347
5348static void
5349extend_selection (EvView *view,
5350 CdkPoint *start_point,
5351 CdkPoint *end_point)
5352{
5353 if (!view->selection_info.selections) {
5354 view->selection_info.start.x = start_point->x;
5355 view->selection_info.start.y = start_point->y;
5356 }
5357
5358 compute_selections (view,
5359 EV_SELECTION_STYLE_GLYPH,
5360 &(view->selection_info.start),
5361 end_point);
5362}
5363
5364static gboolean
5365cursor_clear_selection (EvView *view,
5366 gboolean forward)
5367{
5368 GList *l;
5369 EvViewSelection *selection;
5370 cairo_rectangle_int_t rect;
5371 gint doc_x, doc_y;
5372
5373 /* When clearing the selection, move the cursor to
5374 * the limits of the selection region.
5375 */
5376 if (!view->selection_info.selections)
5377 return FALSE(0);
5378
5379 l = forward ? g_list_last (view->selection_info.selections) : view->selection_info.selections;
5380 selection = (EvViewSelection *)l->data;
5381 if (!selection->covered_region || cairo_region_is_empty (selection->covered_region))
5382 return FALSE(0);
5383
5384 cairo_region_get_rectangle (selection->covered_region,
5385 forward ? cairo_region_num_rectangles (selection->covered_region) - 1 : 0,
5386 &rect);
5387
5388 if (!get_doc_point_from_offset (view, selection->page,
5389 forward ? rect.x + rect.width : rect.x,
5390 rect.y + (rect.height / 2), &doc_x, &doc_y))
5391 return FALSE(0);
5392
5393 position_caret_cursor_at_doc_point (view, selection->page, doc_x, doc_y);
5394 return TRUE(!(0));
5395}
5396
5397static gboolean
5398ev_view_move_cursor (EvView *view,
5399 CtkMovementStep step,
5400 gint count,
5401 gboolean extend_selections)
5402{
5403 CdkRectangle rect;
5404 CdkRectangle prev_rect;
5405 gint prev_offset;
5406 gint prev_page;
5407 cairo_region_t *damage_region;
5408 gboolean clear_selections = FALSE(0);
5409 const gboolean forward = count >= 0;
5410
5411 if (!view->caret_enabled || view->rotation != 0)
5412 return FALSE(0);
5413
5414 view->key_binding_handled = TRUE(!(0));
5415 view->cursor_blink_time = 0;
5416
5417 prev_offset = view->cursor_offset;
5418 prev_page = view->cursor_page;
5419
5420 clear_selections = !extend_selections && view->selection_info.selections != NULL((void*)0);
5421
5422 switch (step) {
5423 case CTK_MOVEMENT_VISUAL_POSITIONS:
5424 if (!clear_selections || !cursor_clear_selection (view, count > 0)) {
5425 while (count > 0) {
5426 cursor_forward_char (view);
5427 count--;
5428 }
5429 while (count < 0) {
5430 cursor_backward_char (view);
5431 count++;
5432 }
5433 }
5434 break;
5435 case CTK_MOVEMENT_WORDS:
5436 while (count > 0) {
5437 cursor_forward_word_end (view);
5438 count--;
5439 }
5440 while (count < 0) {
5441 cursor_backward_word_start (view);
5442 count++;
5443 }
5444 break;
5445 case CTK_MOVEMENT_DISPLAY_LINES:
5446 while (count > 0) {
5447 cursor_forward_line (view);
5448 count--;
5449 }
5450 while (count < 0) {
5451 cursor_backward_line (view);
5452 count++;
5453 }
5454 break;
5455 case CTK_MOVEMENT_DISPLAY_LINE_ENDS:
5456 if (count > 0)
5457 cursor_go_to_line_end (view);
5458 else if (count < 0)
5459 cursor_go_to_line_start (view);
5460 break;
5461 default:
5462 g_assert_not_reached ()do { g_assertion_message_expr ("LectorView", "ev-view.c", 5462
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
5463 }
5464
5465 ev_view_pend_cursor_blink (view);
5466
5467 /* Notify the user that it was not possible to move the caret cursor */
5468 if (!clear_selections &&
5469 prev_offset == view->cursor_offset && prev_page == view->cursor_page) {
5470 ctk_widget_error_bell (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
5471 return TRUE(!(0));
5472 }
5473
5474 /* Scroll to make the caret visible */
5475 if (!get_caret_cursor_area (view, view->cursor_page, view->cursor_offset, &rect))
5476 return TRUE(!(0));
5477
5478 if (step == CTK_MOVEMENT_DISPLAY_LINES) {
5479 const gint prev_cursor_offset = view->cursor_offset;
5480
5481 position_caret_cursor_at_location (view,
5482 MAX (rect.x, view->cursor_line_offset)(((rect.x) > (view->cursor_line_offset)) ? (rect.x) : (
view->cursor_line_offset))
,
5483 rect.y + (rect.height / 2));
5484 /* Make sure we didn't move the cursor in the wrong direction
5485 * in case the visual order isn't the same as the logical one,
5486 * in order to avoid cursor movement loops */
5487 if ((forward && prev_cursor_offset > view->cursor_offset) ||
5488 (!forward && prev_cursor_offset < view->cursor_offset)) {
5489 view->cursor_offset = prev_cursor_offset;
5490 }
5491 if (!clear_selections &&
5492 prev_offset == view->cursor_offset && prev_page == view->cursor_page) {
5493 ctk_widget_error_bell (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
5494 return TRUE(!(0));
5495 }
5496
5497 if (!get_caret_cursor_area (view, view->cursor_page, view->cursor_offset, &rect))
5498 return TRUE(!(0));
5499 } else {
5500 view->cursor_line_offset = rect.x;
5501 }
5502
5503 damage_region = cairo_region_create_rectangle (&rect);
5504 if (get_caret_cursor_area (view, prev_page, prev_offset, &prev_rect))
5505 cairo_region_union_rectangle (damage_region, &prev_rect);
5506
5507 rect.x += view->scroll_x;
5508 rect.y += view->scroll_y;
5509
5510 ev_document_model_set_page (view->model, view->cursor_page);
5511 ensure_rectangle_is_visible (view, &rect);
5512
5513 g_signal_emit (view, signals[SIGNAL_CURSOR_MOVED], 0, view->cursor_page, view->cursor_offset);
5514
5515 cdk_window_invalidate_region (ctk_widget_get_window (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
),
5516 damage_region, TRUE(!(0)));
5517 cairo_region_destroy (damage_region);
5518
5519 /* Select text */
5520 if (extend_selections && EV_IS_SELECTION (view->document)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(view->document)); GType __t = ((ev_selection_get_type ())
); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
) {
5521 CdkPoint start_point, end_point;
5522
5523 start_point.x = prev_rect.x + view->scroll_x;
5524 start_point.y = prev_rect.y + (prev_rect.height / 2) + view->scroll_y;
5525
5526 end_point.x = rect.x;
5527 end_point.y = rect.y + rect.height / 2;
5528
5529 extend_selection (view, &start_point, &end_point);
5530 } else if (clear_selections)
5531 clear_selection (view);
5532
5533 return TRUE(!(0));
5534}
5535
5536static gboolean
5537ev_view_key_press_event (CtkWidget *widget,
5538 CdkEventKey *event)
5539{
5540 EvView *view = EV_VIEW (widget)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ev_view_get_type ()))))))
;
5541 gboolean retval;
5542
5543 if (!view->document)
5544 return FALSE(0);
5545
5546 if (!ctk_widget_has_focus (widget))
5547 return ev_view_forward_key_event_to_focused_child (view, event);
5548
5549 /* I expected CTK+ do this for me, but it doesn't cancel
5550 * the propagation of bindings handled for the same binding set
5551 */
5552 view->key_binding_handled = FALSE(0);
5553 retval = ctk_bindings_activate_event (G_OBJECT (widget)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), (((GType) ((20) << (2))))))))
, event);
5554 view->key_binding_handled = FALSE(0);
5555
5556 return retval;
5557}
5558
5559static gint
5560ev_view_focus_in (CtkWidget *widget,
5561 CdkEventFocus *event)
5562{
5563 EvView *view = EV_VIEW (widget)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ev_view_get_type ()))))))
;
5564
5565 if (view->pixbuf_cache)
5566 ev_pixbuf_cache_style_changed (view->pixbuf_cache);
5567
5568 ev_view_check_cursor_blink (view);
5569 ctk_widget_queue_draw (widget);
5570
5571 return FALSE(0);
5572}
5573
5574static gint
5575ev_view_focus_out (CtkWidget *widget,
5576 CdkEventFocus *event)
5577{
5578 EvView *view = EV_VIEW (widget)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ev_view_get_type ()))))))
;
5579
5580 if (view->pixbuf_cache)
5581 ev_pixbuf_cache_style_changed (view->pixbuf_cache);
5582
5583 ev_view_check_cursor_blink (view);
5584 ctk_widget_queue_draw (widget);
5585
5586 return FALSE(0);
5587}
5588
5589static gboolean
5590ev_view_leave_notify_event (CtkWidget *widget, CdkEventCrossing *event)
5591{
5592 EvView *view = EV_VIEW (widget)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ev_view_get_type ()))))))
;
5593
5594 if (view->cursor != EV_VIEW_CURSOR_NORMAL)
5595 ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
5596
5597 return FALSE(0);
5598}
5599
5600static gboolean
5601ev_view_enter_notify_event (CtkWidget *widget, CdkEventCrossing *event)
5602{
5603 EvView *view = EV_VIEW (widget)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ev_view_get_type ()))))))
;
5604
5605 ev_view_handle_cursor_over_xy (view, event->x, event->y);
5606
5607 return FALSE(0);
5608}
5609
5610static void
5611ev_view_style_updated (CtkWidget *widget)
5612{
5613 if (EV_VIEW (widget)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ev_view_get_type ()))))))
->pixbuf_cache)
5614 ev_pixbuf_cache_style_changed (EV_VIEW (widget)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ev_view_get_type ()))))))
->pixbuf_cache);
5615
5616 CTK_WIDGET_CLASS (ev_view_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ev_view_parent_class)), ((ctk_widget_get_type ()))))))
->style_updated (widget);
5617}
5618
5619/*** Drawing ***/
5620
5621static void
5622draw_rubberband (EvView *view,
5623 cairo_t *cr,
5624 const CdkRectangle *rect,
5625 gdouble alpha)
5626{
5627 CtkStyleContext *context;
5628 CdkRGBA color;
5629
5630 context = ctk_widget_get_style_context (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
5631 ctk_style_context_save (context);
5632 ctk_style_context_get_background_color (context, CTK_STATE_FLAG_SELECTED, &color);
5633 ctk_style_context_restore (context);
5634
5635 cairo_save (cr);
5636
5637 cairo_set_source_rgba (cr, color.red, color.green, color.blue, alpha);
5638 cairo_rectangle (cr,
5639 rect->x - view->scroll_x,
5640 rect->y - view->scroll_y,
5641 rect->width, rect->height);
5642 cairo_fill_preserve (cr);
5643
5644 cairo_set_line_width (cr, 0.5);
5645 cairo_set_source_rgb (cr, color.red, color.green, color.blue);
5646 cairo_stroke (cr);
5647
5648 cairo_restore (cr);
5649}
5650
5651
5652static void
5653highlight_find_results (EvView *view, cairo_t *cr, int page)
5654{
5655 gint i, n_results = 0;
5656
5657 n_results = ev_view_find_get_n_results (view, page);
5658
5659 for (i = 0; i < n_results; i++) {
5660 EvRectangle *rectangle;
5661 CdkRectangle view_rectangle;
5662 gdouble alpha;
5663
5664 if (i == view->find_result && page == view->current_page) {
5665 alpha = 0.6;
5666 } else {
5667 alpha = 0.3;
5668 }
5669
5670 rectangle = ev_view_find_get_result (view, page, i);
5671 _ev_view_transform_doc_rect_to_view_rect (view, page, rectangle, &view_rectangle);
5672 draw_rubberband (view, cr, &view_rectangle, alpha);
5673 }
5674}
5675
5676static void
5677highlight_forward_search_results (EvView *view, cairo_t *cr, int page)
5678{
5679 CdkRectangle rect;
5680 EvMapping *mapping = view->synctex_result;
5681
5682 if (GPOINTER_TO_INT (mapping->data)((gint) (glong) (mapping->data)) != page)
5683 return;
5684
5685 _ev_view_transform_doc_rect_to_view_rect (view, page, &mapping->area, &rect);
5686
5687 cairo_save (cr);
5688 cairo_set_source_rgb (cr, 1., 0., 0.);
5689 cairo_rectangle (cr,
5690 rect.x - view->scroll_x,
5691 rect.y - view->scroll_y,
5692 rect.width, rect.height);
5693 cairo_stroke (cr);
5694 cairo_restore (cr);
5695}
5696
5697static void
5698draw_surface (cairo_t *cr,
5699 cairo_surface_t *surface,
5700 gint x,
5701 gint y,
5702 gint offset_x,
5703 gint offset_y,
5704 gint target_width,
5705 gint target_height)
5706{
5707 gdouble width, height;
5708 gdouble device_scale_x = 1, device_scale_y = 1;
5709
5710 cairo_surface_get_device_scale (surface, &device_scale_x, &device_scale_y);
5711 width = cairo_image_surface_get_width (surface) / device_scale_x;
5712 height = cairo_image_surface_get_height (surface) / device_scale_y;
5713
5714 cairo_save (cr);
5715 cairo_translate (cr, x, y);
5716
5717 if (width != target_width || height != target_height) {
5718 gdouble scale_x, scale_y;
5719
5720 scale_x = (gdouble)target_width / width;
5721 scale_y = (gdouble)target_height / height;
5722 cairo_pattern_set_filter (cairo_get_source (cr),
5723 CAIRO_FILTER_FAST);
5724 cairo_scale (cr, scale_x, scale_y);
5725
5726 offset_x /= scale_x;
5727 offset_y /= scale_y;
5728 }
5729
5730 cairo_surface_set_device_offset (surface,
5731 offset_x * device_scale_x,
5732 offset_y * device_scale_y);
5733 cairo_set_source_surface (cr, surface, 0, 0);
5734 cairo_paint (cr);
5735 cairo_restore (cr);
5736}
5737
5738void
5739_ev_view_get_selection_colors (EvView *view,
5740 CdkRGBA *bg_color,
5741 CdkRGBA *fg_color)
5742{
5743 CtkWidget *widget = CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
;
5744 CtkStateFlags state;
5745 CtkStyleContext *context;
5746
5747 state = ctk_widget_has_focus (widget) ? CTK_STATE_FLAG_SELECTED : CTK_STATE_FLAG_ACTIVE;
5748 context = ctk_widget_get_style_context (widget);
5749 ctk_style_context_save (context);
5750
5751 if (bg_color)
5752 ctk_style_context_get_background_color (context, state, bg_color);
5753
5754 if (fg_color)
5755 ctk_style_context_get_color (context, state, fg_color);
5756
5757 ctk_style_context_restore (context);
5758}
5759
5760static void
5761draw_selection_region (cairo_t *cr,
5762 cairo_region_t *region,
5763 CdkRGBA *color,
5764 gint x,
5765 gint y,
5766 gdouble scale_x,
5767 gdouble scale_y)
5768{
5769 cairo_save (cr);
5770 cairo_translate (cr, x, y);
5771 cairo_scale (cr, scale_x, scale_y);
5772 cdk_cairo_region (cr, region);
5773 cairo_set_source_rgb (cr, color->red, color->green, color->blue);
5774 cairo_set_operator (cr, CAIRO_OPERATOR_MULTIPLY);
5775 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
5776 cairo_fill (cr);
5777 cairo_restore (cr);
5778}
5779
5780static void
5781draw_one_page (EvView *view,
5782 gint page,
5783 cairo_t *cr,
5784 CdkRectangle *page_area,
5785 CtkBorder *border,
5786 CdkRectangle *expose_area,
5787 gboolean *page_ready)
5788{
5789 CtkStyleContext *context;
5790 CdkRectangle overlap;
5791 CdkRectangle real_page_area;
5792 gint current_page;
5793
5794 g_assert (view->document)do { if (view->document) ; else g_assertion_message_expr (
"LectorView", "ev-view.c", 5794, ((const char*) (__func__)), "view->document"
); } while (0)
;
5795
5796 if (! cdk_rectangle_intersect (page_area, expose_area, &overlap))
5797 return;
5798
5799 /* Render the document itself */
5800 real_page_area = *page_area;
5801
5802 real_page_area.x += border->left;
5803 real_page_area.y += border->top;
5804 real_page_area.width -= (border->left + border->right);
5805 real_page_area.height -= (border->top + border->bottom);
5806 *page_ready = TRUE(!(0));
5807
5808 context = ctk_widget_get_style_context (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
5809 current_page = ev_document_model_get_page (view->model);
5810
5811 ctk_style_context_save (context);
5812 ctk_style_context_add_class (context, EV_STYLE_CLASS_DOCUMENT_PAGE"document-page");
5813 if (ev_document_model_get_inverted_colors (view->model))
5814 ctk_style_context_add_class (context, EV_STYLE_CLASS_INVERTED"inverted");
5815
5816 if (view->continuous && page == current_page)
5817 ctk_style_context_set_state (context, CTK_STATE_FLAG_ACTIVE);
5818
5819 ctk_render_background (context, cr, page_area->x, page_area->y, page_area->width, page_area->height);
5820 ctk_render_frame (context, cr, page_area->x, page_area->y, page_area->width, page_area->height);
5821 ctk_style_context_restore (context);
5822
5823 if (cdk_rectangle_intersect (&real_page_area, expose_area, &overlap)) {
5824 gint width, height;
5825 cairo_surface_t *page_surface = NULL((void*)0);
5826 cairo_surface_t *selection_surface = NULL((void*)0);
5827 gint offset_x, offset_y;
5828 cairo_region_t *region = NULL((void*)0);
5829
5830 page_surface = ev_pixbuf_cache_get_surface (view->pixbuf_cache, page);
5831
5832 if (!page_surface) {
5833 if (page == current_page)
5834 ev_view_set_loading (view, TRUE(!(0)));
5835
5836 *page_ready = FALSE(0);
5837
5838 return;
5839 }
5840
5841 if (page == current_page)
5842 ev_view_set_loading (view, FALSE(0));
5843
5844 ev_view_get_page_size (view, page, &width, &height);
5845 offset_x = overlap.x - real_page_area.x;
5846 offset_y = overlap.y - real_page_area.y;
5847
5848 draw_surface (cr, page_surface, overlap.x, overlap.y, offset_x, offset_y, width, height);
5849
5850 /* Get the selection pixbuf iff we have something to draw */
5851 if (!find_selection_for_page (view, page))
5852 return;
5853
5854 selection_surface = ev_pixbuf_cache_get_selection_surface (view->pixbuf_cache,
5855 page,
5856 view->scale);
5857 if (selection_surface) {
5858 draw_surface (cr, selection_surface, overlap.x, overlap.y, offset_x, offset_y,
5859 width, height);
5860 return;
5861 }
5862
5863 region = ev_pixbuf_cache_get_selection_region (view->pixbuf_cache,
5864 page,
5865 view->scale);
5866 if (region) {
5867 double scale_x, scale_y;
5868 CdkRGBA color;
5869 double device_scale_x = 1, device_scale_y = 1;
5870
5871 scale_x = (gdouble)width / cairo_image_surface_get_width (page_surface);
5872 scale_y = (gdouble)height / cairo_image_surface_get_height (page_surface);
5873
5874 cairo_surface_get_device_scale (page_surface, &device_scale_x, &device_scale_y);
5875
5876 scale_x *= device_scale_x;
5877 scale_y *= device_scale_y;
5878
5879 _ev_view_get_selection_colors (view, &color, NULL((void*)0));
5880 draw_selection_region (cr, region, &color, real_page_area.x, real_page_area.y,
5881 scale_x, scale_y);
5882 }
5883 }
5884}
5885
5886/*** GObject functions ***/
5887
5888static void
5889ev_view_finalize (GObject *object)
5890{
5891 EvView *view = EV_VIEW (object)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ev_view_get_type ()))))))
;
5892
5893 if (view->selection_info.selections) {
5894 g_list_free_full (view->selection_info.selections, (GDestroyNotify)selection_free);
5895 view->selection_info.selections = NULL((void*)0);
5896 }
5897 clear_link_selected (view);
5898
5899 if (view->synctex_result) {
5900 g_free (view->synctex_result);
5901 view->synctex_result = NULL((void*)0);
5902 }
5903
5904 if (view->image_dnd_info.image)
5905 g_object_unref (view->image_dnd_info.image);
5906 view->image_dnd_info.image = NULL((void*)0);
5907
5908 g_object_unref (view->zoom_gesture);
5909
5910 G_OBJECT_CLASS (ev_view_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ev_view_parent_class)), (((GType) ((20) << (2)))))
)))
->finalize (object);
5911}
5912
5913static void
5914ev_view_dispose (GObject *object)
5915{
5916 EvView *view = EV_VIEW (object)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ev_view_get_type ()))))))
;
5917
5918 if (view->model) {
5919 g_object_unref (view->model);
5920 view->model = NULL((void*)0);
5921 }
5922
5923 if (view->pixbuf_cache) {
5924 g_object_unref (view->pixbuf_cache);
5925 view->pixbuf_cache = NULL((void*)0);
5926 }
5927
5928 if (view->document) {
5929 g_object_unref (view->document);
5930 view->document = NULL((void*)0);
5931 }
5932
5933 if (view->page_cache) {
5934 g_object_unref (view->page_cache);
5935 view->page_cache = NULL((void*)0);
5936 }
5937
5938 ev_view_window_children_free (view);
5939
5940 if (view->selection_scroll_id) {
5941 g_source_remove (view->selection_scroll_id);
5942 view->selection_scroll_id = 0;
5943 }
5944
5945 if (view->selection_update_id) {
5946 g_source_remove (view->selection_update_id);
5947 view->selection_update_id = 0;
5948 }
5949
5950 if (view->scroll_info.timeout_id) {
5951 g_source_remove (view->scroll_info.timeout_id);
5952 view->scroll_info.timeout_id = 0;
5953 }
5954
5955 if (view->drag_info.drag_timeout_id) {
5956 g_source_remove (view->drag_info.drag_timeout_id);
5957 view->drag_info.drag_timeout_id = 0;
5958 }
5959
5960 if (view->drag_info.release_timeout_id) {
5961 g_source_remove (view->drag_info.release_timeout_id);
5962 view->drag_info.release_timeout_id = 0;
5963 }
5964
5965 if (view->cursor_blink_timeout_id) {
5966 g_source_remove (view->cursor_blink_timeout_id);
5967 view->cursor_blink_timeout_id = 0;
5968 }
5969
5970 g_clear_object(&view->accessible)do { _Static_assert (sizeof *((&view->accessible)) == sizeof
(gpointer), "Expression evaluates to false"); __typeof__ (((
&view->accessible))) _pp = ((&view->accessible)
); __typeof__ (*((&view->accessible))) _ptr = *_pp; *_pp
= ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while (0)
;
5971
5972 G_OBJECT_CLASS (ev_view_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ev_view_parent_class)), (((GType) ((20) << (2)))))
)))
->dispose (object);
5973}
5974
5975static void
5976ev_view_get_property (GObject *object,
5977 guint prop_id,
5978 GValue *value,
5979 GParamSpec *pspec)
5980{
5981 EvView *view = EV_VIEW (object)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ev_view_get_type ()))))))
;
5982
5983 switch (prop_id) {
5984 case PROP_IS_LOADING:
5985 g_value_set_boolean (value, view->loading);
5986 break;
5987 case PROP_HADJUSTMENT:
5988 g_value_set_object (value, view->hadjustment);
5989 break;
5990 case PROP_VADJUSTMENT:
5991 g_value_set_object (value, view->vadjustment);
5992 break;
5993 case PROP_HSCROLL_POLICY:
5994 g_value_set_enum (value, view->hscroll_policy);
5995 break;
5996 case PROP_VSCROLL_POLICY:
5997 g_value_set_enum (value, view->vscroll_policy);
5998 break;
5999 default:
6000 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec
*_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id
= ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'"
, "ev-view.c", 6000, ("property"), _glib__property_id, _glib__pspec
->name, g_type_name ((((((GTypeClass*) (((GTypeInstance*) (
_glib__pspec))->g_class))->g_type)))), (g_type_name (((
(((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class
))->g_type)))))); } while (0)
;
6001 break;
6002 }
6003}
6004
6005static void
6006ev_view_set_property (GObject *object,
6007 guint prop_id,
6008 const GValue *value,
6009 GParamSpec *pspec)
6010{
6011 EvView *view = EV_VIEW (object)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ev_view_get_type ()))))))
;
6012
6013 switch (prop_id) {
6014 case PROP_IS_LOADING:
6015 ev_view_set_loading (view, g_value_get_boolean (value));
6016 break;
6017 case PROP_HADJUSTMENT:
6018 set_scroll_adjustment (view, CTK_ORIENTATION_HORIZONTAL,
6019 (CtkAdjustment *) g_value_get_object (value));
6020 break;
6021 case PROP_VADJUSTMENT:
6022 set_scroll_adjustment (view, CTK_ORIENTATION_VERTICAL,
6023 (CtkAdjustment *) g_value_get_object (value));
6024 break;
6025 case PROP_HSCROLL_POLICY:
6026 view->hscroll_policy = g_value_get_enum (value);
6027 ctk_widget_queue_resize (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
6028 break;
6029 case PROP_VSCROLL_POLICY:
6030 view->vscroll_policy = g_value_get_enum (value);
6031 ctk_widget_queue_resize (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
6032 break;
6033 default:
6034 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec
*_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id
= ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'"
, "ev-view.c", 6034, ("property"), _glib__property_id, _glib__pspec
->name, g_type_name ((((((GTypeClass*) (((GTypeInstance*) (
_glib__pspec))->g_class))->g_type)))), (g_type_name (((
(((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class
))->g_type)))))); } while (0)
;
6035 break;
6036 }
6037}
6038
6039/* Accessibility */
6040static AtkObject *
6041ev_view_get_accessible (CtkWidget *widget)
6042{
6043 EvView *view = EV_VIEW (widget)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ev_view_get_type ()))))))
;
6044
6045 if (!view->accessible)
6046 view->accessible = ev_view_accessible_new (widget);
6047 return view->accessible;
6048}
6049
6050/* CtkContainer */
6051static void
6052ev_view_remove (CtkContainer *container,
6053 CtkWidget *widget)
6054{
6055 EvView *view = EV_VIEW (container)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ev_view_get_type ()))))))
;
6056 GList *tmp_list = view->children;
6057 EvViewChild *child;
6058
6059 while (tmp_list) {
6060 child = tmp_list->data;
6061
6062 if (child->widget == widget) {
6063 ctk_widget_unparent (widget);
6064
6065 view->children = g_list_remove_link (view->children, tmp_list);
6066 g_list_free_1 (tmp_list);
6067 g_slice_free (EvViewChild, child)do { if (1) g_slice_free1 (sizeof (EvViewChild), (child)); else
(void) ((EvViewChild*) 0 == (child)); } while (0)
;
6068
6069 return;
6070 }
6071
6072 tmp_list = tmp_list->next;
6073 }
6074}
6075
6076static void
6077ev_view_forall (CtkContainer *container,
6078 gboolean include_internals,
6079 CtkCallback callback,
6080 gpointer callback_data)
6081{
6082 EvView *view = EV_VIEW (container)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((container)), ((ev_view_get_type ()))))))
;
6083 GList *tmp_list = view->children;
6084 EvViewChild *child;
6085
6086 while (tmp_list) {
6087 child = tmp_list->data;
6088 tmp_list = tmp_list->next;
6089
6090 (* callback) (child->widget, callback_data);
6091 }
6092}
6093
6094static void
6095pan_gesture_pan_cb (CtkGesturePan *gesture,
6096 CtkPanDirection direction,
6097 gdouble offset,
6098 EvView *view)
6099{
6100 CtkAllocation allocation;
6101
6102 ctk_widget_get_allocation (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
, &allocation);
6103
6104 if (view->continuous ||
6105 allocation.width < view->requisition.width) {
6106 ctk_gesture_set_state (CTK_GESTURE (gesture)((((CtkGesture*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gesture)), ((ctk_gesture_get_type ()))))))
,
6107 CTK_EVENT_SEQUENCE_DENIED);
6108 return;
6109 }
6110
6111#define PAN_ACTION_DISTANCE 200
6112
6113 view->pan_action = EV_PAN_ACTION_NONE;
6114 ctk_gesture_set_state (CTK_GESTURE (gesture)((((CtkGesture*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gesture)), ((ctk_gesture_get_type ()))))))
, CTK_EVENT_SEQUENCE_CLAIMED);
6115
6116 if (offset > PAN_ACTION_DISTANCE) {
6117 if (direction == CTK_PAN_DIRECTION_LEFT ||
6118 ctk_widget_get_direction (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
) == CTK_TEXT_DIR_RTL)
6119 view->pan_action = EV_PAN_ACTION_NEXT;
6120 else
6121 view->pan_action = EV_PAN_ACTION_PREV;
6122 }
6123#undef PAN_ACTION_DISTANCE
6124}
6125
6126static void
6127pan_gesture_end_cb (CtkGesture *gesture,
6128 CdkEventSequence *sequence,
6129 EvView *view)
6130{
6131 if (!ctk_gesture_handles_sequence (gesture, sequence))
6132 return;
6133
6134 if (view->pan_action == EV_PAN_ACTION_PREV)
6135 ev_view_previous_page (view);
6136 else if (view->pan_action == EV_PAN_ACTION_NEXT)
6137 ev_view_next_page (view);
6138
6139 view->pan_action = EV_PAN_ACTION_NONE;
6140}
6141
6142static void
6143ev_view_hierarchy_changed (CtkWidget *widget,
6144 CtkWidget *previous_toplevel)
6145{
6146 CtkWidget *parent = ctk_widget_get_parent (widget);
6147 EvView *view = EV_VIEW (widget)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ev_view_get_type ()))))))
;
6148
6149 if (parent && !view->pan_gesture) {
6150 view->pan_gesture =
6151 ctk_gesture_pan_new (parent, CTK_ORIENTATION_HORIZONTAL);
6152 g_signal_connect (view->pan_gesture, "pan",g_signal_connect_data ((view->pan_gesture), ("pan"), (((GCallback
) (pan_gesture_pan_cb))), (widget), ((void*)0), (GConnectFlags
) 0)
6153 G_CALLBACK (pan_gesture_pan_cb), widget)g_signal_connect_data ((view->pan_gesture), ("pan"), (((GCallback
) (pan_gesture_pan_cb))), (widget), ((void*)0), (GConnectFlags
) 0)
;
6154 g_signal_connect (view->pan_gesture, "end",g_signal_connect_data ((view->pan_gesture), ("end"), (((GCallback
) (pan_gesture_end_cb))), (widget), ((void*)0), (GConnectFlags
) 0)
6155 G_CALLBACK (pan_gesture_end_cb), widget)g_signal_connect_data ((view->pan_gesture), ("end"), (((GCallback
) (pan_gesture_end_cb))), (widget), ((void*)0), (GConnectFlags
) 0)
;
6156
6157 ctk_gesture_single_set_touch_only (CTK_GESTURE_SINGLE (view->pan_gesture)((((CtkGestureSingle*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((view->pan_gesture)), ((ctk_gesture_single_get_type
()))))))
, TRUE(!(0)));
6158 ctk_event_controller_set_propagation_phase (CTK_EVENT_CONTROLLER (view->pan_gesture)((((CtkEventController*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((view->pan_gesture)), ((ctk_event_controller_get_type
()))))))
,
6159 CTK_PHASE_CAPTURE);
6160 } else if (!parent && view->pan_gesture) {
6161 g_clear_object (&view->pan_gesture)do { _Static_assert (sizeof *((&view->pan_gesture)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&view->pan_gesture))) _pp = ((&view->pan_gesture
)); __typeof__ (*((&view->pan_gesture))) _ptr = *_pp; *
_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while (
0)
;
6162 }
6163}
6164
6165static void
6166ev_view_parent_set (CtkWidget *widget,
6167 CtkWidget *previous_parent)
6168{
6169 CtkWidget *parent;
6170
6171 parent = ctk_widget_get_parent (widget);
6172 g_assert (!parent || CTK_IS_SCROLLED_WINDOW (parent))do { if (!parent || (((__extension__ ({ GTypeInstance *__inst
= (GTypeInstance*) ((parent)); GType __t = ((ctk_scrolled_window_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))) ; else g_assertion_message_expr ("LectorView", "ev-view.c"
, 6172, ((const char*) (__func__)), "!parent || CTK_IS_SCROLLED_WINDOW (parent)"
); } while (0)
;
6173}
6174
6175static void
6176add_move_binding_keypad (CtkBindingSet *binding_set,
6177 guint keyval,
6178 CdkModifierType modifiers,
6179 CtkMovementStep step,
6180 gint count)
6181{
6182 guint keypad_keyval = keyval - CDK_KEY_Left0xff51 + CDK_KEY_KP_Left0xff96;
6183
6184 ctk_binding_entry_add_signal (binding_set, keyval, modifiers,
6185 "move-cursor", 3,
6186 CTK_TYPE_MOVEMENT_STEP(ctk_movement_step_get_type ()), step,
6187 G_TYPE_INT((GType) ((6) << (2))), count,
6188 G_TYPE_BOOLEAN((GType) ((5) << (2))), FALSE(0));
6189 ctk_binding_entry_add_signal (binding_set, keypad_keyval, modifiers,
6190 "move-cursor", 3,
6191 CTK_TYPE_MOVEMENT_STEP(ctk_movement_step_get_type ()), step,
6192 G_TYPE_INT((GType) ((6) << (2))), count,
6193 G_TYPE_BOOLEAN((GType) ((5) << (2))), FALSE(0));
6194
6195 /* Selection-extending version */
6196 ctk_binding_entry_add_signal (binding_set, keyval, modifiers | CDK_SHIFT_MASK,
6197 "move-cursor", 3,
6198 CTK_TYPE_MOVEMENT_STEP(ctk_movement_step_get_type ()), step,
6199 G_TYPE_INT((GType) ((6) << (2))), count,
6200 G_TYPE_BOOLEAN((GType) ((5) << (2))), TRUE(!(0)));
6201 ctk_binding_entry_add_signal (binding_set, keypad_keyval, modifiers | CDK_SHIFT_MASK,
6202 "move-cursor", 3,
6203 CTK_TYPE_MOVEMENT_STEP(ctk_movement_step_get_type ()), step,
6204 G_TYPE_INT((GType) ((6) << (2))), count,
6205 G_TYPE_BOOLEAN((GType) ((5) << (2))), TRUE(!(0)));
6206}
6207
6208static void
6209ev_view_class_init (EvViewClass *class)
6210{
6211 GObjectClass *object_class = G_OBJECT_CLASS (class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), (((GType) ((20) << (2))))))))
;
6212 CtkWidgetClass *widget_class = CTK_WIDGET_CLASS (class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), ((ctk_widget_get_type ()))))))
;
6213 CtkContainerClass *container_class = CTK_CONTAINER_CLASS (class)((((CtkContainerClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), ((ctk_container_get_type ()))))))
;
6214 CtkBindingSet *binding_set;
6215
6216 object_class->get_property = ev_view_get_property;
6217 object_class->set_property = ev_view_set_property;
6218 object_class->finalize = ev_view_finalize;
6219
6220 widget_class->realize = ev_view_realize;
6221 widget_class->draw = ev_view_draw;
6222 widget_class->button_press_event = ev_view_button_press_event;
6223 widget_class->motion_notify_event = ev_view_motion_notify_event;
6224 widget_class->button_release_event = ev_view_button_release_event;
6225 widget_class->key_press_event = ev_view_key_press_event;
6226 widget_class->focus_in_event = ev_view_focus_in;
6227 widget_class->focus_out_event = ev_view_focus_out;
6228 widget_class->get_accessible = ev_view_get_accessible;
6229 widget_class->get_preferred_width = ev_view_get_preferred_width;
6230 widget_class->get_preferred_height = ev_view_get_preferred_height;
6231 widget_class->size_allocate = ev_view_size_allocate;
6232 widget_class->scroll_event = ev_view_scroll_event;
6233 widget_class->enter_notify_event = ev_view_enter_notify_event;
6234 widget_class->leave_notify_event = ev_view_leave_notify_event;
6235 widget_class->style_updated = ev_view_style_updated;
6236 widget_class->drag_data_get = ev_view_drag_data_get;
6237 widget_class->drag_motion = ev_view_drag_motion;
6238 widget_class->popup_menu = ev_view_popup_menu;
6239 widget_class->query_tooltip = ev_view_query_tooltip;
6240 widget_class->parent_set = ev_view_parent_set;
6241 widget_class->hierarchy_changed = ev_view_hierarchy_changed;
6242
6243 object_class->dispose = ev_view_dispose;
6244
6245 ctk_widget_class_set_css_name (widget_class, "evview");
6246
6247 container_class->remove = ev_view_remove;
6248 container_class->forall = ev_view_forall;
6249
6250 class->scroll = ev_view_scroll_internal;
6251 class->move_cursor = ev_view_move_cursor;
6252
6253 g_object_class_install_property (object_class,
6254 PROP_IS_LOADING,
6255 g_param_spec_boolean ("is-loading",
6256 "Is Loading",
6257 "Whether the view is loading",
6258 FALSE(0),
6259 G_PARAM_READABLE |
6260 G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
));
6261
6262 /* Scrollable interface */
6263 g_object_class_override_property (object_class, PROP_HADJUSTMENT, "hadjustment");
6264 g_object_class_override_property (object_class, PROP_VADJUSTMENT, "vadjustment");
6265 g_object_class_override_property (object_class, PROP_HSCROLL_POLICY, "hscroll-policy");
6266 g_object_class_override_property (object_class, PROP_VSCROLL_POLICY, "vscroll-policy");
6267
6268 signals[SIGNAL_SCROLL] = g_signal_new ("scroll",
6269 G_TYPE_FROM_CLASS (object_class)(((GTypeClass*) (object_class))->g_type),
6270 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
6271 G_STRUCT_OFFSET (EvViewClass, scroll)((glong) __builtin_offsetof(EvViewClass, scroll)),
6272 NULL((void*)0), NULL((void*)0),
6273 ev_view_marshal_VOID__ENUM_ENUM,
6274 G_TYPE_NONE((GType) ((1) << (2))), 2,
6275 CTK_TYPE_SCROLL_TYPE(ctk_scroll_type_get_type ()),
6276 CTK_TYPE_ORIENTATION(ctk_orientation_get_type ()));
6277 signals[SIGNAL_HANDLE_LINK] = g_signal_new ("handle-link",
6278 G_TYPE_FROM_CLASS (object_class)(((GTypeClass*) (object_class))->g_type),
6279 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
6280 G_STRUCT_OFFSET (EvViewClass, handle_link)((glong) __builtin_offsetof(EvViewClass, handle_link)),
6281 NULL((void*)0), NULL((void*)0),
6282 g_cclosure_marshal_VOID__OBJECT,
6283 G_TYPE_NONE((GType) ((1) << (2))), 1,
6284 G_TYPE_OBJECT((GType) ((20) << (2))));
6285 signals[SIGNAL_EXTERNAL_LINK] = g_signal_new ("external-link",
6286 G_TYPE_FROM_CLASS (object_class)(((GTypeClass*) (object_class))->g_type),
6287 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
6288 G_STRUCT_OFFSET (EvViewClass, external_link)((glong) __builtin_offsetof(EvViewClass, external_link)),
6289 NULL((void*)0), NULL((void*)0),
6290 g_cclosure_marshal_VOID__OBJECT,
6291 G_TYPE_NONE((GType) ((1) << (2))), 1,
6292 G_TYPE_OBJECT((GType) ((20) << (2))));
6293 signals[SIGNAL_POPUP_MENU] = g_signal_new ("popup",
6294 G_TYPE_FROM_CLASS (object_class)(((GTypeClass*) (object_class))->g_type),
6295 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
6296 G_STRUCT_OFFSET (EvViewClass, popup_menu)((glong) __builtin_offsetof(EvViewClass, popup_menu)),
6297 NULL((void*)0), NULL((void*)0),
6298 g_cclosure_marshal_VOID__POINTER,
6299 G_TYPE_NONE((GType) ((1) << (2))), 1,
6300 G_TYPE_POINTER((GType) ((17) << (2))));
6301 signals[SIGNAL_SELECTION_CHANGED] = g_signal_new ("selection-changed",
6302 G_TYPE_FROM_CLASS (object_class)(((GTypeClass*) (object_class))->g_type),
6303 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
6304 G_STRUCT_OFFSET (EvViewClass, selection_changed)((glong) __builtin_offsetof(EvViewClass, selection_changed)),
6305 NULL((void*)0), NULL((void*)0),
6306 g_cclosure_marshal_VOID__VOID,
6307 G_TYPE_NONE((GType) ((1) << (2))), 0,
6308 G_TYPE_NONE((GType) ((1) << (2))));
6309 signals[SIGNAL_SYNC_SOURCE] = g_signal_new ("sync-source",
6310 G_TYPE_FROM_CLASS (object_class)(((GTypeClass*) (object_class))->g_type),
6311 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
6312 G_STRUCT_OFFSET (EvViewClass, sync_source)((glong) __builtin_offsetof(EvViewClass, sync_source)),
6313 NULL((void*)0), NULL((void*)0),
6314 g_cclosure_marshal_VOID__POINTER,
6315 G_TYPE_NONE((GType) ((1) << (2))), 1,
6316 G_TYPE_POINTER((GType) ((17) << (2))));
6317 signals[SIGNAL_ANNOT_ADDED] = g_signal_new ("annot-added",
6318 G_TYPE_FROM_CLASS (object_class)(((GTypeClass*) (object_class))->g_type),
6319 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
6320 G_STRUCT_OFFSET (EvViewClass, annot_added)((glong) __builtin_offsetof(EvViewClass, annot_added)),
6321 NULL((void*)0), NULL((void*)0),
6322 g_cclosure_marshal_VOID__OBJECT,
6323 G_TYPE_NONE((GType) ((1) << (2))), 1,
6324 EV_TYPE_ANNOTATION(ev_annotation_get_type()));
6325 signals[SIGNAL_ANNOT_REMOVED] = g_signal_new ("annot-removed",
6326 G_TYPE_FROM_CLASS (object_class)(((GTypeClass*) (object_class))->g_type),
6327 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
6328 G_STRUCT_OFFSET (EvViewClass, annot_removed)((glong) __builtin_offsetof(EvViewClass, annot_removed)),
6329 NULL((void*)0), NULL((void*)0),
6330 g_cclosure_marshal_VOID__OBJECT,
6331 G_TYPE_NONE((GType) ((1) << (2))), 1,
6332 EV_TYPE_ANNOTATION(ev_annotation_get_type()));
6333 signals[SIGNAL_LAYERS_CHANGED] = g_signal_new ("layers-changed",
6334 G_TYPE_FROM_CLASS (object_class)(((GTypeClass*) (object_class))->g_type),
6335 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
6336 G_STRUCT_OFFSET (EvViewClass, layers_changed)((glong) __builtin_offsetof(EvViewClass, layers_changed)),
6337 NULL((void*)0), NULL((void*)0),
6338 g_cclosure_marshal_VOID__VOID,
6339 G_TYPE_NONE((GType) ((1) << (2))), 0,
6340 G_TYPE_NONE((GType) ((1) << (2))));
6341 signals[SIGNAL_MOVE_CURSOR] = g_signal_new ("move-cursor",
6342 G_TYPE_FROM_CLASS (object_class)(((GTypeClass*) (object_class))->g_type),
6343 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
6344 G_STRUCT_OFFSET (EvViewClass, move_cursor)((glong) __builtin_offsetof(EvViewClass, move_cursor)),
6345 NULL((void*)0), NULL((void*)0),
6346 ev_view_marshal_BOOLEAN__ENUM_INT_BOOLEAN,
6347 G_TYPE_BOOLEAN((GType) ((5) << (2))), 3,
6348 CTK_TYPE_MOVEMENT_STEP(ctk_movement_step_get_type ()),
6349 G_TYPE_INT((GType) ((6) << (2))),
6350 G_TYPE_BOOLEAN((GType) ((5) << (2))));
6351 signals[SIGNAL_CURSOR_MOVED] = g_signal_new ("cursor-moved",
6352 G_TYPE_FROM_CLASS (object_class)(((GTypeClass*) (object_class))->g_type),
6353 G_SIGNAL_RUN_LAST,
6354 0,
6355 NULL((void*)0), NULL((void*)0),
6356 ev_view_marshal_VOID__INT_INT,
6357 G_TYPE_NONE((GType) ((1) << (2))), 2,
6358 G_TYPE_INT((GType) ((6) << (2))),
6359 G_TYPE_INT((GType) ((6) << (2))));
6360
6361 binding_set = ctk_binding_set_by_class (class);
6362
6363 add_move_binding_keypad (binding_set, CDK_KEY_Left0xff51, 0, CTK_MOVEMENT_VISUAL_POSITIONS, -1);
6364 add_move_binding_keypad (binding_set, CDK_KEY_Right0xff53, 0, CTK_MOVEMENT_VISUAL_POSITIONS, 1);
6365 add_move_binding_keypad (binding_set, CDK_KEY_Left0xff51, CDK_CONTROL_MASK, CTK_MOVEMENT_WORDS, -1);
6366 add_move_binding_keypad (binding_set, CDK_KEY_Right0xff53, CDK_CONTROL_MASK, CTK_MOVEMENT_WORDS, 1);
6367 add_move_binding_keypad (binding_set, CDK_KEY_Up0xff52, 0, CTK_MOVEMENT_DISPLAY_LINES, -1);
6368 add_move_binding_keypad (binding_set, CDK_KEY_Down0xff54, 0, CTK_MOVEMENT_DISPLAY_LINES, 1);
6369 add_move_binding_keypad (binding_set, CDK_KEY_Home0xff50, 0, CTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
6370 add_move_binding_keypad (binding_set, CDK_KEY_End0xff57, 0, CTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
6371
6372 add_scroll_binding_keypad (binding_set, CDK_KEY_Left0xff51, 0, CTK_SCROLL_STEP_BACKWARD, CTK_ORIENTATION_HORIZONTAL);
6373 add_scroll_binding_keypad (binding_set, CDK_KEY_Right0xff53, 0, CTK_SCROLL_STEP_FORWARD, CTK_ORIENTATION_HORIZONTAL);
6374 add_scroll_binding_keypad (binding_set, CDK_KEY_Left0xff51, CDK_MOD1_MASK, CTK_SCROLL_STEP_DOWN, CTK_ORIENTATION_HORIZONTAL);
6375 add_scroll_binding_keypad (binding_set, CDK_KEY_Right0xff53, CDK_MOD1_MASK, CTK_SCROLL_STEP_UP, CTK_ORIENTATION_HORIZONTAL);
6376 add_scroll_binding_keypad (binding_set, CDK_KEY_Up0xff52, 0, CTK_SCROLL_STEP_BACKWARD, CTK_ORIENTATION_VERTICAL);
6377 add_scroll_binding_keypad (binding_set, CDK_KEY_Down0xff54, 0, CTK_SCROLL_STEP_FORWARD, CTK_ORIENTATION_VERTICAL);
6378 add_scroll_binding_keypad (binding_set, CDK_KEY_Up0xff52, CDK_MOD1_MASK, CTK_SCROLL_STEP_DOWN, CTK_ORIENTATION_VERTICAL);
6379 add_scroll_binding_keypad (binding_set, CDK_KEY_Down0xff54, CDK_MOD1_MASK, CTK_SCROLL_STEP_UP, CTK_ORIENTATION_VERTICAL);
6380 add_scroll_binding_keypad (binding_set, CDK_KEY_Page_Up0xff55, 0, CTK_SCROLL_PAGE_BACKWARD, CTK_ORIENTATION_VERTICAL);
6381 add_scroll_binding_keypad (binding_set, CDK_KEY_Page_Down0xff56, 0, CTK_SCROLL_PAGE_FORWARD, CTK_ORIENTATION_VERTICAL);
6382 ctk_binding_entry_add_signal (binding_set, CDK_KEY_Return0xff0d, 0, "scroll", 2,
6383 CTK_TYPE_SCROLL_TYPE(ctk_scroll_type_get_type ()), CTK_SCROLL_PAGE_FORWARD,
6384 CTK_TYPE_ORIENTATION(ctk_orientation_get_type ()), CTK_ORIENTATION_VERTICAL);
6385 ctk_binding_entry_add_signal (binding_set, CDK_KEY_Return0xff0d, CDK_SHIFT_MASK, "scroll", 2,
6386 CTK_TYPE_SCROLL_TYPE(ctk_scroll_type_get_type ()), CTK_SCROLL_PAGE_BACKWARD,
6387 CTK_TYPE_ORIENTATION(ctk_orientation_get_type ()), CTK_ORIENTATION_VERTICAL);
6388 ctk_binding_entry_add_signal (binding_set, CDK_KEY_H0x048, 0, "scroll", 2,
6389 CTK_TYPE_SCROLL_TYPE(ctk_scroll_type_get_type ()), CTK_SCROLL_STEP_BACKWARD,
6390 CTK_TYPE_ORIENTATION(ctk_orientation_get_type ()), CTK_ORIENTATION_HORIZONTAL);
6391 ctk_binding_entry_add_signal (binding_set, CDK_KEY_J0x04a, 0, "scroll", 2,
6392 CTK_TYPE_SCROLL_TYPE(ctk_scroll_type_get_type ()), CTK_SCROLL_STEP_FORWARD,
6393 CTK_TYPE_ORIENTATION(ctk_orientation_get_type ()), CTK_ORIENTATION_VERTICAL);
6394 ctk_binding_entry_add_signal (binding_set, CDK_KEY_K0x04b, 0, "scroll", 2,
6395 CTK_TYPE_SCROLL_TYPE(ctk_scroll_type_get_type ()), CTK_SCROLL_STEP_BACKWARD,
6396 CTK_TYPE_ORIENTATION(ctk_orientation_get_type ()), CTK_ORIENTATION_VERTICAL);
6397 ctk_binding_entry_add_signal (binding_set, CDK_KEY_L0x04c, 0, "scroll", 2,
6398 CTK_TYPE_SCROLL_TYPE(ctk_scroll_type_get_type ()), CTK_SCROLL_STEP_FORWARD,
6399 CTK_TYPE_ORIENTATION(ctk_orientation_get_type ()), CTK_ORIENTATION_HORIZONTAL);
6400 ctk_binding_entry_add_signal (binding_set, CDK_KEY_space0x020, 0, "scroll", 2,
6401 CTK_TYPE_SCROLL_TYPE(ctk_scroll_type_get_type ()), CTK_SCROLL_PAGE_FORWARD,
6402 CTK_TYPE_ORIENTATION(ctk_orientation_get_type ()), CTK_ORIENTATION_VERTICAL);
6403 ctk_binding_entry_add_signal (binding_set, CDK_KEY_space0x020, CDK_SHIFT_MASK, "scroll", 2,
6404 CTK_TYPE_SCROLL_TYPE(ctk_scroll_type_get_type ()), CTK_SCROLL_PAGE_BACKWARD,
6405 CTK_TYPE_ORIENTATION(ctk_orientation_get_type ()), CTK_ORIENTATION_VERTICAL);
6406 ctk_binding_entry_add_signal (binding_set, CDK_KEY_BackSpace0xff08, 0, "scroll", 2,
6407 CTK_TYPE_SCROLL_TYPE(ctk_scroll_type_get_type ()), CTK_SCROLL_PAGE_BACKWARD,
6408 CTK_TYPE_ORIENTATION(ctk_orientation_get_type ()), CTK_ORIENTATION_VERTICAL);
6409 ctk_binding_entry_add_signal (binding_set, CDK_KEY_BackSpace0xff08, CDK_SHIFT_MASK, "scroll", 2,
6410 CTK_TYPE_SCROLL_TYPE(ctk_scroll_type_get_type ()), CTK_SCROLL_PAGE_FORWARD,
6411 CTK_TYPE_ORIENTATION(ctk_orientation_get_type ()), CTK_ORIENTATION_VERTICAL);
6412}
6413
6414static void
6415on_notify_scale_factor (EvView *view,
6416 GParamSpec *pspec)
6417{
6418 if (view->document)
6419 view_update_range_and_current_page (view);
6420}
6421
6422static void
6423zoom_gesture_begin_cb (CtkGesture *gesture,
6424 CdkEventSequence *sequence,
6425 EvView *view)
6426{
6427 view->prev_zoom_gesture_scale = 1;
6428}
6429
6430static void
6431zoom_gesture_scale_changed_cb (CtkGestureZoom *gesture,
6432 gdouble scale,
6433 EvView *view)
6434{
6435 gdouble factor;
6436
6437 view->drag_info.in_drag = FALSE(0);
6438 view->image_dnd_info.in_drag = FALSE(0);
6439
6440 factor = scale - view->prev_zoom_gesture_scale + 1;
6441 view->prev_zoom_gesture_scale = scale;
6442 ev_document_model_set_sizing_mode (view->model, EV_SIZING_FREE);
6443
6444 ctk_gesture_get_bounding_box_center (CTK_GESTURE (gesture)((((CtkGesture*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gesture)), ((ctk_gesture_get_type ()))))))
, &view->zoom_center_x, &view->zoom_center_y);
6445
6446 if ((factor < 1.0 && ev_view_can_zoom_out (view)) ||
6447 (factor >= 1.0 && ev_view_can_zoom_in (view)))
6448 ev_view_zoom (view, factor);
6449}
6450
6451static void
6452ev_view_init (EvView *view)
6453{
6454 CtkStyleContext *context;
6455
6456 ctk_widget_set_can_focus (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
, TRUE(!(0)));
6457 ctk_widget_set_has_window (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
, TRUE(!(0)));
6458 ctk_widget_set_redraw_on_allocate (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
, FALSE(0));
6459
6460 context = ctk_widget_get_style_context (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
6461 ctk_style_context_add_class (context, "content-view");
6462 ctk_style_context_add_class (context, "view");
6463
6464 ctk_widget_set_events (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
,
6465 CDK_TOUCH_MASK |
6466 CDK_EXPOSURE_MASK |
6467 CDK_BUTTON_PRESS_MASK |
6468 CDK_BUTTON_RELEASE_MASK |
6469 CDK_SCROLL_MASK |
6470 CDK_SMOOTH_SCROLL_MASK |
6471 CDK_KEY_PRESS_MASK |
6472 CDK_POINTER_MOTION_MASK |
6473 CDK_POINTER_MOTION_HINT_MASK |
6474 CDK_ENTER_NOTIFY_MASK |
6475 CDK_LEAVE_NOTIFY_MASK);
6476
6477 view->start_page = -1;
6478 view->end_page = -1;
6479 view->spacing = 5;
6480 view->scale = 1.0;
6481 view->current_page = 0;
6482 view->pressed_button = -1;
6483 view->cursor = EV_VIEW_CURSOR_NORMAL;
6484 view->drag_info.in_drag = FALSE(0);
6485 view->scroll_info.autoscrolling = FALSE(0);
6486 view->selection_info.selections = NULL((void*)0);
6487 view->selection_info.in_drag = FALSE(0);
6488 view->continuous = TRUE(!(0));
6489 view->dual_even_left = TRUE(!(0));
6490 view->fullscreen = FALSE(0);
6491 view->sizing_mode = EV_SIZING_FIT_WIDTH;
6492 view->page_layout = EV_PAGE_LAYOUT_SINGLE;
6493 view->pending_scroll = SCROLL_TO_KEEP_POSITION;
6494 view->jump_to_find_result = TRUE(!(0));
6495 view->highlight_find_results = FALSE(0);
6496 view->caret_enabled = FALSE(0);
6497 view->cursor_page = 0;
6498 view->zoom_center_x = -1;
6499 view->zoom_center_y = -1;
6500
6501 g_signal_connect (view, "notify::scale-factor",g_signal_connect_data ((view), ("notify::scale-factor"), (((GCallback
) (on_notify_scale_factor))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
6502 G_CALLBACK (on_notify_scale_factor), NULL)g_signal_connect_data ((view), ("notify::scale-factor"), (((GCallback
) (on_notify_scale_factor))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
6503
6504 view->zoom_gesture = ctk_gesture_zoom_new (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
6505 ctk_event_controller_set_propagation_phase (CTK_EVENT_CONTROLLER (view->zoom_gesture)((((CtkEventController*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((view->zoom_gesture)), ((ctk_event_controller_get_type
()))))))
,
6506 CTK_PHASE_CAPTURE);
6507
6508 g_signal_connect (view->zoom_gesture, "begin",g_signal_connect_data ((view->zoom_gesture), ("begin"), ((
(GCallback) (zoom_gesture_begin_cb))), (view), ((void*)0), (GConnectFlags
) 0)
6509 G_CALLBACK (zoom_gesture_begin_cb), view)g_signal_connect_data ((view->zoom_gesture), ("begin"), ((
(GCallback) (zoom_gesture_begin_cb))), (view), ((void*)0), (GConnectFlags
) 0)
;
6510 g_signal_connect (view->zoom_gesture, "scale-changed",g_signal_connect_data ((view->zoom_gesture), ("scale-changed"
), (((GCallback) (zoom_gesture_scale_changed_cb))), (view), (
(void*)0), (GConnectFlags) 0)
6511 G_CALLBACK (zoom_gesture_scale_changed_cb), view)g_signal_connect_data ((view->zoom_gesture), ("scale-changed"
), (((GCallback) (zoom_gesture_scale_changed_cb))), (view), (
(void*)0), (GConnectFlags) 0)
;
6512}
6513
6514/*** Callbacks ***/
6515
6516static void
6517ev_view_change_page (EvView *view,
6518 gint new_page)
6519{
6520 gint x, y;
6521
6522 view->current_page = new_page;
6523 view->pending_scroll = SCROLL_TO_PAGE_POSITION;
6524
6525 ev_view_set_loading (view, FALSE(0));
6526
6527 ev_document_misc_get_pointer_position (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
, &x, &y);
6528 ev_view_handle_cursor_over_xy (view, x, y);
6529
6530 ctk_widget_queue_resize (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
6531}
6532
6533static void
6534job_finished_cb (EvPixbufCache *pixbuf_cache,
6535 cairo_region_t *region,
6536 EvView *view)
6537{
6538 if (region) {
6539 cdk_window_invalidate_region (ctk_widget_get_window (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
), region, TRUE(!(0)));
6540 } else {
6541 ctk_widget_queue_draw (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
6542 }
6543}
6544
6545static void
6546ev_view_page_changed_cb (EvDocumentModel *model,
6547 gint old_page,
6548 gint new_page,
6549 EvView *view)
6550{
6551 if (!view->document)
6552 return;
6553
6554 if (view->current_page != new_page) {
6555 ev_view_change_page (view, new_page);
6556 } else {
6557 ctk_widget_queue_draw (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
6558 }
6559
6560 view->find_result = 0;
6561}
6562
6563static void
6564on_adjustment_value_changed (CtkAdjustment *adjustment,
6565 EvView *view)
6566{
6567 CtkWidget *widget = CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
;
6568 int dx = 0, dy = 0;
6569 gint x, y;
6570 gint value;
6571 GList *l;
6572
6573 if (!ctk_widget_get_realized (widget))
6574 return;
6575
6576 if (view->hadjustment) {
6577 value = (gint) ctk_adjustment_get_value (view->hadjustment);
6578 dx = view->scroll_x - value;
6579 view->scroll_x = value;
6580 } else {
6581 view->scroll_x = 0;
6582 }
6583
6584 if (view->vadjustment) {
6585 value = (gint) ctk_adjustment_get_value (view->vadjustment);
6586 dy = view->scroll_y - value;
6587 view->scroll_y = value;
6588 } else {
6589 view->scroll_y = 0;
6590 }
6591
6592 for (l = view->children; l && l->data; l = g_list_next (l)((l) ? (((GList *)(l))->next) : ((void*)0))) {
6593 EvViewChild *child = (EvViewChild *)l->data;
6594
6595 child->x += dx;
6596 child->y += dy;
6597 if (ctk_widget_get_visible (child->widget) && ctk_widget_get_visible (widget))
6598 ctk_widget_queue_resize (widget);
6599 }
6600
6601 for (l = view->window_children; l && l->data; l = g_list_next (l)((l) ? (((GList *)(l))->next) : ((void*)0))) {
6602 EvViewWindowChild *child;
6603
6604 child = (EvViewWindowChild *)l->data;
6605
6606 ev_view_window_child_move (view, child, child->x + dx, child->y + dy);
6607 }
6608
6609 if (view->pending_resize) {
6610 ctk_widget_queue_draw (widget);
6611 } else {
6612 cdk_window_scroll (ctk_widget_get_window (widget), dx, dy);
6613 }
6614
6615 ev_document_misc_get_pointer_position (widget, &x, &y);
6616 ev_view_handle_cursor_over_xy (view, x, y);
6617
6618 if (view->document)
6619 view_update_range_and_current_page (view);
6620}
6621
6622CtkWidget*
6623ev_view_new (void)
6624{
6625 CtkWidget *view;
6626
6627 view = g_object_new (EV_TYPE_VIEW(ev_view_get_type ()), NULL((void*)0));
6628
6629 return view;
6630}
6631
6632static void
6633setup_caches (EvView *view)
6634{
6635 gboolean inverted_colors;
6636
6637 view->height_to_page_cache = ev_view_get_height_to_page_cache (view);
29
Calling 'ev_view_get_height_to_page_cache'
6638 view->pixbuf_cache = ev_pixbuf_cache_new (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
, view->model, view->pixbuf_cache_size);
6639 view->page_cache = ev_page_cache_new (view->document);
6640
6641 ev_page_cache_set_flags (view->page_cache,
6642 ev_page_cache_get_flags (view->page_cache) |
6643 EV_PAGE_DATA_INCLUDE_TEXT_LAYOUT |
6644 EV_PAGE_DATA_INCLUDE_TEXT |
6645 EV_PAGE_DATA_INCLUDE_TEXT_ATTRS |
6646 EV_PAGE_DATA_INCLUDE_TEXT_LOG_ATTRS);
6647
6648 inverted_colors = ev_document_model_get_inverted_colors (view->model);
6649 ev_pixbuf_cache_set_inverted_colors (view->pixbuf_cache, inverted_colors);
6650 g_signal_connect (view->pixbuf_cache, "job-finished", G_CALLBACK (job_finished_cb), view)g_signal_connect_data ((view->pixbuf_cache), ("job-finished"
), (((GCallback) (job_finished_cb))), (view), ((void*)0), (GConnectFlags
) 0)
;
6651}
6652
6653static void
6654clear_caches (EvView *view)
6655{
6656 if (view->pixbuf_cache) {
6657 g_object_unref (view->pixbuf_cache);
6658 view->pixbuf_cache = NULL((void*)0);
6659 }
6660
6661 if (view->page_cache) {
6662 g_object_unref (view->page_cache);
6663 view->page_cache = NULL((void*)0);
6664 }
6665}
6666
6667/**
6668 * ev_view_set_page_cache_size:
6669 * @view:
6670 * @cache_size:
6671 *
6672 * Sets the maximum size in bytes that will be used to cache
6673 * rendered pages. Use 0 to disable caching rendered pages.
6674 *
6675 * Note that this limit doesn't affect the current visible page range,
6676 * which will always be rendered. In order to limit the total memory used
6677 * you have to use ev_document_model_set_max_scale() too.
6678 *
6679 */
6680void
6681ev_view_set_page_cache_size (EvView *view,
6682 gsize cache_size)
6683{
6684 if (view->pixbuf_cache_size == cache_size)
6685 return;
6686
6687 view->pixbuf_cache_size = cache_size;
6688 if (view->pixbuf_cache)
6689 ev_pixbuf_cache_set_max_size (view->pixbuf_cache, cache_size);
6690}
6691
6692void
6693ev_view_set_loading (EvView *view,
6694 gboolean loading)
6695{
6696 if (view->loading == loading)
6697 return;
6698
6699 view->loading = loading;
6700 g_object_notify (G_OBJECT (view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), (((GType) ((20) << (2))))))))
, "is-loading");
6701}
6702
6703gboolean
6704ev_view_is_loading (EvView *view)
6705{
6706 return view->loading;
6707}
6708
6709static gboolean
6710ev_view_autoscroll_cb (EvView *view)
6711{
6712 gdouble speed, value;
6713
6714 /* If the user stops autoscrolling, autoscrolling will be
6715 * set to false but the timeout will continue; stop the timeout: */
6716 if (!view->scroll_info.autoscrolling) {
6717 view->scroll_info.timeout_id = 0;
6718 return FALSE(0);
6719 }
6720
6721 /* Replace 100 with your speed of choice: The lower the faster.
6722 * Replace 3 with another speed of choice: The higher, the faster it accelerated
6723 * based on the distance of the starting point from the mouse
6724 * (All also effected by the timeout interval of this callback) */
6725
6726 if (view->scroll_info.start_y > view->scroll_info.last_y)
6727 speed = -pow ((((gdouble)view->scroll_info.start_y - view->scroll_info.last_y) / 100), 3);
6728 else
6729 speed = pow ((((gdouble)view->scroll_info.last_y - view->scroll_info.start_y) / 100), 3);
6730
6731 value = ctk_adjustment_get_value (view->vadjustment);
6732 value = CLAMP (value + speed, 0,(((value + speed) > (ctk_adjustment_get_upper (view->vadjustment
) - ctk_adjustment_get_page_size (view->vadjustment))) ? (
ctk_adjustment_get_upper (view->vadjustment) - ctk_adjustment_get_page_size
(view->vadjustment)) : (((value + speed) < (0)) ? (0) :
(value + speed)))
6733 ctk_adjustment_get_upper (view->vadjustment) -(((value + speed) > (ctk_adjustment_get_upper (view->vadjustment
) - ctk_adjustment_get_page_size (view->vadjustment))) ? (
ctk_adjustment_get_upper (view->vadjustment) - ctk_adjustment_get_page_size
(view->vadjustment)) : (((value + speed) < (0)) ? (0) :
(value + speed)))
6734 ctk_adjustment_get_page_size (view->vadjustment))(((value + speed) > (ctk_adjustment_get_upper (view->vadjustment
) - ctk_adjustment_get_page_size (view->vadjustment))) ? (
ctk_adjustment_get_upper (view->vadjustment) - ctk_adjustment_get_page_size
(view->vadjustment)) : (((value + speed) < (0)) ? (0) :
(value + speed)))
;
6735 ctk_adjustment_set_value (view->vadjustment, value);
6736
6737 return TRUE(!(0));
6738
6739}
6740
6741void
6742ev_view_autoscroll_start (EvView *view)
6743{
6744 gint x, y;
6745
6746 g_return_if_fail (EV_IS_VIEW (view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ev_view_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("LectorView", ((const char*
) (__func__)), "EV_IS_VIEW (view)"); return; } } while (0)
;
6747
6748 if (view->scroll_info.autoscrolling)
6749 return;
6750
6751 view->scroll_info.autoscrolling = TRUE(!(0));
6752 view->scroll_info.timeout_id =
6753 g_timeout_add (20, (GSourceFunc)ev_view_autoscroll_cb,
6754 view);
6755
6756 ev_document_misc_get_pointer_position (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
, &x, &y);
6757 ev_view_handle_cursor_over_xy (view, x, y);
6758}
6759
6760void
6761ev_view_autoscroll_stop (EvView *view)
6762{
6763 gint x, y;
6764
6765 g_return_if_fail (EV_IS_VIEW (view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ev_view_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("LectorView", ((const char*
) (__func__)), "EV_IS_VIEW (view)"); return; } } while (0)
;
6766
6767 if (!view->scroll_info.autoscrolling)
6768 return;
6769
6770 view->scroll_info.autoscrolling = FALSE(0);
6771 if (view->scroll_info.timeout_id) {
6772 g_source_remove (view->scroll_info.timeout_id);
6773 view->scroll_info.timeout_id = 0;
6774 }
6775
6776 ev_document_misc_get_pointer_position (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
, &x, &y);
6777 ev_view_handle_cursor_over_xy (view, x, y);
6778}
6779
6780static void
6781ev_view_document_changed_cb (EvDocumentModel *model,
6782 GParamSpec *pspec,
6783 EvView *view)
6784{
6785 EvDocument *document = ev_document_model_get_document (model);
6786
6787 if (document != view->document) {
18
Assuming 'document' is not equal to field 'document'
19
Taking true branch
6788 gint current_page;
6789
6790 ev_view_remove_all (view);
6791 clear_caches (view);
6792
6793 if (view->document) {
20
Assuming field 'document' is null
6794 g_object_unref (view->document);
6795 }
6796
6797 view->document = document ? g_object_ref (document)((__typeof__ (document)) (g_object_ref) (document)) : NULL((void*)0);
21
Taking false branch
22
Assuming 'document' is non-null
23
'?' condition is true
6798 view->find_result = 0;
6799
6800 if (view->document) {
24
Assuming field 'document' is non-null
6801 if (ev_document_get_n_pages (view->document) <= 0 ||
25
Assuming the condition is false
27
Taking false branch
6802 !ev_document_check_dimensions (view->document))
26
Assuming the condition is false
6803 return;
6804
6805 ev_view_set_loading (view, FALSE(0));
6806 setup_caches (view);
28
Calling 'setup_caches'
6807 }
6808
6809 current_page = ev_document_model_get_page (model);
6810 if (view->current_page != current_page) {
6811 ev_view_change_page (view, current_page);
6812 } else {
6813 view->pending_scroll = SCROLL_TO_KEEP_POSITION;
6814 ctk_widget_queue_resize (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
6815 }
6816 }
6817}
6818
6819static void
6820ev_view_rotation_changed_cb (EvDocumentModel *model,
6821 GParamSpec *pspec,
6822 EvView *view)
6823{
6824 gint rotation = ev_document_model_get_rotation (model);
6825
6826 view->rotation = rotation;
6827
6828 if (view->pixbuf_cache) {
6829 ev_pixbuf_cache_clear (view->pixbuf_cache);
6830 if (!ev_document_is_page_size_uniform (view->document))
6831 view->pending_scroll = SCROLL_TO_PAGE_POSITION;
6832 ctk_widget_queue_resize (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
6833 }
6834
6835 ev_view_remove_all (view);
6836
6837 if (rotation != 0)
6838 clear_selection (view);
6839}
6840
6841static void
6842ev_view_inverted_colors_changed_cb (EvDocumentModel *model,
6843 GParamSpec *pspec,
6844 EvView *view)
6845{
6846 if (view->pixbuf_cache) {
6847 gboolean inverted_colors;
6848
6849 inverted_colors = ev_document_model_get_inverted_colors (model);
6850 ev_pixbuf_cache_set_inverted_colors (view->pixbuf_cache, inverted_colors);
6851 ctk_widget_queue_draw (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
6852 }
6853}
6854
6855static void
6856ev_view_sizing_mode_changed_cb (EvDocumentModel *model,
6857 GParamSpec *pspec,
6858 EvView *view)
6859{
6860 EvSizingMode mode = ev_document_model_get_sizing_mode (model);
6861
6862 view->sizing_mode = mode;
6863 if (mode != EV_SIZING_FREE)
6864 ctk_widget_queue_resize (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
6865}
6866
6867static void
6868ev_view_page_layout_changed_cb (EvDocumentModel *model,
6869 GParamSpec *pspec,
6870 EvView *view)
6871{
6872 EvPageLayout layout = ev_document_model_get_page_layout (model);
6873
6874 view->page_layout = layout;
6875
6876 view->pending_scroll = SCROLL_TO_PAGE_POSITION;
6877 ctk_widget_queue_resize (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
6878
6879 /* FIXME: if we're keeping the pixbuf cache around, we should extend the
6880 * preload_cache_size to be 2 if dual_page is set.
6881 */
6882}
6883
6884#define EPSILON0.0000001 0.0000001
6885static void
6886ev_view_scale_changed_cb (EvDocumentModel *model,
6887 GParamSpec *pspec,
6888 EvView *view)
6889{
6890 gdouble scale = ev_document_model_get_scale (model);
6891
6892 if (ABS (view->scale - scale)(((view->scale - scale) < 0) ? -(view->scale - scale
) : (view->scale - scale))
< EPSILON0.0000001)
6893 return;
6894
6895 view->scale = scale;
6896
6897 view->pending_resize = TRUE(!(0));
6898 if (view->sizing_mode == EV_SIZING_FREE)
6899 ctk_widget_queue_resize (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
6900}
6901
6902static void
6903ev_view_continuous_changed_cb (EvDocumentModel *model,
6904 GParamSpec *pspec,
6905 EvView *view)
6906{
6907 gboolean continuous = ev_document_model_get_continuous (model);
6908
6909 view->continuous = continuous;
6910 view->pending_scroll = SCROLL_TO_PAGE_POSITION;
6911 ctk_widget_queue_resize (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
6912}
6913
6914static void
6915ev_view_dual_odd_left_changed_cb (EvDocumentModel *model,
6916 GParamSpec *pspec,
6917 EvView *view)
6918{
6919 view->dual_even_left = !ev_document_model_get_dual_page_odd_pages_left (model);
6920 view->pending_scroll = SCROLL_TO_PAGE_POSITION;
6921 ctk_widget_queue_resize (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
6922}
6923
6924static void
6925ev_view_fullscreen_changed_cb (EvDocumentModel *model,
6926 GParamSpec *pspec,
6927 EvView *view)
6928{
6929 gboolean fullscreen = ev_document_model_get_fullscreen (model);
6930
6931 view->fullscreen = fullscreen;
6932 ctk_widget_queue_resize (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
6933}
6934
6935void
6936ev_view_set_model (EvView *view,
6937 EvDocumentModel *model)
6938{
6939 g_return_if_fail (EV_IS_VIEW (view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ev_view_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("LectorView", ((const char*
) (__func__)), "EV_IS_VIEW (view)"); return; } } while (0)
;
1
Assuming '__inst' is non-null
2
Taking false branch
3
Assuming field 'g_class' is null
4
Assuming the condition is true
5
Taking true branch
6
Loop condition is false. Exiting loop
6940 g_return_if_fail (EV_IS_DOCUMENT_MODEL (model))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((model)); GType __t = ((ev_document_model_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("LectorView", ((const char*
) (__func__)), "EV_IS_DOCUMENT_MODEL (model)"); return; } } while
(0)
;
7
Assuming '__inst' is non-null
8
Taking false branch
9
Assuming field 'g_class' is null
10
Assuming the condition is true
11
Taking true branch
12
Loop condition is false. Exiting loop
6941
6942 if (model == view->model)
13
Assuming 'model' is not equal to field 'model'
14
Taking false branch
6943 return;
6944
6945 if (view->model) {
15
Assuming field 'model' is null
16
Taking false branch
6946 g_signal_handlers_disconnect_by_func (view->model,g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (ev_view_document_changed_cb), (view))
6947 ev_view_document_changed_cb,g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (ev_view_document_changed_cb), (view))
6948 view)g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (ev_view_document_changed_cb), (view))
;
6949 g_signal_handlers_disconnect_by_func (view->model,g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (ev_view_page_changed_cb), (view))
6950 ev_view_page_changed_cb,g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (ev_view_page_changed_cb), (view))
6951 view)g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (ev_view_page_changed_cb), (view))
;
6952 g_object_unref (view->model);
6953 }
6954 view->model = g_object_ref (model)((__typeof__ (model)) (g_object_ref) (model));
6955
6956 /* Initialize view from model */
6957 view->rotation = ev_document_model_get_rotation (view->model);
6958 view->sizing_mode = ev_document_model_get_sizing_mode (view->model);
6959 view->scale = ev_document_model_get_scale (view->model);
6960 view->continuous = ev_document_model_get_continuous (view->model);
6961 view->page_layout = ev_document_model_get_page_layout (view->model);
6962 view->fullscreen = ev_document_model_get_fullscreen (view->model);
6963 ev_view_document_changed_cb (view->model, NULL((void*)0), view);
17
Calling 'ev_view_document_changed_cb'
6964
6965 g_signal_connect (view->model, "notify::document",g_signal_connect_data ((view->model), ("notify::document")
, (((GCallback) (ev_view_document_changed_cb))), (view), ((void
*)0), (GConnectFlags) 0)
6966 G_CALLBACK (ev_view_document_changed_cb),g_signal_connect_data ((view->model), ("notify::document")
, (((GCallback) (ev_view_document_changed_cb))), (view), ((void
*)0), (GConnectFlags) 0)
6967 view)g_signal_connect_data ((view->model), ("notify::document")
, (((GCallback) (ev_view_document_changed_cb))), (view), ((void
*)0), (GConnectFlags) 0)
;
6968 g_signal_connect (view->model, "notify::rotation",g_signal_connect_data ((view->model), ("notify::rotation")
, (((GCallback) (ev_view_rotation_changed_cb))), (view), ((void
*)0), (GConnectFlags) 0)
6969 G_CALLBACK (ev_view_rotation_changed_cb),g_signal_connect_data ((view->model), ("notify::rotation")
, (((GCallback) (ev_view_rotation_changed_cb))), (view), ((void
*)0), (GConnectFlags) 0)
6970 view)g_signal_connect_data ((view->model), ("notify::rotation")
, (((GCallback) (ev_view_rotation_changed_cb))), (view), ((void
*)0), (GConnectFlags) 0)
;
6971 g_signal_connect (view->model, "notify::inverted-colors",g_signal_connect_data ((view->model), ("notify::inverted-colors"
), (((GCallback) (ev_view_inverted_colors_changed_cb))), (view
), ((void*)0), (GConnectFlags) 0)
6972 G_CALLBACK (ev_view_inverted_colors_changed_cb),g_signal_connect_data ((view->model), ("notify::inverted-colors"
), (((GCallback) (ev_view_inverted_colors_changed_cb))), (view
), ((void*)0), (GConnectFlags) 0)
6973 view)g_signal_connect_data ((view->model), ("notify::inverted-colors"
), (((GCallback) (ev_view_inverted_colors_changed_cb))), (view
), ((void*)0), (GConnectFlags) 0)
;
6974 g_signal_connect (view->model, "notify::sizing-mode",g_signal_connect_data ((view->model), ("notify::sizing-mode"
), (((GCallback) (ev_view_sizing_mode_changed_cb))), (view), (
(void*)0), (GConnectFlags) 0)
6975 G_CALLBACK (ev_view_sizing_mode_changed_cb),g_signal_connect_data ((view->model), ("notify::sizing-mode"
), (((GCallback) (ev_view_sizing_mode_changed_cb))), (view), (
(void*)0), (GConnectFlags) 0)
6976 view)g_signal_connect_data ((view->model), ("notify::sizing-mode"
), (((GCallback) (ev_view_sizing_mode_changed_cb))), (view), (
(void*)0), (GConnectFlags) 0)
;
6977 g_signal_connect (view->model, "notify::page-layout",g_signal_connect_data ((view->model), ("notify::page-layout"
), (((GCallback) (ev_view_page_layout_changed_cb))), (view), (
(void*)0), (GConnectFlags) 0)
6978 G_CALLBACK (ev_view_page_layout_changed_cb),g_signal_connect_data ((view->model), ("notify::page-layout"
), (((GCallback) (ev_view_page_layout_changed_cb))), (view), (
(void*)0), (GConnectFlags) 0)
6979 view)g_signal_connect_data ((view->model), ("notify::page-layout"
), (((GCallback) (ev_view_page_layout_changed_cb))), (view), (
(void*)0), (GConnectFlags) 0)
;
6980 g_signal_connect (view->model, "notify::scale",g_signal_connect_data ((view->model), ("notify::scale"), (
((GCallback) (ev_view_scale_changed_cb))), (view), ((void*)0)
, (GConnectFlags) 0)
6981 G_CALLBACK (ev_view_scale_changed_cb),g_signal_connect_data ((view->model), ("notify::scale"), (
((GCallback) (ev_view_scale_changed_cb))), (view), ((void*)0)
, (GConnectFlags) 0)
6982 view)g_signal_connect_data ((view->model), ("notify::scale"), (
((GCallback) (ev_view_scale_changed_cb))), (view), ((void*)0)
, (GConnectFlags) 0)
;
6983 g_signal_connect (view->model, "notify::continuous",g_signal_connect_data ((view->model), ("notify::continuous"
), (((GCallback) (ev_view_continuous_changed_cb))), (view), (
(void*)0), (GConnectFlags) 0)
6984 G_CALLBACK (ev_view_continuous_changed_cb),g_signal_connect_data ((view->model), ("notify::continuous"
), (((GCallback) (ev_view_continuous_changed_cb))), (view), (
(void*)0), (GConnectFlags) 0)
6985 view)g_signal_connect_data ((view->model), ("notify::continuous"
), (((GCallback) (ev_view_continuous_changed_cb))), (view), (
(void*)0), (GConnectFlags) 0)
;
6986 g_signal_connect (view->model, "notify::dual-odd-left",g_signal_connect_data ((view->model), ("notify::dual-odd-left"
), (((GCallback) (ev_view_dual_odd_left_changed_cb))), (view)
, ((void*)0), (GConnectFlags) 0)
6987 G_CALLBACK (ev_view_dual_odd_left_changed_cb),g_signal_connect_data ((view->model), ("notify::dual-odd-left"
), (((GCallback) (ev_view_dual_odd_left_changed_cb))), (view)
, ((void*)0), (GConnectFlags) 0)
6988 view)g_signal_connect_data ((view->model), ("notify::dual-odd-left"
), (((GCallback) (ev_view_dual_odd_left_changed_cb))), (view)
, ((void*)0), (GConnectFlags) 0)
;
6989 g_signal_connect (view->model, "notify::fullscreen",g_signal_connect_data ((view->model), ("notify::fullscreen"
), (((GCallback) (ev_view_fullscreen_changed_cb))), (view), (
(void*)0), (GConnectFlags) 0)
6990 G_CALLBACK (ev_view_fullscreen_changed_cb),g_signal_connect_data ((view->model), ("notify::fullscreen"
), (((GCallback) (ev_view_fullscreen_changed_cb))), (view), (
(void*)0), (GConnectFlags) 0)
6991 view)g_signal_connect_data ((view->model), ("notify::fullscreen"
), (((GCallback) (ev_view_fullscreen_changed_cb))), (view), (
(void*)0), (GConnectFlags) 0)
;
6992 g_signal_connect (view->model, "page-changed",g_signal_connect_data ((view->model), ("page-changed"), ((
(GCallback) (ev_view_page_changed_cb))), (view), ((void*)0), (
GConnectFlags) 0)
6993 G_CALLBACK (ev_view_page_changed_cb),g_signal_connect_data ((view->model), ("page-changed"), ((
(GCallback) (ev_view_page_changed_cb))), (view), ((void*)0), (
GConnectFlags) 0)
6994 view)g_signal_connect_data ((view->model), ("page-changed"), ((
(GCallback) (ev_view_page_changed_cb))), (view), ((void*)0), (
GConnectFlags) 0)
;
6995
6996 if (view->accessible)
6997 ev_view_accessible_set_model (EV_VIEW_ACCESSIBLE (view->accessible)((((EvViewAccessible*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((view->accessible)), ((ev_view_accessible_get_type
()))))))
,
6998 view->model);
6999}
7000
7001static void
7002ev_view_reload_page (EvView *view,
7003 gint page,
7004 cairo_region_t *region)
7005{
7006 ev_pixbuf_cache_reload_page (view->pixbuf_cache,
7007 region,
7008 page,
7009 view->rotation,
7010 view->scale);
7011}
7012
7013void
7014ev_view_reload (EvView *view)
7015{
7016 ev_pixbuf_cache_clear (view->pixbuf_cache);
7017 view_update_range_and_current_page (view);
7018}
7019
7020/*** Zoom and sizing mode ***/
7021
7022gboolean
7023ev_view_can_zoom_in (EvView *view)
7024{
7025 return view->scale * ZOOM_IN_FACTOR1.2 <= ev_document_model_get_max_scale (view->model);
7026}
7027
7028gboolean
7029ev_view_can_zoom_out (EvView *view)
7030{
7031 return view->scale * ZOOM_OUT_FACTOR(1.0/1.2) >= ev_document_model_get_min_scale (view->model);
7032}
7033
7034void
7035ev_view_zoom (EvView *view, gdouble factor)
7036{
7037 gdouble scale;
7038
7039 g_return_if_fail (view->sizing_mode == EV_SIZING_FREE)do { if ((view->sizing_mode == EV_SIZING_FREE)) { } else {
g_return_if_fail_warning ("LectorView", ((const char*) (__func__
)), "view->sizing_mode == EV_SIZING_FREE"); return; } } while
(0)
;
7040
7041 view->pending_scroll = SCROLL_TO_CENTER;
7042 scale = ev_document_model_get_scale (view->model) * factor;
7043 ev_document_model_set_scale (view->model, scale);
7044}
7045
7046void
7047ev_view_zoom_in (EvView *view)
7048{
7049 ev_view_zoom (view, ZOOM_IN_FACTOR1.2);
7050}
7051
7052void
7053ev_view_zoom_out (EvView *view)
7054{
7055 ev_view_zoom (view, ZOOM_OUT_FACTOR(1.0/1.2));
7056}
7057
7058void
7059ev_view_zoom_reset (EvView *view)
7060{
7061 g_return_if_fail (view->sizing_mode == EV_SIZING_FREE)do { if ((view->sizing_mode == EV_SIZING_FREE)) { } else {
g_return_if_fail_warning ("LectorView", ((const char*) (__func__
)), "view->sizing_mode == EV_SIZING_FREE"); return; } } while
(0)
;
7062 ev_document_model_set_scale (view->model, 1.2);
7063}
7064
7065static double
7066zoom_for_size_fit_width (gdouble doc_width,
7067 gdouble doc_height,
7068 int target_width,
7069 int target_height)
7070{
7071 return (double)target_width / doc_width;
7072}
7073
7074static double
7075zoom_for_size_fit_height (gdouble doc_width,
7076 gdouble doc_height,
7077 int target_width,
7078 int target_height)
7079{
7080 return (double)target_height / doc_height;
7081}
7082
7083static double
7084zoom_for_size_fit_page (gdouble doc_width,
7085 gdouble doc_height,
7086 int target_width,
7087 int target_height)
7088{
7089 double w_scale;
7090 double h_scale;
7091
7092 w_scale = (double)target_width / doc_width;
7093 h_scale = (double)target_height / doc_height;
7094
7095 return MIN (w_scale, h_scale)(((w_scale) < (h_scale)) ? (w_scale) : (h_scale));
7096}
7097
7098static double
7099zoom_for_size_automatic (CdkScreen *screen,
7100 gdouble doc_width,
7101 gdouble doc_height,
7102 int target_width,
7103 int target_height)
7104{
7105 double fit_width_scale;
7106 double scale;
7107
7108 fit_width_scale = zoom_for_size_fit_width (doc_width, doc_height, target_width, target_height);
7109
7110 if (doc_height < doc_width) {
7111 double fit_height_scale;
7112
7113 fit_height_scale = zoom_for_size_fit_height (doc_width, doc_height, target_width, target_height);
7114 scale = MIN (fit_width_scale, fit_height_scale)(((fit_width_scale) < (fit_height_scale)) ? (fit_width_scale
) : (fit_height_scale))
;
7115 } else {
7116 double actual_scale, resolution;
7117
7118 resolution = cdk_screen_get_resolution (screen);
7119 if (resolution == -1) {
7120 CdkDisplay *display = cdk_screen_get_display (screen);
7121 CdkMonitor *monitor = cdk_display_get_primary_monitor (display);
7122 resolution = ev_document_misc_get_monitor_dpi (monitor);
7123 }
7124 actual_scale = resolution / 72.0;
7125 scale = MIN (fit_width_scale, actual_scale)(((fit_width_scale) < (actual_scale)) ? (fit_width_scale) :
(actual_scale))
;
7126 }
7127
7128 return scale;
7129}
7130
7131static void
7132ev_view_zoom_for_size_continuous_and_dual_page (EvView *view,
7133 int width,
7134 int height)
7135{
7136 gdouble doc_width, doc_height;
7137 CtkBorder border;
7138 gdouble scale;
7139 gint sb_size;
7140
7141 ev_document_get_max_page_size (view->document, &doc_width, &doc_height);
7142 if (view->rotation == 90 || view->rotation == 270) {
7143 gdouble tmp;
7144
7145 tmp = doc_width;
7146 doc_width = doc_height;
7147 doc_height = tmp;
7148 }
7149
7150 compute_border (view, &border);
7151
7152 doc_width *= 2;
7153 width -= (2 * (border.left + border.right) + 3 * view->spacing);
7154 height -= (border.top + border.bottom + 2 * view->spacing - 1);
7155
7156 sb_size = ev_view_get_scrollbar_size (view, CTK_ORIENTATION_VERTICAL);
7157
7158 switch (view->sizing_mode) {
7159 case EV_SIZING_FIT_WIDTH:
7160 scale = zoom_for_size_fit_width (doc_width, doc_height, width - sb_size, height);
7161 break;
7162 case EV_SIZING_FIT_PAGE:
7163 scale = zoom_for_size_fit_page (doc_width, doc_height, width - sb_size, height);
7164 break;
7165 case EV_SIZING_AUTOMATIC:
7166 scale = zoom_for_size_automatic (ctk_widget_get_screen (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
),
7167 doc_width, doc_height, width - sb_size, height);
7168 break;
7169 default:
7170 g_assert_not_reached ()do { g_assertion_message_expr ("LectorView", "ev-view.c", 7170
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
7171 }
7172
7173 ev_document_model_set_scale (view->model, scale);
7174}
7175
7176static void
7177ev_view_zoom_for_size_continuous (EvView *view,
7178 int width,
7179 int height)
7180{
7181 gdouble doc_width, doc_height;
7182 CtkBorder border;
7183 gdouble scale;
7184 gint sb_size;
7185
7186 ev_document_get_max_page_size (view->document, &doc_width, &doc_height);
7187 if (view->rotation == 90 || view->rotation == 270) {
7188 gdouble tmp;
7189
7190 tmp = doc_width;
7191 doc_width = doc_height;
7192 doc_height = tmp;
7193 }
7194
7195 compute_border (view, &border);
7196
7197 width -= (border.left + border.right + 2 * view->spacing);
7198 height -= (border.top + border.bottom + 2 * view->spacing - 1);
7199
7200 sb_size = ev_view_get_scrollbar_size (view, CTK_ORIENTATION_VERTICAL);
7201
7202 switch (view->sizing_mode) {
7203 case EV_SIZING_FIT_WIDTH:
7204 scale = zoom_for_size_fit_width (doc_width, doc_height, width - sb_size, height);
7205 break;
7206 case EV_SIZING_FIT_PAGE:
7207 scale = zoom_for_size_fit_page (doc_width, doc_height, width - sb_size, height);
7208 break;
7209 case EV_SIZING_AUTOMATIC:
7210 scale = zoom_for_size_automatic (ctk_widget_get_screen (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
),
7211 doc_width, doc_height, width - sb_size, height);
7212 break;
7213 default:
7214 g_assert_not_reached ()do { g_assertion_message_expr ("LectorView", "ev-view.c", 7214
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
7215 }
7216
7217 ev_document_model_set_scale (view->model, scale);
7218}
7219
7220static void
7221ev_view_zoom_for_size_dual_page (EvView *view,
7222 int width,
7223 int height)
7224{
7225 CtkBorder border;
7226 gdouble doc_width, doc_height;
7227 gdouble scale;
7228 gint other_page;
7229 gint sb_size;
7230
7231 other_page = view->current_page ^ 1;
7232
7233 /* Find the largest of the two. */
7234 get_doc_page_size (view, view->current_page, &doc_width, &doc_height);
7235 if (other_page < ev_document_get_n_pages (view->document)) {
7236 gdouble width_2, height_2;
7237
7238 get_doc_page_size (view, other_page, &width_2, &height_2);
7239 if (width_2 > doc_width)
7240 doc_width = width_2;
7241 if (height_2 > doc_height)
7242 doc_height = height_2;
7243 }
7244 compute_border (view, &border);
7245
7246 doc_width = doc_width * 2;
7247 width -= ((border.left + border.right)* 2 + 3 * view->spacing);
7248 height -= (border.top + border.bottom + 2 * view->spacing);
7249
7250 switch (view->sizing_mode) {
7251 case EV_SIZING_FIT_WIDTH:
7252 sb_size = ev_view_get_scrollbar_size (view, CTK_ORIENTATION_VERTICAL);
7253 scale = zoom_for_size_fit_width (doc_width, doc_height, width - sb_size, height);
7254 break;
7255 case EV_SIZING_FIT_PAGE:
7256 scale = zoom_for_size_fit_page (doc_width, doc_height, width, height);
7257 break;
7258 case EV_SIZING_AUTOMATIC:
7259 sb_size = ev_view_get_scrollbar_size (view, CTK_ORIENTATION_VERTICAL);
7260 scale = zoom_for_size_automatic (ctk_widget_get_screen (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
),
7261 doc_width, doc_height, width - sb_size, height);
7262 break;
7263 default:
7264 g_assert_not_reached ()do { g_assertion_message_expr ("LectorView", "ev-view.c", 7264
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
7265 }
7266
7267 ev_document_model_set_scale (view->model, scale);
7268}
7269
7270static void
7271ev_view_zoom_for_size_single_page (EvView *view,
7272 int width,
7273 int height)
7274{
7275 gdouble doc_width, doc_height;
7276 CtkBorder border;
7277 gdouble scale;
7278 gint sb_size;
7279
7280 get_doc_page_size (view, view->current_page, &doc_width, &doc_height);
7281
7282 /* Get an approximate border */
7283 compute_border (view, &border);
7284
7285 width -= (border.left + border.right + 2 * view->spacing);
7286 height -= (border.top + border.bottom + 2 * view->spacing);
7287
7288 switch (view->sizing_mode) {
7289 case EV_SIZING_FIT_WIDTH:
7290 sb_size = ev_view_get_scrollbar_size (view, CTK_ORIENTATION_VERTICAL);
7291 scale = zoom_for_size_fit_width (doc_width, doc_height, width - sb_size, height);
7292 break;
7293 case EV_SIZING_FIT_PAGE:
7294 scale = zoom_for_size_fit_page (doc_width, doc_height, width, height);
7295 break;
7296 case EV_SIZING_AUTOMATIC:
7297 sb_size = ev_view_get_scrollbar_size (view, CTK_ORIENTATION_VERTICAL);
7298 scale = zoom_for_size_automatic (ctk_widget_get_screen (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
),
7299 doc_width, doc_height, width - sb_size, height);
7300 break;
7301 default:
7302 g_assert_not_reached ()do { g_assertion_message_expr ("LectorView", "ev-view.c", 7302
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
7303 }
7304
7305 ev_document_model_set_scale (view->model, scale);
7306}
7307
7308static void
7309ev_view_zoom_for_size (EvView *view,
7310 int width,
7311 int height)
7312{
7313 gboolean dual_page;
7314
7315 g_return_if_fail (EV_IS_VIEW (view))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ev_view_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("LectorView", ((const char*
) (__func__)), "EV_IS_VIEW (view)"); return; } } while (0)
;
7316 g_return_if_fail (view->sizing_mode == EV_SIZING_FIT_WIDTH ||do { if ((view->sizing_mode == EV_SIZING_FIT_WIDTH || view
->sizing_mode == EV_SIZING_FIT_PAGE || view->sizing_mode
== EV_SIZING_AUTOMATIC)) { } else { g_return_if_fail_warning
("LectorView", ((const char*) (__func__)), "view->sizing_mode == EV_SIZING_FIT_WIDTH || view->sizing_mode == EV_SIZING_FIT_PAGE || view->sizing_mode == EV_SIZING_AUTOMATIC"
); return; } } while (0)
7317 view->sizing_mode == EV_SIZING_FIT_PAGE ||do { if ((view->sizing_mode == EV_SIZING_FIT_WIDTH || view
->sizing_mode == EV_SIZING_FIT_PAGE || view->sizing_mode
== EV_SIZING_AUTOMATIC)) { } else { g_return_if_fail_warning
("LectorView", ((const char*) (__func__)), "view->sizing_mode == EV_SIZING_FIT_WIDTH || view->sizing_mode == EV_SIZING_FIT_PAGE || view->sizing_mode == EV_SIZING_AUTOMATIC"
); return; } } while (0)
7318 view->sizing_mode == EV_SIZING_AUTOMATIC)do { if ((view->sizing_mode == EV_SIZING_FIT_WIDTH || view
->sizing_mode == EV_SIZING_FIT_PAGE || view->sizing_mode
== EV_SIZING_AUTOMATIC)) { } else { g_return_if_fail_warning
("LectorView", ((const char*) (__func__)), "view->sizing_mode == EV_SIZING_FIT_WIDTH || view->sizing_mode == EV_SIZING_FIT_PAGE || view->sizing_mode == EV_SIZING_AUTOMATIC"
); return; } } while (0)
;
7319 g_return_if_fail (width >= 0)do { if ((width >= 0)) { } else { g_return_if_fail_warning
("LectorView", ((const char*) (__func__)), "width >= 0");
return; } } while (0)
;
7320 g_return_if_fail (height >= 0)do { if ((height >= 0)) { } else { g_return_if_fail_warning
("LectorView", ((const char*) (__func__)), "height >= 0")
; return; } } while (0)
;
7321
7322 if (view->document == NULL((void*)0))
7323 return;
7324
7325 dual_page = is_dual_page (view, NULL((void*)0));
7326 if (view->continuous && dual_page)
7327 ev_view_zoom_for_size_continuous_and_dual_page (view, width, height);
7328 else if (view->continuous)
7329 ev_view_zoom_for_size_continuous (view, width, height);
7330 else if (dual_page)
7331 ev_view_zoom_for_size_dual_page (view, width, height);
7332 else
7333 ev_view_zoom_for_size_single_page (view, width, height);
7334}
7335
7336static gboolean
7337ev_view_page_fits (EvView *view,
7338 CtkOrientation orientation)
7339{
7340 CtkRequisition requisition;
7341 CtkAllocation allocation;
7342 double size;
7343
7344 if (view->sizing_mode == EV_SIZING_FIT_PAGE)
7345 return TRUE(!(0));
7346
7347 if (orientation == CTK_ORIENTATION_HORIZONTAL &&
7348 (view->sizing_mode == EV_SIZING_FIT_WIDTH))
7349 return TRUE(!(0));
7350
7351 ctk_widget_get_allocation (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
, &allocation);
7352 ev_view_size_request (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
, &requisition);
7353
7354 if (orientation == CTK_ORIENTATION_HORIZONTAL) {
7355 if (requisition.width == 1) {
7356 size = 1.0;
7357 } else {
7358 if (allocation.width > 0.0)
7359 size = (double) requisition.width / allocation.width;
7360 else
7361 size = 1.0;
7362 }
7363 } else {
7364 if (requisition.height == 1) {
7365 size = 1.0;
7366 } else {
7367 if (allocation.height > 0.0)
7368 size = (double) requisition.height / allocation.height;
7369 else
7370 size = 1.0;
7371 }
7372 }
7373
7374 return size <= 1.0;
7375}
7376
7377/*** Find ***/
7378static gint
7379ev_view_find_get_n_results (EvView *view, gint page)
7380{
7381 return view->find_pages ? g_list_length (view->find_pages[page]) : 0;
7382}
7383
7384static EvRectangle *
7385ev_view_find_get_result (EvView *view, gint page, gint result)
7386{
7387 return view->find_pages ? (EvRectangle *) g_list_nth_data (view->find_pages[page], result) : NULL((void*)0);
7388}
7389
7390static void
7391jump_to_find_result (EvView *view)
7392{
7393 gint n_results;
7394 gint page = view->current_page;
7395
7396 n_results = ev_view_find_get_n_results (view, page);
7397
7398 if (n_results > 0 && view->find_result < n_results) {
7399 EvRectangle *rect;
7400 CdkRectangle view_rect;
7401
7402 rect = ev_view_find_get_result (view, page, view->find_result);
7403 _ev_view_transform_doc_rect_to_view_rect (view, page, rect, &view_rect);
7404 ensure_rectangle_is_visible (view, &view_rect);
7405 if (view->caret_enabled && view->rotation == 0)
7406 position_caret_cursor_at_doc_point (view, page, rect->x1, rect->y1);
7407
7408 view->jump_to_find_result = FALSE(0);
7409 }
7410}
7411
7412/**
7413 * jump_to_find_page:
7414 * @view: #EvView instance
7415 * @direction: Direction to look
7416 * @shift: Shift from current page
7417 *
7418 * Jumps to the first page that has occurences of searched word.
7419 * Uses a direction where to look and a shift from current page.
7420 *
7421 */
7422static void
7423jump_to_find_page (EvView *view, EvViewFindDirection direction, gint shift)
7424{
7425 int n_pages, i;
7426
7427 n_pages = ev_document_get_n_pages (view->document);
7428
7429 for (i = 0; i < n_pages; i++) {
7430 int page;
7431
7432 if (direction == EV_VIEW_FIND_NEXT)
7433 page = view->current_page + i;
7434 else
7435 page = view->current_page - i;
7436 page += shift;
7437
7438 if (page >= n_pages) {
7439 page = page - n_pages;
7440 } else if (page < 0)
7441 page = page + n_pages;
7442
7443 if (ev_view_find_get_n_results (view, page) > 0) {
7444 ev_document_model_set_page (view->model, page);
7445 break;
7446 }
7447 }
7448}
7449
7450/**
7451 * ev_view_find_changed: (skip)
7452 * @view: an #EvView
7453 * @results: the results as returned by ev_job_find_get_results()
7454 * @page: page index
7455 */
7456void
7457ev_view_find_changed (EvView *view, GList **results, gint page)
7458{
7459 g_return_if_fail (view->current_page >= 0)do { if ((view->current_page >= 0)) { } else { g_return_if_fail_warning
("LectorView", ((const char*) (__func__)), "view->current_page >= 0"
); return; } } while (0)
;
7460 view->find_pages = results;
7461
7462 if (view->jump_to_find_result == TRUE(!(0))) {
7463 jump_to_find_page (view, EV_VIEW_FIND_NEXT, 0);
7464 jump_to_find_result (view);
7465 }
7466
7467 if (view->current_page == page)
7468 ctk_widget_queue_draw (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
7469}
7470
7471void
7472ev_view_find_next (EvView *view)
7473{
7474 gint n_results;
7475
7476 n_results = ev_view_find_get_n_results (view, view->current_page);
7477 view->find_result++;
7478
7479 if (view->find_result >= n_results) {
7480 view->find_result = 0;
7481 jump_to_find_page (view, EV_VIEW_FIND_NEXT, 1);
7482 jump_to_find_result (view);
7483 } else {
7484 jump_to_find_result (view);
7485 ctk_widget_queue_draw (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
7486 }
7487}
7488
7489void
7490ev_view_find_previous (EvView *view)
7491{
7492 view->find_result--;
7493
7494 if (view->find_result < 0) {
7495 jump_to_find_page (view, EV_VIEW_FIND_PREV, -1);
7496 view->find_result = MAX (0, ev_view_find_get_n_results (view, view->current_page) - 1)(((0) > (ev_view_find_get_n_results (view, view->current_page
) - 1)) ? (0) : (ev_view_find_get_n_results (view, view->current_page
) - 1))
;
7497 jump_to_find_result (view);
7498 } else {
7499 jump_to_find_result (view);
7500 ctk_widget_queue_draw (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
7501 }
7502}
7503
7504void
7505ev_view_find_search_changed (EvView *view)
7506{
7507 /* search string has changed, focus on new search result */
7508 view->jump_to_find_result = TRUE(!(0));
7509 view->find_pages = NULL((void*)0);
7510}
7511
7512void
7513ev_view_find_set_highlight_search (EvView *view, gboolean value)
7514{
7515 view->highlight_find_results = value;
7516 ctk_widget_queue_draw (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
7517}
7518
7519void
7520ev_view_find_cancel (EvView *view)
7521{
7522 view->find_pages = NULL((void*)0);
7523}
7524
7525/*** Synctex ***/
7526void
7527ev_view_highlight_forward_search (EvView *view,
7528 EvSourceLink *link)
7529{
7530 EvMapping *mapping;
7531 gint page;
7532 CdkRectangle view_rect;
7533
7534 if (!ev_document_has_synctex (view->document))
7535 return;
7536
7537 mapping = ev_document_synctex_forward_search (view->document, link);
7538 if (!mapping)
7539 return;
7540
7541 if (view->synctex_result)
7542 g_free (view->synctex_result);
7543 view->synctex_result = mapping;
7544
7545 page = GPOINTER_TO_INT (mapping->data)((gint) (glong) (mapping->data));
7546 ev_document_model_set_page (view->model, page);
7547
7548 _ev_view_transform_doc_rect_to_view_rect (view, page, &mapping->area, &view_rect);
7549 ensure_rectangle_is_visible (view, &view_rect);
7550 ctk_widget_queue_draw (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
7551}
7552
7553/*** Selections ***/
7554static gboolean
7555cdk_rectangle_point_in (CdkRectangle *rectangle,
7556 CdkPoint *point)
7557{
7558 return rectangle->x <= point->x &&
7559 rectangle->y <= point->y &&
7560 point->x < rectangle->x + rectangle->width &&
7561 point->y < rectangle->y + rectangle->height;
7562}
7563
7564static inline gboolean
7565cdk_point_equal (CdkPoint *a,
7566 CdkPoint *b)
7567{
7568 return a->x == b->x && a->y == b->y;
7569}
7570
7571static gboolean
7572get_selection_page_range (EvView *view,
7573 EvSelectionStyle style,
7574 CdkPoint *start,
7575 CdkPoint *stop,
7576 gint *first_page,
7577 gint *last_page)
7578{
7579 gint start_page, end_page;
7580 gint first, last;
7581 gint i, n_pages;
7582
7583 n_pages = ev_document_get_n_pages (view->document);
7584
7585 if (cdk_point_equal (start, stop)) {
7586 start_page = view->start_page;
7587 end_page = view->end_page;
7588 } else if (view->continuous) {
7589 start_page = 0;
7590 end_page = n_pages - 1;
7591 } else if (is_dual_page (view, NULL((void*)0))) {
7592 start_page = view->start_page;
7593 end_page = view->end_page;
7594 } else {
7595 start_page = view->current_page;
7596 end_page = view->current_page;
7597 }
7598
7599 first = -1;
7600 last = -1;
7601 for (i = start_page; i <= end_page; i++) {
7602 CdkRectangle page_area;
7603 CtkBorder border;
7604
7605 ev_view_get_page_extents (view, i, &page_area, &border);
7606 page_area.x -= border.left;
7607 page_area.y -= border.top;
7608 page_area.width += border.left + border.right;
7609 page_area.height += border.top + border.bottom;
7610 if (cdk_rectangle_point_in (&page_area, start) ||
7611 cdk_rectangle_point_in (&page_area, stop)) {
7612 if (first == -1)
7613 first = i;
7614 last = i;
7615 }
7616 }
7617
7618 if (first != -1 && last != -1) {
7619 *first_page = first;
7620 *last_page = last;
7621
7622 return TRUE(!(0));
7623 }
7624
7625 return FALSE(0);
7626}
7627
7628static GList *
7629compute_new_selection (EvView *view,
7630 EvSelectionStyle style,
7631 CdkPoint *start,
7632 CdkPoint *stop)
7633{
7634 int i, first, last;
7635 GList *list = NULL((void*)0);
7636
7637 /* First figure out the range of pages the selection affects. */
7638 if (!get_selection_page_range (view, style, start, stop, &first, &last))
7639 return list;
7640
7641 /* Now create a list of EvViewSelection's for the affected
7642 * pages. This could be an empty list, a list of just one
7643 * page or a number of pages.*/
7644 for (i = first; i <= last; i++) {
7645 EvViewSelection *selection;
7646 CdkRectangle page_area;
7647 CtkBorder border;
7648 CdkPoint *point;
7649 gdouble width, height;
7650
7651 get_doc_page_size (view, i, &width, &height);
7652
7653 selection = g_slice_new0 (EvViewSelection)((EvViewSelection*) g_slice_alloc0 (sizeof (EvViewSelection))
)
;
7654 selection->page = i;
7655 selection->style = style;
7656 selection->rect.x1 = selection->rect.y1 = 0;
7657 selection->rect.x2 = width;
7658 selection->rect.y2 = height;
7659
7660 ev_view_get_page_extents (view, i, &page_area, &border);
7661 page_area.x -= border.left;
7662 page_area.y -= border.top;
7663 page_area.width += border.left + border.right;
7664 page_area.height += border.top + border.bottom;
7665
7666 if (cdk_rectangle_point_in (&page_area, start))
7667 point = start;
7668 else
7669 point = stop;
7670
7671 if (i == first) {
7672 _ev_view_transform_view_point_to_doc_point (view, point, &page_area,
7673 &selection->rect.x1,
7674 &selection->rect.y1);
7675 selection->rect.x1 = MAX (selection->rect.x1 - border.left, 0)(((selection->rect.x1 - border.left) > (0)) ? (selection
->rect.x1 - border.left) : (0))
;
7676 selection->rect.y1 = MAX (selection->rect.y1 - border.top, 0)(((selection->rect.y1 - border.top) > (0)) ? (selection
->rect.y1 - border.top) : (0))
;
7677 }
7678
7679 /* If the selection is contained within just one page,
7680 * make sure we don't write 'start' into both points
7681 * in selection->rect. */
7682 if (first == last)
7683 point = stop;
7684
7685 if (i == last) {
7686 _ev_view_transform_view_point_to_doc_point (view, point, &page_area,
7687 &selection->rect.x2,
7688 &selection->rect.y2);
7689 selection->rect.x2 = MAX (selection->rect.x2 - border.right, 0)(((selection->rect.x2 - border.right) > (0)) ? (selection
->rect.x2 - border.right) : (0))
;
7690 selection->rect.y2 = MAX (selection->rect.y2 - border.bottom, 0)(((selection->rect.y2 - border.bottom) > (0)) ? (selection
->rect.y2 - border.bottom) : (0))
;
7691 }
7692
7693 list = g_list_prepend (list, selection);
7694 }
7695
7696 return g_list_reverse (list);
7697}
7698
7699/* This function takes the newly calculated list, and figures out which regions
7700 * have changed. It then queues a redraw approporiately.
7701 */
7702static void
7703merge_selection_region (EvView *view,
7704 GList *new_list)
7705{
7706 GList *old_list;
7707 GList *new_list_ptr, *old_list_ptr;
7708
7709 /* Update the selection */
7710 old_list = ev_pixbuf_cache_get_selection_list (view->pixbuf_cache);
7711 g_list_free_full (view->selection_info.selections, (GDestroyNotify)selection_free);
7712 view->selection_info.selections = new_list;
7713 ev_pixbuf_cache_set_selection_list (view->pixbuf_cache, new_list);
7714 g_signal_emit (view, signals[SIGNAL_SELECTION_CHANGED], 0, NULL((void*)0));
7715
7716 new_list_ptr = new_list;
7717 old_list_ptr = old_list;
7718
7719 while (new_list_ptr || old_list_ptr) {
7720 EvViewSelection *old_sel, *new_sel;
7721 int cur_page;
7722 cairo_region_t *region = NULL((void*)0);
7723
7724 new_sel = (new_list_ptr) ? (new_list_ptr->data) : NULL((void*)0);
7725 old_sel = (old_list_ptr) ? (old_list_ptr->data) : NULL((void*)0);
7726
7727 /* Assume that the lists are in order, and we run through them
7728 * comparing them, one page at a time. We come out with the
7729 * first page we see. */
7730 if (new_sel && old_sel) {
7731 if (new_sel->page < old_sel->page) {
7732 new_list_ptr = new_list_ptr->next;
7733 old_sel = NULL((void*)0);
7734 } else if (new_sel->page > old_sel->page) {
7735 old_list_ptr = old_list_ptr->next;
7736 new_sel = NULL((void*)0);
7737 } else {
7738 new_list_ptr = new_list_ptr->next;
7739 old_list_ptr = old_list_ptr->next;
7740 }
7741 } else if (new_sel) {
7742 new_list_ptr = new_list_ptr->next;
7743 } else if (old_sel) {
7744 old_list_ptr = old_list_ptr->next;
7745 }
7746
7747 g_assert (new_sel || old_sel)do { if (new_sel || old_sel) ; else g_assertion_message_expr (
"LectorView", "ev-view.c", 7747, ((const char*) (__func__)), "new_sel || old_sel"
); } while (0)
;
7748
7749 /* is the page we're looking at on the screen?*/
7750 cur_page = new_sel ? new_sel->page : old_sel->page;
7751 if (cur_page < view->start_page || cur_page > view->end_page)
7752 continue;
7753
7754 /* seed the cache with a new page. We are going to need the new
7755 * region too. */
7756 if (new_sel) {
7757 cairo_region_t *tmp_region;
7758
7759 tmp_region = ev_pixbuf_cache_get_selection_region (view->pixbuf_cache,
7760 cur_page,
7761 view->scale);
7762 if (tmp_region)
7763 new_sel->covered_region = cairo_region_reference (tmp_region);
7764 }
7765
7766 /* Now we figure out what needs redrawing */
7767 if (old_sel && new_sel) {
7768 if (old_sel->covered_region && new_sel->covered_region) {
7769 if (!cairo_region_equal (old_sel->covered_region, new_sel->covered_region)) {
7770 /* Anything that was previously or currently selected may
7771 * have changed */
7772 region = cairo_region_copy (old_sel->covered_region);
7773 cairo_region_union (region, new_sel->covered_region);
7774 }
7775 } else if (old_sel->covered_region) {
7776 region = cairo_region_reference (old_sel->covered_region);
7777 } else if (new_sel->covered_region) {
7778 region = cairo_region_reference (new_sel->covered_region);
7779 }
7780 } else if (old_sel && !new_sel) {
7781 if (old_sel->covered_region && !cairo_region_is_empty (old_sel->covered_region)) {
7782 region = cairo_region_reference (old_sel->covered_region);
7783 }
7784 } else if (!old_sel && new_sel) {
7785 if (new_sel->covered_region && !cairo_region_is_empty (new_sel->covered_region)) {
7786 region = cairo_region_reference (new_sel->covered_region);
7787 }
7788 } else {
7789 g_assert_not_reached ()do { g_assertion_message_expr ("LectorView", "ev-view.c", 7789
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
7790 }
7791
7792 /* Redraw the damaged region! */
7793 if (region) {
7794 CdkRectangle page_area;
7795 CtkBorder border;
7796 cairo_region_t *damage_region;
7797 gint i, n_rects;
7798
7799 ev_view_get_page_extents (view, cur_page, &page_area, &border);
7800
7801 damage_region = cairo_region_create ();
7802 /* Translate the region and grow it 2 pixels because for some zoom levels
7803 * the area actually drawn by cairo is larger than the selected region, due
7804 * to rounding errors or pixel alignment.
7805 */
7806 n_rects = cairo_region_num_rectangles (region);
7807 for (i = 0; i < n_rects; i++) {
7808 cairo_rectangle_int_t rect;
7809
7810 cairo_region_get_rectangle (region, i, &rect);
7811 rect.x += page_area.x + border.left - view->scroll_x - 2;
7812 rect.y += page_area.y + border.top - view->scroll_y - 2;
7813 rect.width += 4;
7814 rect.height += 4;
7815 cairo_region_union_rectangle (damage_region, &rect);
7816 }
7817 cairo_region_destroy (region);
7818
7819 cdk_window_invalidate_region (ctk_widget_get_window (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
),
7820 damage_region, TRUE(!(0)));
7821 cairo_region_destroy (damage_region);
7822 }
7823 }
7824
7825 ev_view_check_cursor_blink (view);
7826
7827 /* Free the old list, now that we're done with it. */
7828 g_list_free_full (old_list, (GDestroyNotify)selection_free);
7829}
7830
7831static void
7832compute_selections (EvView *view,
7833 EvSelectionStyle style,
7834 CdkPoint *start,
7835 CdkPoint *stop)
7836{
7837 merge_selection_region (view, compute_new_selection (view, style, start, stop));
7838}
7839
7840/* Free's the selection. It's up to the caller to queue redraws if needed.
7841 */
7842static void
7843selection_free (EvViewSelection *selection)
7844{
7845 if (selection->covered_region)
7846 cairo_region_destroy (selection->covered_region);
7847 g_slice_free (EvViewSelection, selection)do { if (1) g_slice_free1 (sizeof (EvViewSelection), (selection
)); else (void) ((EvViewSelection*) 0 == (selection)); } while
(0)
;
7848}
7849
7850static void
7851clear_selection (EvView *view)
7852{
7853 merge_selection_region (view, NULL((void*)0));
7854}
7855
7856void
7857ev_view_select_all (EvView *view)
7858{
7859 GList *selections = NULL((void*)0);
7860 int n_pages, i;
7861
7862 /* Disable selection on rotated pages for the 0.4.0 series */
7863 if (view->rotation != 0)
7864 return;
7865
7866 n_pages = ev_document_get_n_pages (view->document);
7867 for (i = 0; i < n_pages; i++) {
7868 gdouble width, height;
7869 EvViewSelection *selection;
7870
7871 get_doc_page_size (view, i, &width, &height);
7872
7873 selection = g_slice_new0 (EvViewSelection)((EvViewSelection*) g_slice_alloc0 (sizeof (EvViewSelection))
)
;
7874 selection->page = i;
7875 selection->style = EV_SELECTION_STYLE_GLYPH;
7876 selection->rect.x1 = selection->rect.y1 = 0;
7877 selection->rect.x2 = width;
7878 selection->rect.y2 = height;
7879
7880 selections = g_list_prepend (selections, selection);
7881 }
7882
7883 merge_selection_region (view, g_list_reverse (selections));
7884}
7885
7886gboolean
7887ev_view_get_has_selection (EvView *view)
7888{
7889 return view->selection_info.selections != NULL((void*)0);
7890}
7891
7892void
7893_ev_view_clear_selection (EvView *view)
7894{
7895 clear_selection (view);
7896}
7897
7898void
7899_ev_view_set_selection (EvView *view,
7900 CdkPoint *start_point,
7901 CdkPoint *end_point)
7902{
7903 compute_selections (view, EV_SELECTION_STYLE_GLYPH, start_point, end_point);
7904}
7905
7906static char *
7907get_selected_text (EvView *view)
7908{
7909 GString *text;
7910 GList *l;
7911 gchar *normalized_text;
7912
7913 text = g_string_new (NULL((void*)0));
7914
7915 ev_document_doc_mutex_lock ();
7916
7917 for (l = view->selection_info.selections; l != NULL((void*)0); l = l->next) {
7918 EvViewSelection *selection = (EvViewSelection *)l->data;
7919 EvPage *page;
7920 gchar *tmp;
7921
7922 page = ev_document_get_page (view->document, selection->page);
7923 tmp = ev_selection_get_selected_text (EV_SELECTION (view->document)((((EvSelection*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view->document)), ((ev_selection_get_type ()))))))
,
7924 page, selection->style,
7925 &(selection->rect));
7926 g_object_unref (page);
7927 g_string_append (text, tmp)(__builtin_constant_p (tmp) ? __extension__ ({ const char * const
__val = (tmp); g_string_append_len_inline (text, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (text, tmp, (gssize) -
1))
;
7928 g_free (tmp);
7929 }
7930
7931 ev_document_doc_mutex_unlock ();
7932
7933 normalized_text = g_utf8_normalize (text->str, text->len, G_NORMALIZE_NFKC);
7934 g_string_free (text, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(text), ((!(0)))) : g_string_free_and_steal (text)) : (g_string_free
) ((text), ((!(0)))))
;
7935 return normalized_text;
7936}
7937
7938static void
7939ev_view_clipboard_copy (EvView *view,
7940 const gchar *text)
7941{
7942 CtkClipboard *clipboard;
7943
7944 clipboard = ctk_widget_get_clipboard (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
,
7945 CDK_SELECTION_CLIPBOARD((CdkAtom)((gpointer) (gulong) (69))));
7946 ctk_clipboard_set_text (clipboard, text, -1);
7947}
7948
7949void
7950ev_view_copy (EvView *ev_view)
7951{
7952 char *text;
7953
7954 if (!EV_IS_SELECTION (ev_view->document)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(ev_view->document)); GType __t = ((ev_selection_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
7955 return;
7956
7957 text = get_selected_text (ev_view);
7958 ev_view_clipboard_copy (ev_view, text);
7959 g_free (text);
7960}
7961
7962static void
7963ev_view_primary_get_cb (CtkClipboard *clipboard,
7964 CtkSelectionData *selection_data,
7965 guint info,
7966 gpointer data)
7967{
7968 EvView *ev_view = EV_VIEW (data)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((ev_view_get_type ()))))))
;
7969
7970 if (ev_view->link_selected) {
7971 ctk_selection_data_set_text (selection_data,
7972 ev_link_action_get_uri (ev_view->link_selected),
7973 -1);
7974 } else if (EV_IS_SELECTION (ev_view->document)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(ev_view->document)); GType __t = ((ev_selection_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
&&
7975 ev_view->selection_info.selections) {
7976 gchar *text;
7977
7978 text = get_selected_text (ev_view);
7979 if (text) {
7980 ctk_selection_data_set_text (selection_data, text, -1);
7981 g_free (text);
7982 }
7983 }
7984}
7985
7986static void
7987ev_view_primary_clear_cb (CtkClipboard *clipboard,
7988 gpointer data)
7989{
7990 EvView *view = EV_VIEW (data)((((EvView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((ev_view_get_type ()))))))
;
7991
7992 clear_selection (view);
7993 clear_link_selected (view);
7994}
7995
7996static void
7997ev_view_update_primary_selection (EvView *ev_view)
7998{
7999 CtkClipboard *clipboard;
8000
8001 clipboard = ctk_widget_get_clipboard (CTK_WIDGET (ev_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((ev_view)), ((ctk_widget_get_type ()))))))
,
8002 CDK_SELECTION_PRIMARY((CdkAtom)((gpointer) (gulong) (1))));
8003
8004 if (ev_view->selection_info.selections || ev_view->link_selected) {
8005 CtkTargetList *target_list;
8006 CtkTargetEntry *targets;
8007 int n_targets;
8008
8009 target_list = ctk_target_list_new (NULL((void*)0), 0);
8010 ctk_target_list_add_text_targets (target_list, 0);
8011 targets = ctk_target_table_new_from_list (target_list, &n_targets);
8012 ctk_target_list_unref (target_list);
8013
8014 if (!ctk_clipboard_set_with_owner (clipboard,
8015 targets, n_targets,
8016 ev_view_primary_get_cb,
8017 ev_view_primary_clear_cb,
8018 G_OBJECT (ev_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((ev_view)), (((GType) ((20) << (2))))))))
))
8019 ev_view_primary_clear_cb (clipboard, ev_view);
8020
8021 ctk_target_table_free (targets, n_targets);
8022 } else {
8023 if (ctk_clipboard_get_owner (clipboard) == G_OBJECT (ev_view)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((ev_view)), (((GType) ((20) << (2))))))))
)
8024 ctk_clipboard_clear (clipboard);
8025 }
8026}
8027
8028static void
8029clear_link_selected (EvView *view)
8030{
8031 if (view->link_selected) {
8032 g_object_unref (view->link_selected);
8033 view->link_selected = NULL((void*)0);
8034 }
8035}
8036
8037void
8038ev_view_copy_link_address (EvView *view,
8039 EvLinkAction *action)
8040{
8041 clear_link_selected (view);
8042
8043 ev_view_clipboard_copy (view, ev_link_action_get_uri (action));
8044
8045 view->link_selected = g_object_ref (action)((__typeof__ (action)) (g_object_ref) (action));
8046 ev_view_update_primary_selection (view);
8047}
8048
8049/*** Cursor operations ***/
8050static void
8051ev_view_set_cursor (EvView *view, EvViewCursor new_cursor)
8052{
8053 CdkDisplay *display;
8054 CdkCursor *cursor = NULL((void*)0);
8055 CtkWidget *widget;
8056 CdkWindow *bin_window;
8057
8058 if (view->cursor == new_cursor) {
8059 return;
8060 }
8061
8062 view->cursor = new_cursor;
8063
8064 bin_window = ctk_widget_get_window (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
8065 widget = ctk_widget_get_toplevel (CTK_WIDGET (view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((view)), ((ctk_widget_get_type ()))))))
);
8066 display = ctk_widget_get_display (widget);
8067 cursor = ev_view_cursor_new (display, new_cursor);
8068 cdk_window_set_cursor (bin_window, cursor);
8069 cdk_display_flush (display);
8070 if (cursor)
8071 g_object_unref (cursor);
8072}
8073
8074void
8075ev_view_hide_cursor (EvView *view)
8076{
8077 ev_view_set_cursor (view, EV_VIEW_CURSOR_HIDDEN);
8078}
8079
8080void
8081ev_view_show_cursor (EvView *view)
8082{
8083 ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
8084}
8085
8086gboolean
8087ev_view_next_page (EvView *view)
8088{
8089 gint next_page;
8090
8091 g_return_val_if_fail (EV_IS_VIEW (view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ev_view_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("LectorView", ((const char*
) (__func__)), "EV_IS_VIEW (view)"); return ((0)); } } while (
0)
;
8092
8093 next_page = go_to_next_page (view, view->current_page);
8094 if (next_page == -1)
8095 return FALSE(0);
8096
8097 ev_document_model_set_page (view->model, next_page);
8098
8099 return TRUE(!(0));
8100}
8101
8102gboolean
8103ev_view_previous_page (EvView *view)
8104{
8105 gint prev_page;
8106
8107 g_return_val_if_fail (EV_IS_VIEW (view), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((view)); GType __t = ((ev_view_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("LectorView", ((const char*
) (__func__)), "EV_IS_VIEW (view)"); return ((0)); } } while (
0)
;
8108
8109 prev_page = go_to_previous_page (view, view->current_page);
8110 if (prev_page == -1)
8111 return FALSE(0);
8112
8113 ev_document_model_set_page (view->model, prev_page);
8114
8115 return TRUE(!(0));
8116}
8117
8118/**
8119 * ev_view_disconnect_handlers
8120 * @view: #EvView instance
8121 *
8122 * Disconnect all signal handlers from the model, to ensure error free operation of the webview,
8123 * we have an equivalent function for the webview.
8124 */
8125void
8126ev_view_disconnect_handlers(EvView *view)
8127{
8128 g_signal_handlers_disconnect_by_func(view->model,g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_rotation_changed_cb))), (view))
8129 G_CALLBACK (ev_view_rotation_changed_cb),g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_rotation_changed_cb))), (view))
8130 view)g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_rotation_changed_cb))), (view))
;
8131 g_signal_handlers_disconnect_by_func(view->model,g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_inverted_colors_changed_cb))), (view
))
8132 G_CALLBACK (ev_view_inverted_colors_changed_cb),g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_inverted_colors_changed_cb))), (view
))
8133 view)g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_inverted_colors_changed_cb))), (view
))
;
8134 g_signal_handlers_disconnect_by_func(view->model,g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_sizing_mode_changed_cb))), (view))
8135 G_CALLBACK (ev_view_sizing_mode_changed_cb),g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_sizing_mode_changed_cb))), (view))
8136 view)g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_sizing_mode_changed_cb))), (view))
;
8137 g_signal_handlers_disconnect_by_func(view->model,g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_page_layout_changed_cb))), (view))
8138 G_CALLBACK (ev_view_page_layout_changed_cb),g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_page_layout_changed_cb))), (view))
8139 view)g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_page_layout_changed_cb))), (view))
;
8140 g_signal_handlers_disconnect_by_func(view->model,g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_scale_changed_cb))), (view))
8141 G_CALLBACK (ev_view_scale_changed_cb),g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_scale_changed_cb))), (view))
8142 view)g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_scale_changed_cb))), (view))
;
8143 g_signal_handlers_disconnect_by_func(view->model,g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_continuous_changed_cb))), (view))
8144 G_CALLBACK (ev_view_continuous_changed_cb),g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_continuous_changed_cb))), (view))
8145 view)g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_continuous_changed_cb))), (view))
;
8146 g_signal_handlers_disconnect_by_func(view->model,g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_fullscreen_changed_cb))), (view))
8147 G_CALLBACK (ev_view_fullscreen_changed_cb),g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_fullscreen_changed_cb))), (view))
8148 view)g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_fullscreen_changed_cb))), (view))
;
8149 g_signal_handlers_disconnect_by_func(view->model,g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_page_changed_cb))), (view))
8150 G_CALLBACK (ev_view_page_changed_cb),g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_page_changed_cb))), (view))
8151 view)g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_page_changed_cb))), (view))
;
8152 g_signal_handlers_disconnect_by_func(view->model,g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_document_changed_cb))), (view))
8153 G_CALLBACK (ev_view_document_changed_cb),g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_document_changed_cb))), (view))
8154 view)g_signal_handlers_disconnect_matched ((view->model), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (ev_view_document_changed_cb))), (view))
;
8155}