1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2016 Salvatore De Paolis & the Claws Mail Team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #  include "config.h"
21 #include "claws-features.h"
22 #endif
23 
24 #include <glib.h>
25 #include <glib/gi18n.h>
26 
27 #include "poppler_viewer.h"
28 #include "printing.h"
29 #include "prefs_common.h"
30 #include "gtk/gtkutils.h"
31 #include "gtk/inputdialog.h"
32 #include "mimeview.h"
33 #include "summaryview.h"
34 #include "file-utils.h"
35 #ifndef POPPLER_WITH_GDK
36 #include "stdbool.h"
37 #endif
38 
39 static FileType pdf_viewer_mimepart_get_type(MimeInfo *partinfo);
40 static MimeViewerFactory pdf_viewer_factory;
41 
42 static void pdf_viewer_show_mimepart(MimeViewer *_viewer, const gchar *infile,
43 				MimeInfo *partinfo);
44 
45 static MimeViewer *pdf_viewer_create(void);
46 static void pdf_viewer_clear(MimeViewer *_viewer);
47 static void pdf_viewer_destroy(MimeViewer *_viewer);
48 static void pdf_viewer_update(MimeViewer *_viewer, gboolean reload_file, int page_num);
49 
50 static GtkWidget *pdf_viewer_get_widget(MimeViewer *_viewer);
51 
52 static void pdf_viewer_hide_index_pane(PdfViewer *viewer);
53 static void pdf_viewer_set_index_button_sensitive(PdfViewer *viewer);
54 static void pdf_viewer_scroll_to(PdfViewer *viewer, gfloat x, gfloat y);
55 
56 static void search_matches_free(PdfViewer *viewer);
57 static gboolean	pdf_viewer_text_search(MimeViewer *_viewer, gboolean backward,
58 				     const gchar *str, gboolean case_sens);
59 static void pdf_viewer_render_selection(PdfViewer *viewer, PopplerRectangle *rect, PageResult *page_results);
60 static void pdf_viewer_render_page(PopplerPage *page, GtkWidget *view, double width, double height, double zoom, gint rotate);
61 
62 static char * pdf_viewer_get_document_format_data(GTime utime);
63 static void pdf_viewer_get_document_index(PdfViewer *viewer, PopplerIndexIter *index_iter, GtkTreeIter *parentiter);
64 static void pdf_viewer_index_row_activated(GtkTreeView		*tree_view,
65 				   	GtkTreePath		*path,
66 				   	GtkTreeViewColumn	*column,
67 				   	gpointer		 data);
68 
69 static GtkTable * pdf_viewer_fill_info_table(PdfViewer *viewer);
70 
71 /* Callbacks */
72 static void pdf_viewer_move_events_cb(GtkWidget *widget, GdkEventMotion *event, PdfViewer *viewer);
73 static void pdf_viewer_button_press_events_cb(GtkWidget *widget, GdkEventButton *event, PdfViewer *viewer);
74 static void pdf_viewer_mouse_scroll_destroy_cb(GtkWidget *widget, GdkEventButton *event, PdfViewer *viewer);
75 static void pdf_viewer_button_first_page_cb(GtkButton *button, PdfViewer *viewer);
76 static void pdf_viewer_button_last_page_cb(GtkButton *button, PdfViewer *viewer);
77 static void pdf_viewer_button_zoom_in_cb(GtkButton *button, PdfViewer *viewer);
78 static void pdf_viewer_button_zoom_out_cb(GtkButton *button, PdfViewer *viewer);
79 static void pdf_viewer_button_zoom_fit_cb(GtkButton *button, PdfViewer *viewer);
80 static void pdf_viewer_button_zoom_width_cb(GtkButton *button, PdfViewer *viewer);
81 static void pdf_viewer_button_rotate_right_cb(GtkButton *button, PdfViewer *viewer);
82 static void pdf_viewer_button_rotate_left_cb(GtkButton *button, PdfViewer *viewer);
83 static void pdf_viewer_spin_change_page_cb(GtkSpinButton *button, PdfViewer *viewer);
84 static void pdf_viewer_spin_zoom_scroll_cb(GtkSpinButton *button, PdfViewer *viewer);
85 /* Show/Hide the index pane */
86 static void pdf_viewer_show_document_index_cb(GtkToggleButton *button, PdfViewer *viewer);
87 static void pdf_viewer_button_print_cb(GtkButton *button, PdfViewer *viewer);
88 static void pdf_viewer_button_document_info_cb(GtkButton *button, PdfViewer *viewer);
89 
90 static void pdf_viewer_show_controls(PdfViewer *viewer, gboolean show);
91 static gboolean pdf_viewer_scroll_page(MimeViewer *_viewer, gboolean up);
92 static void pdf_viewer_scroll_one_line(MimeViewer *_viewer, gboolean up);
93 
94 /** Claws Mail Plugin functions */
95 gint plugin_init(gchar **error);
96 const gchar *plugin_name(void);
97 const gchar *plugin_desc(void);
98 const gchar *plugin_type(void);
99 const gchar *plugin_licence(void);
100 const gchar *plugin_version(void);
101 struct PluginFeature *plugin_provides(void);
102 
103 #ifndef POPPLER_WITH_GDK
104 static void
copy_cairo_surface_to_pixbuf(cairo_surface_t * surface,GdkPixbuf * pixbuf)105 copy_cairo_surface_to_pixbuf (cairo_surface_t *surface,
106 			      GdkPixbuf       *pixbuf)
107 {
108 	int cairo_width, cairo_height, cairo_rowstride;
109 	unsigned char *pixbuf_data, *dst, *cairo_data;
110 	int pixbuf_rowstride, pixbuf_n_channels;
111 	unsigned int *src;
112 	int x, y;
113 
114 	cairo_width = cairo_image_surface_get_width (surface);
115 	cairo_height = cairo_image_surface_get_height (surface);
116 	cairo_rowstride = cairo_image_surface_get_stride (surface);
117 	cairo_data = cairo_image_surface_get_data (surface);
118 
119 	pixbuf_data = gdk_pixbuf_get_pixels (pixbuf);
120 	pixbuf_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
121 	pixbuf_n_channels = gdk_pixbuf_get_n_channels (pixbuf);
122 
123 	if (cairo_width > gdk_pixbuf_get_width (pixbuf))
124 		cairo_width = gdk_pixbuf_get_width (pixbuf);
125 	if (cairo_height > gdk_pixbuf_get_height (pixbuf))
126 		cairo_height = gdk_pixbuf_get_height (pixbuf);
127 	for (y = 0; y < cairo_height; y++) {
128 		src = (unsigned int *) (cairo_data + y * cairo_rowstride);
129 		dst = pixbuf_data + y * pixbuf_rowstride;
130 		for (x = 0; x < cairo_width; x++) {
131 			dst[0] = (*src >> 16) & 0xff;
132 			dst[1] = (*src >> 8) & 0xff;
133 			dst[2] = (*src >> 0) & 0xff;
134 			if (pixbuf_n_channels == 4)
135 				dst[3] = (*src >> 24) & 0xff;
136 			dst += pixbuf_n_channels;
137 			src++;
138 		}
139 	}
140 }
141 static void
_poppler_page_render_to_pixbuf(PopplerPage * page,int src_x,int src_y,int src_width,int src_height,double scale,int rotation,gboolean printing,GdkPixbuf * pixbuf)142 _poppler_page_render_to_pixbuf (PopplerPage *page,
143 				int src_x, int src_y,
144 				int src_width, int src_height,
145 				double scale,
146 				int rotation,
147 				gboolean printing,
148 				GdkPixbuf *pixbuf)
149 {
150 	cairo_t *cr;
151 	cairo_surface_t *surface;
152 
153 	surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
154 					src_width, src_height);
155 	cr = cairo_create (surface);
156 	cairo_save (cr);
157 	switch (rotation) {
158 	case 90:
159 		cairo_translate (cr, src_x + src_width, -src_y);
160 		break;
161 	case 180:
162 		cairo_translate (cr, src_x + src_width, src_y + src_height);
163 		break;
164 	case 270:
165 		cairo_translate (cr, -src_x, src_y + src_height);
166 		break;
167 	default:
168 		cairo_translate (cr, -src_x, -src_y);
169 	}
170 
171 	if (scale != 1.0)
172 		cairo_scale (cr, scale, scale);
173 
174 	if (rotation != 0)
175 		cairo_rotate (cr, rotation * G_PI / 180.0);
176 
177 	if (printing)
178 		poppler_page_render_for_printing (page, cr);
179 	else
180 		poppler_page_render (page, cr);
181 	cairo_restore (cr);
182 
183 	cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER);
184 	cairo_set_source_rgb (cr, 1., 1., 1.);
185 	cairo_paint (cr);
186 
187 	cairo_destroy (cr);
188 
189 	copy_cairo_surface_to_pixbuf (surface, pixbuf);
190 	cairo_surface_destroy (surface);
191 }
192 
193 /**
194  * poppler_page_render_to_pixbuf:
195  * @page: the page to render from
196  * @src_x: x coordinate of upper left corner
197  * @src_y: y coordinate of upper left corner
198  * @src_width: width of rectangle to render
199  * @src_height: height of rectangle to render
200  * @scale: scale specified as pixels per point
201  * @rotation: rotate the document by the specified degree
202  * @pixbuf: pixbuf to render into
203  *
204  * First scale the document to match the specified pixels per point,
205  * then render the rectangle given by the upper left corner at
206  * (src_x, src_y) and src_width and src_height.
207  * This function is for rendering a page that will be displayed.
208  * If you want to render a page that will be printed use
209  * poppler_page_render_to_pixbuf_for_printing() instead
210  *
211  * Deprecated: 0.16
212  **/
213 static void
poppler_page_render_to_pixbuf(PopplerPage * page,int src_x,int src_y,int src_width,int src_height,double scale,int rotation,GdkPixbuf * pixbuf)214 poppler_page_render_to_pixbuf (PopplerPage *page,
215 			       int src_x, int src_y,
216 			       int src_width, int src_height,
217 			       double scale,
218 			       int rotation,
219 			       GdkPixbuf *pixbuf)
220 {
221 	g_return_if_fail (POPPLER_IS_PAGE (page));
222 	g_return_if_fail (scale > 0.0);
223 	g_return_if_fail (pixbuf != NULL);
224 
225 	_poppler_page_render_to_pixbuf (page, src_x, src_y,
226 				  src_width, src_height,
227 				  scale, rotation,
228 				  FALSE,
229 				  pixbuf);
230 }
231 #endif
pdf_viewer_get_widget(MimeViewer * _viewer)232 static GtkWidget *pdf_viewer_get_widget(MimeViewer *_viewer)
233 {
234 	PdfViewer *viewer = (PdfViewer *) _viewer;
235 	debug_print("pdf_viewer_get_widget: %p\n", viewer->vbox);
236 
237 	return GTK_WIDGET(viewer->vbox);
238 }
239 /** Hide the index panel */
pdf_viewer_hide_index_pane(PdfViewer * viewer)240 static void pdf_viewer_hide_index_pane(PdfViewer *viewer)
241 {
242 	if (viewer->pdf_index) {
243 		poppler_index_iter_free(viewer->pdf_index);
244 		viewer->pdf_index = NULL;
245 		gtk_widget_hide(GTK_WIDGET(viewer->frame_index));
246 	}
247 }
248 
search_matches_free(PdfViewer * viewer)249 static void search_matches_free(PdfViewer *viewer)
250 {
251 	GList *cur;
252 	for(cur = viewer->text_found; cur; cur = cur->next) {
253 		PageResult *res = (PageResult *)cur->data;
254 		g_list_free(res->results);
255 		g_free(res);
256 	}
257 	g_list_free(viewer->text_found);
258 	viewer->text_found = NULL;
259 	g_free(viewer->last_search);
260 	viewer->last_search = NULL;
261 	if (viewer->last_rect && viewer->last_page_result) {
262 		viewer->last_rect = NULL;
263 		viewer->last_page_result = NULL;
264 		pdf_viewer_update((MimeViewer *)viewer,
265 			FALSE,
266 			gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer->cur_page)));
267 	}
268 }
269 
pdf_viewer_scroll_to(PdfViewer * viewer,gfloat x,gfloat y)270 static void pdf_viewer_scroll_to(PdfViewer *viewer, gfloat x, gfloat y)
271 {
272 	GtkAdjustment *vadj;
273 	GtkAdjustment *hadj;
274 	vadj = gtk_scrolled_window_get_vadjustment(
275 		GTK_SCROLLED_WINDOW(viewer->scrollwin));
276 
277 	if (y < gtk_adjustment_get_value(vadj)) {
278 		gtk_adjustment_set_value(vadj, y);
279 	}
280 	else {
281 		while(y > gtk_adjustment_get_value(vadj) + gtk_adjustment_get_page_size(vadj)) {
282 			gtk_adjustment_set_value(vadj,
283 					gtk_adjustment_get_value(vadj) + gtk_adjustment_get_page_size(vadj));
284 		}
285 	}
286 
287 	hadj = gtk_scrolled_window_get_hadjustment(
288 		GTK_SCROLLED_WINDOW(viewer->scrollwin));
289 
290 	if (x < gtk_adjustment_get_value(hadj)) {
291 		gtk_adjustment_set_value(hadj, x);
292 	}
293 	else {
294 		while(x > gtk_adjustment_get_value(hadj) + gtk_adjustment_get_page_size(hadj)) {
295 			gtk_adjustment_set_value(hadj,
296 					gtk_adjustment_get_value(hadj) + gtk_adjustment_get_page_size(hadj));
297 		}
298 	}
299 
300 	g_signal_emit_by_name(G_OBJECT(hadj), "value-changed", 0);
301 	g_signal_emit_by_name(G_OBJECT(vadj), "value-changed", 0);
302 }
pdf_viewer_render_page(PopplerPage * page,GtkWidget * view,double width,double height,double zoom,gint rotate)303 static void pdf_viewer_render_page(PopplerPage *page, GtkWidget *view, double width,
304 				   double height, double zoom, gint rotate)
305 {
306 	GdkPixbuf *pb;
307 
308 	debug_print("width: %f\n", width);
309 	pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
310 				FALSE, 8,
311 				(int)(width * zoom),
312 				(int)(height * zoom));
313 
314 			poppler_page_render_to_pixbuf(page, 0, 0,
315 				(int)(width * zoom),
316 				(int)(height * zoom),
317 				zoom, rotate, pb);
318 
319 			gtk_image_set_from_pixbuf(GTK_IMAGE(view), pb);
320 			g_object_unref(G_OBJECT(pb));
321 }
pdf_viewer_render_selection(PdfViewer * viewer,PopplerRectangle * rect,PageResult * page_results)322 static void pdf_viewer_render_selection(PdfViewer *viewer, PopplerRectangle *rect, PageResult *page_results)
323 {
324 	gint selw, selh;
325 	double width_points, height_points;
326 	gint width, height;
327 	GdkPixbuf *sel_pb, *page_pb;
328 	gfloat x1, x2, y1, y2;
329 
330 
331 	gint cur_page_num =
332 		gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer->cur_page));
333 
334 	viewer->last_match = viewer->res_cnt;
335 
336 	viewer->last_rect = NULL;
337 	viewer->last_page_result = NULL;
338 	if (cur_page_num != page_results->page_num) {
339 		/* we changed page. update the view */
340 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer->cur_page),
341 	(gdouble) page_results->page_num);
342 	}
343 
344 	viewer->last_rect = rect;
345 	viewer->last_page_result = page_results;
346 
347 	GTK_EVENTS_FLUSH();
348 
349 	poppler_page_get_size(POPPLER_PAGE(viewer->pdf_page), &width_points, &height_points);
350 	width = (int)((width_points * viewer->zoom) + 0.5);
351 	height = (int)((height_points * viewer->zoom) + 0.5);
352 
353 	if (viewer->rotate == 90) {
354 		x1 = MIN(rect->y1,rect->y2) * viewer->zoom;
355 		x2 = MAX(rect->y1,rect->y2) * viewer->zoom;
356 		y1 = MAX(rect->x1,rect->x2) * viewer->zoom;
357 		y2 = MIN(rect->x1,rect->x2) * viewer->zoom;
358 		selw = (x2 - x1);
359 		selh = (y1 - y2);
360 
361 	} else if (viewer->rotate == 180) {
362 		x1 = width - rect->x2 * viewer->zoom;
363 		x2 = width - rect->x1 * viewer->zoom;
364 		y1 = height - rect->y2 * viewer->zoom;
365 		y2 = height - rect->y1 * viewer->zoom;
366 		selw = (x2 - x1);
367 		selh = (y2 - y1);
368 		y1 = height - y1;
369 		y2 = height - y2;
370 
371 	} else if (viewer->rotate == 270) {
372 		x1 = height - MAX(rect->y1,rect->y2) * viewer->zoom;
373 		x2 = height - MIN(rect->y1,rect->y2) * viewer->zoom;
374 		y1 = width - MIN(rect->x1,rect->x2) * viewer->zoom;
375 		y2 = width - MAX(rect->x1,rect->x2) * viewer->zoom;
376 		selw = (x2 - x1);
377 		selh = (y1 - y2);
378 	} else {
379 		x1 = rect->x1 * viewer->zoom;
380 		x2 = rect->x2 * viewer->zoom;
381 		y1 = rect->y1 * viewer->zoom;
382 		y2 = rect->y2 * viewer->zoom;
383 		selw = (x2 - x1);
384 		selh = (y2 - y1);
385 		y1 = height - y1;
386 		y2 = height - y2;
387 	}
388 
389 	sel_pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
390 							selw, selh);
391 
392 	gdk_pixbuf_fill(sel_pb, SELECTION_COLOR);
393 
394 	page_pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
395 					FALSE, 8,
396 				(int)(viewer->width * viewer->zoom),
397 				(int)(viewer->height * viewer->zoom));
398 
399 	poppler_page_render_to_pixbuf(viewer->pdf_page,
400 					0,
401 					0,
402 				(int)(viewer->width * viewer->zoom),
403 				(int)(viewer->height * viewer->zoom),
404 					viewer->zoom,
405 					viewer->rotate,
406 					page_pb);
407 
408 	gdk_pixbuf_composite(sel_pb, page_pb,
409 					x1, y2, selw, selh, 0, 0,
410 					viewer->zoom, viewer->zoom,
411 					GDK_INTERP_BILINEAR, ALPHA_CHANNEL);
412 
413 	gtk_image_set_from_pixbuf(GTK_IMAGE(viewer->pdf_view), page_pb);
414 
415 	pdf_viewer_scroll_to(viewer, MIN(x1,x2), MIN(y1,y2));
416 
417 	g_object_unref(G_OBJECT(sel_pb));
418 	g_object_unref(G_OBJECT(page_pb));
419 
420 }
421 
pdf_viewer_text_search(MimeViewer * _viewer,gboolean backward,const gchar * str,gboolean case_sens)422 static gboolean	pdf_viewer_text_search(MimeViewer *_viewer, gboolean backward,
423 				     const gchar *str, gboolean case_sens)
424 {
425 	PdfViewer *viewer = (PdfViewer *)_viewer;
426 	GList *all_pages_results, *cur_page_results;
427 	viewer->res_cnt = 0;
428 
429 	debug_print("pdf_viewer_text_search: %s\n", str);
430 	main_window_cursor_wait(mainwindow_get_mainwindow());
431 
432 	if (viewer->last_search && strcmp(str, viewer->last_search)) {
433 		search_matches_free(viewer);
434 		viewer->last_match = -1;
435 		viewer->num_matches = 0;
436 	} else if (!viewer->last_search) {
437 		viewer->last_match = -1;
438 		viewer->num_matches = 0;
439 	}
440 	/* It's a new search, build list of matches
441 	 * across all pages */
442 	if (viewer->last_match == -1) {
443 		gint i;
444 
445 		for(i = 1; i <= viewer->num_pages; i++) {
446 
447 			PopplerPage *pdf_page = poppler_document_get_page(viewer->pdf_doc, i - 1);
448 			viewer->page_results = poppler_page_find_text(pdf_page, str);
449 
450 			if (viewer->page_results != NULL) {
451 				debug_print("page_results %p\n", viewer->page_results);
452 				/* store results for this page */
453 				guint num_res = 0;
454 				PageResult *res = g_new0(PageResult, 1);
455 				res->results = viewer->page_results;
456 				res->page_num = i;
457 				/* found text, prepend this page(faster than append) */
458 				viewer->text_found = g_list_prepend(viewer->text_found, res);
459 				num_res = g_list_length(viewer->page_results);
460 				debug_print("%d results on page %d\n", num_res, i);
461 				viewer->num_matches += num_res;
462 			}
463 			g_object_unref(G_OBJECT(pdf_page));
464 		}
465 
466 		if (viewer->text_found == NULL) {
467 			main_window_cursor_normal(mainwindow_get_mainwindow());
468 			return FALSE;
469 		}
470 		/* put back the list in the correct order */
471 		viewer->text_found = g_list_reverse(viewer->text_found);
472 	}
473 
474 	if (!viewer->text_found) {
475 		main_window_cursor_normal(mainwindow_get_mainwindow());
476 		return FALSE;
477 	} else {
478 		viewer->last_search = g_strdup(str);
479 	}
480 
481 	if (backward) {
482 		/* if backward, we have to initialize stuff to search
483 		 * from the end */
484 		viewer->res_cnt = viewer->num_matches-1;
485 		if (viewer->last_match == -1) {
486 			viewer->last_match = viewer->num_matches+1;
487 		}
488 		all_pages_results = g_list_last(viewer->text_found);
489 	}
490 	else {
491 		all_pages_results = viewer->text_found;
492 	}
493 
494 	for(; all_pages_results; all_pages_results = (backward?all_pages_results->prev:all_pages_results->next)) {
495 
496 		PageResult * page_results = (PageResult *)all_pages_results->data;
497 
498 		if (backward) {
499 			cur_page_results = g_list_last(page_results->results);
500 		}
501 		else {
502 			cur_page_results = page_results->results;
503 		}
504 
505 		for(; cur_page_results; cur_page_results = (backward?cur_page_results->prev:cur_page_results->next)) {
506 
507 			gboolean valid = FALSE;
508 			/* first valid result is the last+1 if searching
509 			 * forward, last-1 if searching backward */
510 			if (backward) {
511 				valid = (viewer->res_cnt < viewer->last_match);
512 			}
513 			else {
514 				valid = (viewer->res_cnt > viewer->last_match);
515 			}
516 			if (valid) {
517 				pdf_viewer_render_selection(viewer,
518 					(PopplerRectangle *)cur_page_results->data,
519 						page_results);
520 				main_window_cursor_normal(mainwindow_get_mainwindow());
521 				return TRUE;
522 			}
523 
524 			if (backward) {
525 				viewer->res_cnt--;
526 			}
527 			else {
528 				viewer->res_cnt++;
529 			}
530 		}
531 	}
532 	main_window_cursor_normal(mainwindow_get_mainwindow());
533 	search_matches_free(viewer);
534 	return FALSE;
535 }
536 
pdf_viewer_get_document_index(PdfViewer * viewer,PopplerIndexIter * index_iter,GtkTreeIter * parentiter)537 static void pdf_viewer_get_document_index(PdfViewer *viewer, PopplerIndexIter *index_iter, GtkTreeIter *parentiter)
538 {
539 	PopplerAction *action;
540 	PopplerIndexIter *child;
541 	GtkTreeIter childiter;
542 
543 	debug_print("get document index\n");
544 	do	{
545 		gint page_num = 0;
546 
547 		action = poppler_index_iter_get_action(index_iter);
548 
549 		if (action->type != POPPLER_ACTION_GOTO_DEST) {
550 			poppler_action_free(action);
551 			continue;
552 		}
553 
554 		if (action->goto_dest.dest->type == POPPLER_DEST_XYZ || action->goto_dest.dest->type == POPPLER_DEST_FITH) {
555 			page_num = action->goto_dest.dest->page_num;
556 		}
557 #ifdef HAVE_POPPLER_DEST_NAMED
558 		else if (action->goto_dest.dest->type == POPPLER_DEST_NAMED) {
559 			PopplerDest *dest = poppler_document_find_dest(
560 					viewer->pdf_doc, action->goto_dest.dest->named_dest);
561 			if (dest->type != POPPLER_DEST_XYZ) {
562 				g_warning("couldn't figure out link");
563 				poppler_dest_free(dest);
564 				continue;
565 			}
566 			page_num = dest->page_num;
567 			poppler_dest_free(dest);
568 		}
569 #endif
570 		else {
571 #ifdef HAVE_POPPLER_DEST_NAMED
572 			g_warning("unhandled link type %d. please contact developers", action->goto_dest.dest->type);
573 #else
574 			g_warning("unhandled link type %d. please upgrade libpoppler-glib to 0.5.4", action->goto_dest.dest->type);
575 #endif
576 			continue;
577 		}
578 		gtk_tree_store_append(GTK_TREE_STORE(viewer->index_model), &childiter, parentiter);
579 		gtk_tree_store_set(GTK_TREE_STORE(viewer->index_model), &childiter,
580 						INDEX_NAME, action->named.title,
581 						INDEX_PAGE, page_num,
582 						INDEX_TOP, action->goto_dest.dest->top,
583 						-1);
584 		poppler_action_free(action);
585 		child = poppler_index_iter_get_child(index_iter);
586 		if (child) {
587 			pdf_viewer_get_document_index(viewer, child, &childiter);
588 			poppler_index_iter_free(child);
589 		}
590 	}
591 	while(poppler_index_iter_next(index_iter));
592 }
593 
pdf_viewer_index_row_activated(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * column,gpointer data)594 static void pdf_viewer_index_row_activated(GtkTreeView		*tree_view,
595 				   	GtkTreePath		*path,
596 				   	GtkTreeViewColumn	*column,
597 				   	gpointer		 data)
598 {
599 	GtkTreeIter iter;
600 	GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
601 	PdfViewer *viewer = (PdfViewer *)data;
602 	gint page_num = 0;
603 
604 	debug_print("index_row_activated\n");
605 	if (!gtk_tree_model_get_iter(model, &iter, path)) return;
606 
607 	gtk_tree_model_get(model, &iter,
608 			   INDEX_PAGE, &page_num,
609 			   -1);
610 
611 	if (page_num > 0) {
612 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer->cur_page),(gdouble)page_num);
613 		debug_print("Page num: %d\n", page_num);
614 	}
615 	GTK_EVENTS_FLUSH();
616 }
617 
618 /** Disable the index button if the document doesn't have an index */
pdf_viewer_set_index_button_sensitive(PdfViewer * viewer)619 static void pdf_viewer_set_index_button_sensitive(PdfViewer *viewer)
620 {
621 	viewer->pdf_index  = poppler_index_iter_new(viewer->pdf_doc);
622 	if (viewer->pdf_index) {
623 		if (!gtk_widget_is_sensitive(viewer->doc_index)) {
624 			gtk_widget_set_sensitive(viewer->doc_index, TRUE);
625 		}
626 	}
627 	else {
628 		gtk_widget_set_sensitive(viewer->doc_index, FALSE);
629 	}
630 
631     poppler_index_iter_free(viewer->pdf_index);
632     viewer->pdf_index = NULL;
633 }
634 
pdf_viewer_get_document_format_data(GTime utime)635 static char * pdf_viewer_get_document_format_data(GTime utime)
636 {
637 	time_t time = (time_t) utime;
638 	struct tm t;
639 	char s[256];
640 	const char *fmt_hack = "%c";
641 	size_t len;
642 
643 	if (time == 0 || !localtime_r(&time, &t)) return NULL;
644 
645 	len = strftime(s, sizeof(s), fmt_hack, &t);
646 
647 	if (len == 0 || s[0] == '\0') return NULL;
648 
649 	return g_locale_to_utf8(s, -1, NULL, NULL, NULL);
650 }
651 
652 #define ADD_TO_TABLE(LABEL, VALUE) \
653 	label = gtk_label_new(LABEL); \
654 	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); \
655 	gtk_misc_set_padding(GTK_MISC(label), 4, 0); \
656 	gtk_table_attach(viewer->table_doc_info, label, 0, 1, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0); \
657 	\
658 	label = gtk_label_new(VALUE); \
659 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); \
660 	gtk_misc_set_padding(GTK_MISC(label), 4, 0); \
661 	gtk_table_attach(viewer->table_doc_info, label, 1, 2, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0); \
662 	row++;
663 
664 
pdf_viewer_fill_info_table(PdfViewer * viewer)665 static GtkTable * pdf_viewer_fill_info_table(PdfViewer *viewer)
666 {
667 	GtkWidget *label;
668 	const gchar *title, *format, *author, *subject, *keywords, *creator, *producer;
669 	gboolean linearized;
670 	gchar *tmp;
671 	gint row = 0;
672 
673 	GTime creation_date, mod_date;
674 
675 	PopplerPageLayout layout;
676 	PopplerPageMode mode;
677 	PopplerPermissions permissions;
678 	PopplerViewerPreferences view_prefs;
679 
680 	title = format = author = subject = keywords = creator = producer = tmp = 0;
681 
682 	g_object_get(viewer->pdf_doc,
683 				"title", &title,
684 				"format", &format,
685 				"author", &author,
686 				"subject", &subject,
687 				"keywords", &keywords,
688 				"creation-date", &creation_date,
689 				"permissions", &permissions,
690 				"mod-date", &mod_date,
691 				"creator", &creator,
692 				"producer", &producer,
693 				"linearized", &linearized,
694 				"page-mode", &mode,
695 				"page-layout", &layout,
696 				"viewer-preferences", &view_prefs,
697 				NULL);
698 
699 	viewer->table_doc_info = GTK_TABLE(gtk_table_new(13, 2, FALSE));
700 
701 	ADD_TO_TABLE(_("Filename:"), viewer->target_filename)
702 	ADD_TO_TABLE(_("Size:"), to_human_readable(viewer->to_load->length))
703 	ADD_TO_TABLE(NULL, NULL)
704 	ADD_TO_TABLE(_("Title:"), title)
705 	ADD_TO_TABLE(_("Subject:"), subject)
706 	ADD_TO_TABLE(_("Author:"), author)
707 	ADD_TO_TABLE(_("Keywords:"), keywords)
708 	ADD_TO_TABLE(_("Creator:"), creator)
709 	ADD_TO_TABLE(_("Producer:"), producer)
710 
711 	tmp = pdf_viewer_get_document_format_data(creation_date);
712 	ADD_TO_TABLE(_("Created:"), tmp)
713 	g_free(tmp);
714 
715 	tmp = pdf_viewer_get_document_format_data(mod_date);
716 	ADD_TO_TABLE(_("Modified:"), tmp)
717 	g_free(tmp);
718 
719 	ADD_TO_TABLE(_("Format:"), format)
720 	if (linearized) {
721 		ADD_TO_TABLE(_("Optimized:"), _("Yes"))
722 	}
723 	else {
724 		ADD_TO_TABLE(_("Optimized:"), _("No"))
725 	}
726 	//ADD_TO_TABLE(_("Page Mode:"), pdf_viewer_get_document_info_mode(mode))
727 	//ADD_TO_TABLE(_("Page Layout:"), pdf_viewer_get_document_info_layout(layout))
728 
729 	return(GtkTable *) viewer->table_doc_info;
730 }
731 #undef ADD_TO_TABLE
732 
pdf_viewer_mimepart_get_type(MimeInfo * partinfo)733 static FileType pdf_viewer_mimepart_get_type(MimeInfo *partinfo)
734 {
735 	gchar *content_type = NULL;
736 	FileType type = TYPE_UNKNOWN;
737 	debug_print("mimepart_get_type\n");
738 	if ((partinfo->type == MIMETYPE_APPLICATION) &&
739 	(!g_ascii_strcasecmp(partinfo->subtype, "octet-stream"))) {
740 
741 		const gchar *filename;
742 
743 		filename = procmime_mimeinfo_get_parameter(partinfo, "filename");
744 
745 			if (filename == NULL)
746 				filename = procmime_mimeinfo_get_parameter(partinfo, "name");
747 			if (filename != NULL)
748 				content_type = procmime_get_mime_type(filename);
749 	}
750 	else {
751 		content_type = procmime_get_content_type_str(partinfo->type, partinfo->subtype);
752 	}
753 
754 	if (content_type == NULL) type = TYPE_UNKNOWN;
755 	else if (!strcmp(content_type, "application/pdf")) type = TYPE_PDF;
756 	else if (!strcmp(content_type, "application/postscript")) type = TYPE_PS;
757 	else type = TYPE_UNKNOWN;
758 
759 	g_free(content_type);
760 	return type;
761 }
762 
763 /* Callbacks */
pdf_viewer_button_first_page_cb(GtkButton * button,PdfViewer * viewer)764 static void pdf_viewer_button_first_page_cb(GtkButton *button, PdfViewer *viewer)
765 {
766 
767 	gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->cur_page), GTK_SPIN_HOME, 1);
768 }
769 
pdf_viewer_button_prev_page_cb(GtkButton * button,PdfViewer * viewer)770 static void pdf_viewer_button_prev_page_cb(GtkButton *button, PdfViewer *viewer)
771 {
772 
773 	gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->cur_page), GTK_SPIN_STEP_BACKWARD, 1);
774 }
775 
pdf_viewer_button_next_page_cb(GtkButton * button,PdfViewer * viewer)776 static void pdf_viewer_button_next_page_cb(GtkButton *button, PdfViewer *viewer)
777 {
778 
779 	gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->cur_page), GTK_SPIN_STEP_FORWARD, 1);
780 }
781 
pdf_viewer_button_last_page_cb(GtkButton * button,PdfViewer * viewer)782 static void pdf_viewer_button_last_page_cb(GtkButton *button, PdfViewer *viewer)
783 {
784 
785 	gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->cur_page), GTK_SPIN_END, 1);
786 }
787 
pdf_viewer_spin_change_page_cb(GtkSpinButton * button,PdfViewer * viewer)788 static void pdf_viewer_spin_change_page_cb(GtkSpinButton *button, PdfViewer *viewer)
789 {
790 	pdf_viewer_update((MimeViewer *)viewer,
791 			FALSE,
792 			gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer->cur_page)));
793 }
794 
pdf_viewer_button_zoom_in_cb(GtkButton * button,PdfViewer * viewer)795 static void pdf_viewer_button_zoom_in_cb(GtkButton *button, PdfViewer *viewer)
796 {
797 
798 	gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->zoom_scroll), GTK_SPIN_STEP_FORWARD, ZOOM_FACTOR);
799 }
800 
pdf_viewer_spin_zoom_scroll_cb(GtkSpinButton * button,PdfViewer * viewer)801 static void pdf_viewer_spin_zoom_scroll_cb(GtkSpinButton *button, PdfViewer *viewer)
802 {
803 	viewer->zoom = gtk_spin_button_get_value(GTK_SPIN_BUTTON(viewer->zoom_scroll));
804 	pdf_viewer_update((MimeViewer *)viewer,
805 			FALSE,
806 			gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer->cur_page)));
807 }
808 
pdf_viewer_button_zoom_out_cb(GtkButton * button,PdfViewer * viewer)809 static void pdf_viewer_button_zoom_out_cb(GtkButton *button, PdfViewer *viewer)
810 {
811 
812 	gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->zoom_scroll), GTK_SPIN_STEP_BACKWARD, ZOOM_FACTOR);
813 
814 }
815 
pdf_viewer_button_press_events_cb(GtkWidget * widget,GdkEventButton * event,PdfViewer * viewer)816 static void pdf_viewer_button_press_events_cb(GtkWidget *widget, GdkEventButton *event, PdfViewer *viewer)
817 {
818 	gchar *uri;
819 	GdkWindow *gdkwin;
820 	#ifdef HAVE_POPPLER_DEST_NAMED
821 	PopplerDest *dest;
822 	#endif
823 	static GdkCursor *hand_cur = NULL;
824 
825 	if (!hand_cur) hand_cur = gdk_cursor_new(GDK_FLEUR);
826 
827 	/* Execute Poppler Links */
828 	if (event->button == 1 && viewer->in_link) {
829 		switch (viewer->link_action->type) {
830 		case POPPLER_ACTION_UNKNOWN:
831 			debug_print("action unknown\n");
832 			break;
833 		case POPPLER_ACTION_GOTO_DEST:
834 			if (viewer->link_action->goto_dest.dest->type == POPPLER_DEST_XYZ ||
835 					viewer->link_action->goto_dest.dest->type == POPPLER_DEST_FITH) {
836 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer->cur_page),
837 									  (gdouble)viewer->link_action->goto_dest.dest->page_num);
838 			}
839 		#ifdef HAVE_POPPLER_DEST_NAMED
840 			else if (viewer->link_action->goto_dest.dest->type == POPPLER_DEST_NAMED) {
841 				dest = poppler_document_find_dest(
842 					viewer->pdf_doc, viewer->link_action->goto_dest.dest->named_dest);
843 			if (dest->type != POPPLER_DEST_XYZ) {
844 				g_warning("couldn't figure out link");
845 				poppler_dest_free(dest);
846 				break;
847 			}
848 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer->cur_page),
849 									  (gdouble)dest->page_num);
850 			poppler_dest_free(dest);
851 		}
852 		#endif
853 			break;
854 		case POPPLER_ACTION_GOTO_REMOTE:
855 			#ifdef HAVE_POPPLER_DEST_NAMED
856 			dest = poppler_document_find_dest(
857 					viewer->pdf_doc, viewer->link_action->goto_remote.dest->named_dest);
858 			if (dest->type != POPPLER_DEST_XYZ) {
859 				g_warning ("couldn't figure out link");
860 				poppler_dest_free(dest);
861 				break;
862 			}
863 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer->cur_page),
864 									  (gdouble)dest->page_num);
865 			poppler_dest_free(dest);
866 			#endif
867 			break;
868 		case POPPLER_ACTION_LAUNCH:
869 			debug_print("action launch not yet implemented\n");
870 			break;
871 		case POPPLER_ACTION_URI:
872 			uri = g_strdup(viewer->link_action->uri.uri);
873 			if (!g_ascii_strncasecmp(uri, "mailto:", 7))
874 				compose_new(NULL, uri + 7, NULL);
875 			else
876 				open_uri(uri, prefs_common_get_uri_cmd());
877 			g_free(uri);
878 			break;
879 		case POPPLER_ACTION_NAMED:
880 			debug_print("action named not yet implemented\n");
881 			break;
882 		case POPPLER_ACTION_NONE:
883 			debug_print("action none does nothing, surprise!\n");
884 			break;
885 		case POPPLER_ACTION_MOVIE:
886 			debug_print("yoyoyo ;-) a movie?\n");
887 			break;
888 #if POPPLER_CHECK_VERSION(0,14,0)
889 		case POPPLER_ACTION_RENDITION:
890 			debug_print("yoyoyo ;-) multimedia?\n");
891 			break;
892 		case POPPLER_ACTION_OCG_STATE:
893 			debug_print("yoyoyo ;-) layer state?\n");
894 			break;
895 #if POPPLER_CHECK_VERSION(0,18,0)
896 		case POPPLER_ACTION_JAVASCRIPT:
897 			debug_print("yoyoyo ;-) javascript?\n");
898 			break;
899 #if POPPLER_CHECK_VERSION(0,90,0)
900 		case POPPLER_ACTION_RESET_FORM:
901 			debug_print("yoyoyo ;-) reset form?\n");
902 			break;
903 #endif /* 0.90 */
904 #endif /* 0.18 */
905 #endif /* 0.14 */
906 		}
907 		if (((MimeViewer *)viewer)->mimeview &&
908 			((MimeViewer *)viewer)->mimeview->messageview &&
909 			((MimeViewer *)viewer)->mimeview->messageview->window &&
910 			(gdkwin = gtk_widget_get_window(((MimeViewer *)viewer)->mimeview->messageview->window)) != NULL)
911 			gdk_window_set_cursor (gdkwin, NULL);
912 		else
913 			gdk_window_set_cursor (gtk_widget_get_window(mainwindow_get_mainwindow()->window), NULL);
914 	}
915 
916 	/* Init document to be scrolled with left mouse click */
917 	if (event->button == 1 && !viewer->in_link) {
918 		viewer->pdf_view_scroll = TRUE;
919 		if (((MimeViewer *)viewer)->mimeview &&
920 			((MimeViewer *)viewer)->mimeview->messageview &&
921 			((MimeViewer *)viewer)->mimeview->messageview->window &&
922 			(gdkwin = gtk_widget_get_window(((MimeViewer *)viewer)->mimeview->messageview->window)) != NULL)
923 			gdk_window_set_cursor (gdkwin, hand_cur);
924 		else
925 			gdk_window_set_cursor (gtk_widget_get_window(mainwindow_get_mainwindow()->window), hand_cur);
926 
927 		viewer->last_x = event->x;
928 		viewer->last_y = event->y;
929 		viewer->last_dir_x = 0;
930 		viewer->last_dir_y = 0;
931 	}
932 }
933 /* Set the normal cursor*/
pdf_viewer_mouse_scroll_destroy_cb(GtkWidget * widget,GdkEventButton * event,PdfViewer * viewer)934 static void pdf_viewer_mouse_scroll_destroy_cb(GtkWidget *widget, GdkEventButton *event, PdfViewer *viewer)
935 {
936 	GdkWindow *gdkwin;
937 
938 	if (event->button == 1) {
939 		viewer->pdf_view_scroll = FALSE;
940 		if (((MimeViewer *)viewer)->mimeview &&
941 			((MimeViewer *)viewer)->mimeview->messageview &&
942 			((MimeViewer *)viewer)->mimeview->messageview->window &&
943 			(gdkwin = gtk_widget_get_window(((MimeViewer *)viewer)->mimeview->messageview->window)) != NULL)
944 			gdk_window_set_cursor (gdkwin, NULL);
945 		else
946 			gdk_window_set_cursor (gtk_widget_get_window(mainwindow_get_mainwindow()->window), NULL);
947 	}
948 }
949 
pdf_viewer_move_events_cb(GtkWidget * widget,GdkEventMotion * event,PdfViewer * viewer)950 static void pdf_viewer_move_events_cb(GtkWidget *widget, GdkEventMotion *event, PdfViewer *viewer)
951 {
952 	GdkWindow *gdkwin;
953 
954 	/* Grab the document and scroll it with mouse */
955 	if (viewer->pdf_view_scroll) {
956 
957 		viewer->pdf_view_vadj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(viewer->scrollwin));
958 		viewer->pdf_view_hadj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(viewer->scrollwin));
959 
960 			if (event->x < viewer->last_x
961 					&& gtk_adjustment_get_value(viewer->pdf_view_hadj) < (gtk_adjustment_get_upper(viewer->pdf_view_hadj) - gtk_adjustment_get_page_size(viewer->pdf_view_hadj))) {
962 				if (viewer->last_dir_x == -1) {
963 					gtk_adjustment_set_value(viewer->pdf_view_hadj,
964 							gtk_adjustment_get_value(viewer->pdf_view_hadj)
965 							+ viewer->last_x
966 							- event->x);
967 					g_signal_emit_by_name(G_OBJECT(viewer->pdf_view_hadj),
968 								"value_changed", 0);
969 				}
970 				viewer->last_dir_x = -1;
971 			}
972 			else if (event->x > viewer->last_x
973 					&& gtk_adjustment_get_value(viewer->pdf_view_hadj) > 0.0)  {
974 				if (viewer->last_dir_x == +1) {
975 					gtk_adjustment_set_value(viewer->pdf_view_hadj,
976 							gtk_adjustment_get_value(viewer->pdf_view_hadj)
977 							+ viewer->last_x
978 							- event->x);
979 					g_signal_emit_by_name(G_OBJECT(viewer->pdf_view_hadj),
980 								"value_changed", 0);
981 				}
982 				viewer->last_dir_x = +1;
983 			}
984 
985 			if (event->y < viewer->last_y
986 					&& gtk_adjustment_get_value(viewer->pdf_view_vadj) < (gtk_adjustment_get_upper(viewer->pdf_view_vadj) - gtk_adjustment_get_page_size(viewer->pdf_view_vadj))) {
987 				if (viewer->last_dir_y == -1) {
988 					gtk_adjustment_set_value(viewer->pdf_view_vadj,
989 							gtk_adjustment_get_value(viewer->pdf_view_vadj)
990 							+ viewer->last_y
991 							- event->y);
992 					g_signal_emit_by_name(G_OBJECT(viewer->pdf_view_vadj),
993 								"value_changed", 0);
994 				}
995 				viewer->last_dir_y = -1;
996 			}
997 			else if (event->y > viewer->last_y
998 					&& gtk_adjustment_get_value(viewer->pdf_view_vadj) > 0.0)  {
999 				if (viewer->last_dir_y == +1) {
1000 					gtk_adjustment_set_value(viewer->pdf_view_vadj,
1001 							gtk_adjustment_get_value(viewer->pdf_view_vadj)
1002 							+ viewer->last_y
1003 							- event->y);
1004 					g_signal_emit_by_name(G_OBJECT(viewer->pdf_view_vadj),
1005 								"value_changed", 0);
1006 				}
1007 				viewer->last_dir_y = +1;
1008 			}
1009 			viewer->last_x = event->x;
1010 			viewer->last_y = event->y;
1011 			GTK_EVENTS_FLUSH();
1012 		}
1013 	else {
1014 	/* Link Mapping */
1015 	static GList *l;
1016 	static GdkCursor *link_cur = NULL;
1017 	static GtkRequisition size;
1018 	static gdouble x,y, x1, y1, x2, y2;
1019 	gboolean ccur;
1020 
1021 	viewer->pdf_view_vadj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(viewer->scrollwin));
1022 	viewer->pdf_view_hadj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(viewer->scrollwin));
1023 
1024 	if (!link_cur) link_cur = gdk_cursor_new(GDK_HAND2);
1025 
1026 	ccur = FALSE;
1027 	viewer->in_link = FALSE;
1028 	for (l = viewer->link_map; l; l = g_list_next (l)) {
1029 		gint upper;
1030 		PopplerLinkMapping *lmapping;
1031 		lmapping = (PopplerLinkMapping *)l->data;
1032 
1033 		x1 = lmapping->area.x1;
1034 		y1 = lmapping->area.y1;
1035 		x2 = lmapping->area.x2;
1036 		y2 = lmapping->area.y2;
1037 		gtk_widget_size_request(viewer->pdf_view, &size);
1038 
1039 		upper = gtk_adjustment_get_upper(viewer->pdf_view_hadj);
1040 		switch (viewer->rotate) {
1041 		case 0:
1042 		case 360:
1043 				if (size.width != upper)
1044 					x = (event->x - (upper - size.width) / 2) / viewer->zoom;
1045 				else
1046 					x = event->x / viewer->zoom;
1047 
1048 				y = (upper - event->y) / viewer->zoom;
1049 			break;
1050 		case 90:
1051 				if (size.width != upper)
1052 					y = (event->x - (upper - size.width) / 2) / viewer->zoom;
1053 				else
1054 					y = event->x / viewer->zoom;
1055 
1056 				x = (event->y) / viewer->zoom;
1057 			break;
1058 		case 180:
1059 				if (size.width != upper)
1060 					x = ((upper -  event->x) - ((upper - size.width) / 2)) / viewer->zoom;
1061 				else
1062 					x =  ((upper -  event->x) - (upper - size.width)) / viewer->zoom;
1063 
1064 				y = (event->y) / viewer->zoom;
1065 			break;
1066 		case 270:
1067 				if (size.width != upper)
1068 					y = ((upper -  event->x) - ((upper - size.width) / 2)) / viewer->zoom;
1069 				else
1070 					y =  ((upper -  event->x) - (upper - size.width)) / viewer->zoom;
1071 
1072 				x = (upper - event->y) / viewer->zoom;
1073 			break;
1074 		}
1075 
1076 		if ( (x > x1 && x < x2) && (y > y1 && y < y2) ) {
1077 				viewer->in_link = TRUE;
1078 			if (((MimeViewer *)viewer)->mimeview &&
1079 				((MimeViewer *)viewer)->mimeview->messageview &&
1080 				((MimeViewer *)viewer)->mimeview->messageview->window &&
1081 				(gdkwin = gtk_widget_get_window(((MimeViewer *)viewer)->mimeview->messageview->window)) != NULL)
1082 					gdk_window_set_cursor (gdkwin, link_cur);
1083 				else
1084 					gdk_window_set_cursor (gtk_widget_get_window(mainwindow_get_mainwindow()->window), link_cur);
1085 
1086 				viewer->link_action = lmapping->action;
1087 				ccur = TRUE;
1088 		}
1089 		if (!ccur) {
1090 			if (((MimeViewer *)viewer)->mimeview &&
1091 				((MimeViewer *)viewer)->mimeview->messageview &&
1092 				((MimeViewer *)viewer)->mimeview->messageview->window &&
1093 				(gdkwin = gtk_widget_get_window(((MimeViewer *)viewer)->mimeview->messageview->window)) != NULL)
1094 				gdk_window_set_cursor (gdkwin, NULL);
1095 			else
1096 				gdk_window_set_cursor (gtk_widget_get_window(mainwindow_get_mainwindow()->window), NULL);
1097 		}
1098 	}
1099 	g_free(l);
1100 	}
1101 }
pdf_viewer_scroll_cb(GtkWidget * widget,GdkEventScroll * event,PdfViewer * viewer)1102 static gboolean pdf_viewer_scroll_cb(GtkWidget *widget, GdkEventScroll *event,
1103 				    PdfViewer *viewer)
1104 {
1105 	GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(viewer->scrollwin));
1106 	static gboolean in_scroll_cb = FALSE;
1107 	gboolean handled = FALSE;
1108 	gint cur_p = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer->cur_page));
1109 
1110 	if (in_scroll_cb)
1111 		return FALSE;
1112 
1113 	in_scroll_cb = TRUE;
1114 
1115 	if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK) {
1116 		if (event->direction == GDK_SCROLL_UP) {
1117 			pdf_viewer_button_zoom_in_cb(NULL, viewer);
1118 		} else {
1119 			pdf_viewer_button_zoom_out_cb(NULL, viewer);
1120 		}
1121 		in_scroll_cb = FALSE;
1122 		return TRUE;
1123 	}
1124 
1125 	if (event->direction == GDK_SCROLL_UP &&
1126 	    gtk_adjustment_get_value(adj) == gtk_adjustment_get_lower(adj) &&
1127 	    cur_p > 1) {
1128 		gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->cur_page), GTK_SPIN_STEP_BACKWARD, 1);
1129 		gtk_adjustment_set_value(adj,
1130 				gtk_adjustment_get_upper(adj) - gtk_adjustment_get_page_size(adj));
1131 		handled = TRUE;
1132 	} else if (event->direction == GDK_SCROLL_DOWN &&
1133 	    gtk_adjustment_get_value(adj) + gtk_adjustment_get_page_size(adj) == gtk_adjustment_get_upper(adj) &&
1134 	    cur_p < viewer->num_pages) {
1135 		gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->cur_page), GTK_SPIN_STEP_FORWARD, 1);
1136 		gtk_adjustment_set_value(adj, 0.0);
1137 		handled = TRUE;
1138 	}
1139 	in_scroll_cb = FALSE;
1140 	return handled;
1141 }
1142 
pdf_viewer_button_zoom_fit_cb(GtkButton * button,PdfViewer * viewer)1143 static void pdf_viewer_button_zoom_fit_cb(GtkButton *button, PdfViewer *viewer)
1144 {
1145 	GtkAllocation allocation;
1146 	double xratio, yratio;
1147 	gtk_widget_get_allocation(viewer->scrollwin, &allocation);
1148 	debug_print("width: %d\n", allocation.width);
1149 	debug_print("height: %d\n", allocation.height);
1150 	xratio = allocation.width / viewer->width;
1151 	yratio = allocation.height / viewer->height;
1152 
1153 	if (xratio >= yratio) {
1154 		viewer->zoom = yratio;
1155 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer->zoom_scroll),viewer->zoom);
1156 	}
1157 	else {
1158 		viewer->zoom = xratio;
1159 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer->zoom_scroll),viewer->zoom);
1160 	}
1161 }
1162 
pdf_viewer_button_zoom_width_cb(GtkButton * button,PdfViewer * viewer)1163 static void pdf_viewer_button_zoom_width_cb(GtkButton *button, PdfViewer *viewer)
1164 {
1165 	GtkAllocation allocation;
1166 	double xratio;
1167 	gtk_widget_get_allocation(viewer->scrollwin, &allocation);
1168 	debug_print("width: %d\n", allocation.width);
1169 	xratio = allocation.width / viewer->width;
1170 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer->zoom_scroll), xratio);
1171 }
1172 
pdf_viewer_button_rotate_right_cb(GtkButton * button,PdfViewer * viewer)1173 static void pdf_viewer_button_rotate_right_cb(GtkButton *button, PdfViewer *viewer)
1174 {
1175 	if (viewer->rotate == 360) {
1176 		viewer->rotate = 0;
1177 	}
1178 
1179 	viewer->rotate += (gint) ROTATION;
1180 	pdf_viewer_update((MimeViewer *)viewer, FALSE,
1181 		gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer->cur_page)));
1182 }
1183 
pdf_viewer_button_rotate_left_cb(GtkButton * button,PdfViewer * viewer)1184 static void pdf_viewer_button_rotate_left_cb(GtkButton *button, PdfViewer *viewer)
1185 {
1186 	if (viewer->rotate == 0) {
1187 		viewer->rotate = 360;
1188 	}
1189 
1190 	viewer->rotate = abs(viewer->rotate -(gint) ROTATION);
1191 	pdf_viewer_update((MimeViewer *)viewer, FALSE,
1192 		gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer->cur_page)));
1193 }
1194 
1195 /* Show/Hide the index pane */
pdf_viewer_show_document_index_cb(GtkToggleButton * button,PdfViewer * viewer)1196 static void pdf_viewer_show_document_index_cb(GtkToggleButton *button, PdfViewer *viewer)
1197 {
1198 	if (!viewer->pdf_index) {
1199 		viewer->pdf_index = poppler_index_iter_new(viewer->pdf_doc);
1200 	}
1201 
1202 	gtk_tree_store_clear(GTK_TREE_STORE(viewer->index_model));
1203 
1204 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(viewer->doc_index))) {
1205 		pdf_viewer_get_document_index(viewer,(PopplerIndexIter *) viewer->pdf_index, NULL);
1206 		gtk_widget_show(GTK_WIDGET(viewer->frame_index));
1207 	}
1208 	else {
1209 		pdf_viewer_hide_index_pane(viewer);
1210 	}
1211 
1212 }
1213 
pdf_viewer_button_print_cb(GtkButton * button,PdfViewer * viewer)1214 static void pdf_viewer_button_print_cb(GtkButton *button, PdfViewer *viewer)
1215 {
1216 	MainWindow *mainwin = mainwindow_get_mainwindow();
1217 	summary_print(mainwin->summaryview);
1218 }
1219 
pdf_viewer_button_document_info_cb(GtkButton * button,PdfViewer * viewer)1220 static void pdf_viewer_button_document_info_cb(GtkButton *button, PdfViewer *viewer)
1221 {
1222 	alertpanel_full(_("PDF properties"), NULL, GTK_STOCK_CLOSE, NULL, NULL,
1223 			ALERTFOCUS_FIRST, FALSE,
1224 			GTK_WIDGET(pdf_viewer_fill_info_table(viewer)),
1225 			ALERT_NOTICE);
1226 }
1227 
1228 /*
1229 static const char * poppler_get_document_info_mode(PopplerPageMode mode)
1230 {
1231 	GEnumValue *enum_value;
1232 
1233 	enum_value = g_enum_get_value((GEnumClass *) g_type_class_peek(POPPLER_TYPE_PAGE_MODE), mode);
1234 	return(gchar *) enum_value->value_name;
1235 }
1236 static const char * poppler_get_document_info_layout(PopplerPageLayout layout)
1237 {
1238 
1239 	GEnumValue *enum_value;
1240 
1241 	enum_value = g_enum_get_value((GEnumClass *) g_type_class_peek(POPPLER_TYPE_PAGE_LAYOUT), layout);
1242 	return(gchar *) enum_value->value_name;
1243 }
1244 */
pdf_viewer_show_controls(PdfViewer * viewer,gboolean show)1245 static void pdf_viewer_show_controls(PdfViewer *viewer, gboolean show)
1246 {
1247 	if (show) {
1248 		gtk_widget_show(viewer->first_page);
1249 		gtk_widget_show(viewer->cur_page);
1250 		gtk_widget_show(viewer->prev_page);
1251 		gtk_widget_show(viewer->next_page);
1252 		gtk_widget_show(viewer->last_page);
1253 		gtk_widget_show(viewer->zoom_in);
1254 		gtk_widget_show(viewer->zoom_out);
1255 		gtk_widget_show(viewer->zoom_fit);
1256 		gtk_widget_show(viewer->zoom_width);
1257 		gtk_widget_show(viewer->zoom_scroll);
1258 		gtk_widget_show(viewer->widgets_table);
1259 		gtk_widget_show(viewer->rotate_right);
1260 		gtk_widget_show(viewer->rotate_left);
1261 		gtk_widget_show(viewer->print);
1262 		gtk_widget_show(viewer->doc_info);
1263 		gtk_widget_show(viewer->doc_index);
1264 	} else {
1265 		gtk_widget_hide(viewer->first_page);
1266 		gtk_widget_hide(viewer->cur_page);
1267 		gtk_widget_hide(viewer->prev_page);
1268 		gtk_widget_hide(viewer->next_page);
1269 		gtk_widget_hide(viewer->last_page);
1270 		gtk_widget_hide(viewer->zoom_in);
1271 		gtk_widget_hide(viewer->zoom_out);
1272 		gtk_widget_hide(viewer->zoom_fit);
1273 		gtk_widget_hide(viewer->zoom_width);
1274 		gtk_widget_hide(viewer->zoom_scroll);
1275 		gtk_widget_hide(viewer->widgets_table);
1276 		gtk_widget_hide(viewer->rotate_right);
1277 		gtk_widget_hide(viewer->rotate_left);
1278 		gtk_widget_hide(viewer->print);
1279 		gtk_widget_hide(viewer->doc_info);
1280 		gtk_widget_hide(viewer->doc_index);
1281 	}
1282 }
1283 /** Render the current page, page_num on the viewer */
pdf_viewer_update(MimeViewer * _viewer,gboolean reload_file,int page_num)1284 static void pdf_viewer_update(MimeViewer *_viewer, gboolean reload_file, int page_num)
1285 {
1286 
1287 	PdfViewer *viewer = (PdfViewer *) _viewer;
1288 	GError *error = NULL;
1289 	gchar *tmpfile = NULL;
1290 	gchar *tmp;
1291 	gchar *password = NULL;
1292 
1293 	debug_print("pdf_viewer_update\n");
1294 
1295 	if (reload_file) {
1296 		if (viewer->pdf_doc) {
1297 			g_object_unref(G_OBJECT(viewer->pdf_doc));
1298 			viewer->pdf_doc = NULL;
1299 		}
1300 
1301 		if (pdf_viewer_mimepart_get_type(viewer->to_load) == TYPE_PS) {
1302 			stock_pixbuf_gdk(STOCK_PIXMAP_MIME_PS,
1303 					&viewer->icon_pixbuf);
1304 			gtk_image_set_from_pixbuf(GTK_IMAGE(viewer->icon_type),
1305 									viewer->icon_pixbuf);
1306 		}
1307 		else if (pdf_viewer_mimepart_get_type(viewer->to_load) == TYPE_PDF) {
1308 			stock_pixbuf_gdk(STOCK_PIXMAP_MIME_PDF,
1309 			&viewer->icon_pixbuf);
1310 			gtk_image_set_from_pixbuf(GTK_IMAGE(viewer->icon_type),
1311 									viewer->icon_pixbuf);
1312 		}
1313 		else {
1314 			stock_pixbuf_gdk(STOCK_PIXMAP_MIME_APPLICATION,
1315 			&viewer->icon_pixbuf);
1316 			gtk_image_set_from_pixbuf(GTK_IMAGE(viewer->icon_type),
1317 									viewer->icon_pixbuf);
1318 		}
1319 
1320 		gtk_label_set_text(GTK_LABEL(viewer->doc_label), _("Loading..."));
1321 		pdf_viewer_show_controls(viewer, FALSE);
1322 		main_window_cursor_wait(mainwindow_get_mainwindow());
1323 
1324 		GTK_EVENTS_FLUSH();
1325 
1326 		if (pdf_viewer_mimepart_get_type(viewer->to_load) == TYPE_PS) {
1327 			gchar *cmdline = NULL, *tmp = NULL, *gspath = NULL;
1328 			gint result = 0;
1329 
1330 			if ((gspath = g_find_program_in_path("gs")) != NULL) {
1331 				g_free(gspath);
1332 				/* convert postscript to pdf */
1333 				tmpfile = get_tmp_file();
1334 				cmdline = g_strdup_printf(
1335 					"gs -dSAFER -dCompatibilityLevel=1.2 -q -dNOPAUSE -dBATCH "
1336 					  "-sDEVICE=pdfwrite -sOutputFile=%s -c .setpdfwrite -f \"%s\"",
1337 					tmpfile, viewer->filename);
1338 				result = execute_command_line(cmdline, FALSE, NULL);
1339 				if (result == 0) {
1340 					tmp = g_filename_to_uri(tmpfile, NULL, NULL);
1341 					viewer->pdf_doc = poppler_document_new_from_file( tmp, NULL, &error);
1342 					g_free(tmp);
1343 				}
1344 				else {
1345 					g_warning("gs conversion failed: %s returned %d", cmdline, result);
1346 					tmp = g_strdup_printf("gs: err %d", result);
1347 					alertpanel_warning("%s", tmp);
1348 					g_free(tmp);
1349 				}
1350 
1351 				g_free(cmdline);
1352 				claws_unlink(tmpfile);
1353 				g_free(tmpfile);
1354 			}
1355 			else {
1356 				g_warning("gs conversion disabled: gs binary was not found");
1357 				alertpanel_warning("PostScript view disabled: required gs program not found");
1358 				result = 1;
1359 
1360 			}
1361 			if (result != 0) {
1362 				main_window_cursor_normal(mainwindow_get_mainwindow());
1363 				return;
1364 			}
1365 		}
1366 		else {
1367 			viewer->pdf_doc = poppler_document_new_from_file( viewer->fsname, NULL, &error);
1368 		}
1369 		if (error && g_error_matches(error, POPPLER_ERROR, POPPLER_ERROR_ENCRYPTED)) {
1370 			g_clear_error(&error);
1371 			password = input_dialog_with_invisible(_("Enter password"),
1372 					_("This document is locked and requires a password before it can be opened."),
1373 					"");
1374 			viewer->pdf_doc = poppler_document_new_from_file(viewer->fsname, password, &error);
1375 			g_free(password);
1376 		}
1377 
1378 		viewer->num_pages = poppler_document_get_n_pages(viewer->pdf_doc);
1379 
1380 		g_signal_handlers_block_by_func(G_OBJECT(viewer->cur_page), pdf_viewer_spin_change_page_cb,(gpointer *)viewer);
1381 		gtk_spin_button_set_range(GTK_SPIN_BUTTON(viewer->cur_page),
1382 									1,
1383 								(gdouble)viewer->num_pages );
1384 
1385 		g_signal_handlers_unblock_by_func(G_OBJECT(viewer->cur_page), pdf_viewer_spin_change_page_cb,(gpointer *)viewer);
1386 		gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->cur_page), GTK_SPIN_HOME, 1);
1387 		tmp = g_strdup_printf(_("%s Document"),pdf_viewer_mimepart_get_type(viewer->to_load) == TYPE_PDF ? "PDF":"Postscript");
1388 		CLAWS_SET_TIP(
1389 				GTK_WIDGET(viewer->icon_type_ebox),
1390 				tmp);
1391 		g_free(tmp);
1392 
1393 		tmp = g_strdup_printf(_("of %d"), viewer->num_pages);
1394 		gtk_label_set_text(GTK_LABEL(viewer->doc_label), tmp);
1395 		g_free(tmp);
1396 
1397 		pdf_viewer_show_controls(viewer, TRUE);
1398 		main_window_cursor_normal(mainwindow_get_mainwindow());
1399 	}
1400 	if (viewer->pdf_doc == NULL) {
1401 		stock_pixbuf_gdk(STOCK_PIXMAP_MIME_APPLICATION,
1402 				&viewer->icon_pixbuf);
1403 
1404 		gtk_image_set_from_pixbuf(GTK_IMAGE(viewer->icon_type), viewer->icon_pixbuf);
1405 		if (error) {
1406 			strretchomp(error->message);
1407 			alertpanel_error("%s", error->message);
1408 		} else {
1409 			alertpanel_error(_("PDF rendering failed for an unknown reason."));
1410 		}
1411 		pdf_viewer_show_controls(viewer, FALSE);
1412 		g_error_free(error);
1413 		return;
1414 	}
1415 
1416 	if (page_num == 1) {
1417 		gtk_widget_set_sensitive(viewer->first_page, FALSE);
1418 		gtk_widget_set_sensitive(viewer->prev_page, FALSE);
1419 	}
1420 	else {
1421 		gtk_widget_set_sensitive(viewer->first_page, TRUE);
1422 		gtk_widget_set_sensitive(viewer->prev_page, TRUE);
1423 	}
1424 
1425 	if (page_num == viewer->num_pages) {
1426 		gtk_widget_set_sensitive(viewer->last_page, FALSE);
1427 		gtk_widget_set_sensitive(viewer->next_page, FALSE);
1428 	}
1429 	else {
1430 		gtk_widget_set_sensitive(viewer->last_page, TRUE);
1431 		gtk_widget_set_sensitive(viewer->next_page, TRUE);
1432 	}
1433 
1434 	/* check for the index if exists */
1435 	pdf_viewer_set_index_button_sensitive((PdfViewer *) viewer);
1436 
1437 	if (page_num > 0 && page_num <= viewer->num_pages) {
1438 
1439 		GTK_EVENTS_FLUSH();
1440 
1441 		if (viewer->pdf_page) {
1442 			g_object_unref(G_OBJECT(viewer->pdf_page));
1443 		}
1444 
1445 		viewer->pdf_page = poppler_document_get_page(viewer->pdf_doc, page_num - 1);
1446 
1447 		if (viewer->pdf_page == NULL) {
1448 			g_warning("Page not found");
1449 			return;
1450 		}
1451 
1452 		if (viewer->rotate == 90 || viewer->rotate == 270) {
1453 			poppler_page_get_size(viewer->pdf_page, &viewer->height, &viewer->width);
1454 		}
1455 		else {
1456 			poppler_page_get_size(viewer->pdf_page, &viewer->width, &viewer->height);
1457 		}
1458 
1459 		if (viewer->last_rect && viewer->last_page_result &&
1460 		    viewer->last_page_result->page_num == page_num) {
1461 			pdf_viewer_render_selection(viewer, viewer->last_rect, viewer->last_page_result);
1462 		}
1463 		else {
1464 			pdf_viewer_render_page(viewer->pdf_page, viewer->pdf_view, viewer->width,
1465 									viewer->height, viewer->zoom, viewer->rotate);
1466 
1467 		}
1468 
1469 	/* Get Links Mapping */
1470 	if (viewer->link_map) {
1471 		poppler_page_free_link_mapping(viewer->link_map);
1472 	}
1473 	viewer->link_map = poppler_page_get_link_mapping(viewer->pdf_page);
1474 
1475 	}
1476 }
1477 
1478 
pdf_viewer_show_mimepart(MimeViewer * _viewer,const gchar * infile,MimeInfo * partinfo)1479 static void pdf_viewer_show_mimepart(MimeViewer *_viewer, const gchar *infile,
1480 				MimeInfo *partinfo)
1481 {
1482 	PdfViewer *viewer = (PdfViewer *) _viewer;
1483 	gchar buf[4096];
1484 	const gchar *charset = NULL;
1485 	MessageView *messageview = ((MimeViewer *)viewer)->mimeview
1486 					?((MimeViewer *)viewer)->mimeview->messageview
1487 					: NULL;
1488 
1489 	viewer->rotate = 0;
1490 	viewer->to_load = partinfo;
1491 
1492 	if (messageview)
1493 		messageview->updating = TRUE;
1494 
1495 	memset(buf, 0, sizeof(buf));
1496 	debug_print("pdf_viewer_show_mimepart\n");
1497 
1498 	if (viewer->filename != NULL) {
1499 		claws_unlink(viewer->filename);
1500 		g_free(viewer->filename);
1501 		viewer->filename = NULL;
1502 	}
1503 
1504 	viewer->mimeinfo = NULL;
1505 
1506 	if (partinfo) {
1507 		viewer->target_filename = procmime_get_part_file_name(partinfo);
1508 		viewer->filename = procmime_get_tmp_file_name(partinfo);
1509 		viewer->fsname = g_filename_to_uri(viewer->filename, NULL, NULL);
1510 	}
1511 
1512 	if (partinfo && !(procmime_get_part(viewer->filename, partinfo) < 0)) {
1513 
1514 		if (messageview && messageview->forced_charset)
1515 			charset = _viewer->mimeview->messageview->forced_charset;
1516 		else
1517 			charset = procmime_mimeinfo_get_parameter(partinfo, "charset");
1518 
1519 		if (charset == NULL) {
1520 			charset = conv_get_locale_charset_str();
1521 		}
1522 
1523 		debug_print("using charset %s\n", charset);
1524 
1525 		viewer->mimeinfo = partinfo;
1526 	}
1527 
1528 	pdf_viewer_update((MimeViewer *)viewer, TRUE, 1);
1529 
1530 	if (messageview)
1531 		messageview->updating = FALSE;
1532 }
1533 
pdf_viewer_clear(MimeViewer * _viewer)1534 static void pdf_viewer_clear(MimeViewer *_viewer)
1535 {
1536 	PdfViewer *viewer = (PdfViewer *) _viewer;
1537 	GtkAdjustment *vadj;
1538 
1539 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(viewer->doc_index), FALSE);
1540 	gtk_widget_hide(viewer->frame_index);
1541 
1542 	debug_print("pdf_viewer_clear\n");
1543 	viewer->to_load = NULL;
1544 
1545 	if (viewer->pdf_doc) {
1546 		g_object_unref(G_OBJECT(viewer->pdf_doc));
1547 		viewer->pdf_doc = NULL;
1548 	}
1549 
1550 	vadj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(viewer->scrollwin));
1551 	gtk_adjustment_set_value(vadj, 0.0);
1552 	g_signal_emit_by_name(G_OBJECT(vadj), "value-changed", 0);
1553 	vadj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(viewer->scrollwin_index));
1554 	gtk_adjustment_set_value(vadj, 0.0);
1555 	g_signal_emit_by_name(G_OBJECT(vadj), "value-changed", 0);
1556 	gtk_tree_store_clear(GTK_TREE_STORE(viewer->index_model));
1557 	gtk_image_set_from_pixbuf(GTK_IMAGE(viewer->pdf_view), NULL);
1558 }
1559 
pdf_viewer_destroy(MimeViewer * _viewer)1560 static void pdf_viewer_destroy(MimeViewer *_viewer)
1561 {
1562 	PdfViewer *viewer = (PdfViewer *) _viewer;
1563 
1564 	debug_print("pdf_viewer_destroy\n");
1565 
1566 	if (viewer->pdf_index) poppler_index_iter_free(viewer->pdf_index);
1567 
1568 	poppler_page_free_link_mapping (viewer->link_map);
1569 	g_object_unref(GTK_WIDGET(viewer->vbox));
1570 	g_object_unref(GTK_WIDGET(viewer->pdf_view));
1571 	g_object_unref(GTK_WIDGET(viewer->doc_index_pane));
1572 	g_object_unref(GTK_WIDGET(viewer->scrollwin));
1573 	g_object_unref(GTK_WIDGET(viewer->scrollwin_index));
1574 	claws_unlink(viewer->filename);
1575 	g_free(viewer->filename);
1576 	g_free(viewer);
1577 }
1578 
pdf_viewer_scroll_page(MimeViewer * _viewer,gboolean up)1579 static gboolean pdf_viewer_scroll_page(MimeViewer *_viewer, gboolean up)
1580 {
1581 	PdfViewer *viewer = (PdfViewer *)_viewer;
1582 	GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment(
1583 				GTK_SCROLLED_WINDOW(viewer->scrollwin));
1584 
1585 	gint cur_p = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer->cur_page));
1586 
1587 	if (viewer->pdf_view == NULL) return FALSE;
1588 
1589 	if (!gtkutils_scroll_page(GTK_WIDGET(viewer->pdf_view), vadj, up)) {
1590 		if (!up && cur_p != viewer->num_pages) {
1591 			gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->cur_page), GTK_SPIN_STEP_FORWARD, 1);
1592 			vadj = gtk_scrolled_window_get_vadjustment(
1593 					GTK_SCROLLED_WINDOW(viewer->scrollwin));
1594 			gtk_adjustment_set_value(vadj, 0.0);
1595 			g_signal_emit_by_name(G_OBJECT(vadj), "value-changed", 0);
1596 			return TRUE;
1597 		}
1598 		else if (up && cur_p != 1) {
1599 			gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->cur_page), GTK_SPIN_STEP_BACKWARD, 1);
1600 			vadj = gtk_scrolled_window_get_vadjustment(
1601 					GTK_SCROLLED_WINDOW(viewer->scrollwin));
1602 			gtk_adjustment_set_value(vadj,
1603 					gtk_adjustment_get_upper(vadj) - gtk_adjustment_get_page_size(vadj));
1604 			g_signal_emit_by_name(G_OBJECT(vadj), "value-changed", 0);
1605 			return TRUE;
1606 		}
1607 		return FALSE;
1608 	}
1609 	else return TRUE;
1610 }
1611 
pdf_viewer_scroll_one_line(MimeViewer * _viewer,gboolean up)1612 static void pdf_viewer_scroll_one_line(MimeViewer *_viewer, gboolean up)
1613 {
1614 	PdfViewer *viewer = (PdfViewer *)_viewer;
1615 	GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment(
1616 				GTK_SCROLLED_WINDOW(viewer->scrollwin));
1617 	gint cur_p;
1618 	cur_p = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer->cur_page));
1619 
1620 	if (viewer->pdf_view == NULL) return;
1621 		debug_print("up: %d\n", up);
1622 		if (gtk_adjustment_get_value(vadj) < (gtk_adjustment_get_upper(vadj) - gtk_adjustment_get_page_size(vadj)))  {
1623 			gtkutils_scroll_one_line(GTK_WIDGET(viewer->pdf_view), vadj, up);
1624 		}
1625 		else {
1626 			if (cur_p != viewer->num_pages) {
1627 				pdf_viewer_scroll_page((MimeViewer *)viewer, up);
1628 			}
1629 		}
1630 
1631 }
1632 
1633 #define BUTTON_H_PADDING 3
1634 #define ADD_BUTTON_TO_TABLE(widget, stock_image) \
1635 	widget = gtk_button_new(); \
1636 	img = stock_pixmap_widget(stock_image); \
1637 	gtk_button_set_image(GTK_BUTTON(widget), img); \
1638 	gtk_table_attach(GTK_TABLE(viewer->widgets_table), GTK_WIDGET(widget), \
1639 				col, col+1, 0, 1, 0, 0, BUTTON_H_PADDING, 0); \
1640 	col++;
1641 #define ADD_TOGGLE_BUTTON_TO_TABLE(widget, stock_image) \
1642 	widget = gtk_toggle_button_new(); \
1643 	img = stock_pixmap_widget(stock_image); \
1644 	gtk_button_set_image(GTK_BUTTON(widget), img); \
1645 	gtk_table_attach(GTK_TABLE(viewer->widgets_table), GTK_WIDGET(widget), \
1646 				col, col+1, 0, 1, 0, 0, BUTTON_H_PADDING, 0); \
1647 	col++;
1648 
1649 #define ADD_SEP_TO_TABLE \
1650 	sep = gtk_label_new(""); \
1651 	gtk_table_attach(GTK_TABLE(viewer->widgets_table), GTK_WIDGET(sep), \
1652 					col, col+1, 0, 1, 0, 0, 0, 0); \
1653 	gtk_table_set_col_spacing(GTK_TABLE(viewer->widgets_table), col, 3*BUTTON_H_PADDING); \
1654 	col++;
1655 
1656 #if POPPLER_HAS_CAIRO
pdf_viewer_get_pango_context(gpointer data)1657 static PangoContext *pdf_viewer_get_pango_context(gpointer data)
1658 {
1659 	return NULL;
1660 }
1661 
pdf_viewer_get_data_to_print(gpointer data,gint sel_start,gint sel_end)1662 static gpointer pdf_viewer_get_data_to_print(gpointer data, gint sel_start, gint sel_end)
1663 {
1664 	return NULL; /* we don't need it */
1665 }
1666 
pdf_viewer_cb_begin_print(GtkPrintOperation * op,GtkPrintContext * context,gpointer user_data)1667 static void pdf_viewer_cb_begin_print(GtkPrintOperation *op, GtkPrintContext *context,
1668 			   gpointer user_data)
1669 {
1670   PrintData *print_data;
1671   PopplerDocument *pdf_doc;
1672   gint n_pages = 0;
1673   print_data = (PrintData*) user_data;
1674   pdf_doc = (PopplerDocument *)printing_get_renderer_data(print_data);
1675 
1676   debug_print("Preparing print job...\n");
1677 
1678   n_pages = poppler_document_get_n_pages(pdf_doc);
1679   printing_set_n_pages(print_data, n_pages);
1680   gtk_print_operation_set_n_pages(op, n_pages);
1681 
1682   debug_print("Starting print job...\n");
1683 }
1684 
pdf_viewer_cb_draw_page(GtkPrintOperation * op,GtkPrintContext * context,int page_nr,gpointer user_data)1685 static void pdf_viewer_cb_draw_page(GtkPrintOperation *op, GtkPrintContext *context,
1686 			 int page_nr, gpointer user_data)
1687 {
1688   cairo_t *cr;
1689   PrintData *print_data;
1690   PopplerDocument *pdf_doc;
1691   PopplerPage *pdf_page;
1692 
1693   print_data = (PrintData*) user_data;
1694   pdf_doc = (PopplerDocument *)printing_get_renderer_data(print_data);
1695   pdf_page = poppler_document_get_page(pdf_doc, page_nr);
1696 
1697   cr = gtk_print_context_get_cairo_context(context);
1698   cairo_scale(cr, printing_get_zoom(print_data), printing_get_zoom(print_data));
1699   cairo_set_source_rgb(cr, 0., 0., 0.);
1700 
1701   poppler_page_render_for_printing(pdf_page, cr);
1702 
1703   g_object_unref(G_OBJECT(pdf_page));
1704 
1705   debug_print("Sent page %d to printer\n", page_nr+1);
1706 }
1707 
pdf_viewer_print(MimeViewer * mviewer)1708 static void pdf_viewer_print(MimeViewer *mviewer)
1709 {
1710 	PdfViewer *viewer = (PdfViewer *)mviewer;
1711 	PrintRenderer *pdf_renderer = g_new0(PrintRenderer, 1);
1712 	MainWindow *mainwin = mainwindow_get_mainwindow();
1713 
1714 	pdf_renderer->get_pango_context = pdf_viewer_get_pango_context;
1715 	pdf_renderer->get_data_to_print = pdf_viewer_get_data_to_print;
1716 	pdf_renderer->cb_begin_print    = pdf_viewer_cb_begin_print;
1717 	pdf_renderer->cb_draw_page      = pdf_viewer_cb_draw_page;
1718 
1719 	printing_print_full(mainwin ? GTK_WINDOW(mainwin->window):NULL,
1720 			pdf_renderer, viewer->pdf_doc, -1, -1, NULL);
1721 
1722 	g_free(pdf_renderer);
1723 }
1724 #endif
1725 
pdf_viewer_create(void)1726 static MimeViewer *pdf_viewer_create(void)
1727 {
1728 	PdfViewer *viewer;
1729  	GtkTreeViewColumn *column;
1730 	GtkCellRenderer *renderer;
1731 	GtkTreeStore *tree_store;
1732 	GtkWidget *sep;
1733 	GtkWidget *img;
1734 	gint col = 0;
1735 
1736 	viewer = g_new0(PdfViewer, 1);
1737 	debug_print("pdf_viewer_create\n");
1738 
1739 	viewer->last_x = 0;
1740 	viewer->last_y = 0;
1741 	viewer->mimeviewer.factory = &pdf_viewer_factory;
1742 	viewer->mimeviewer.get_widget = pdf_viewer_get_widget;
1743 	viewer->mimeviewer.show_mimepart = pdf_viewer_show_mimepart;
1744 	viewer->mimeviewer.clear_viewer = pdf_viewer_clear;
1745 	viewer->mimeviewer.destroy_viewer = pdf_viewer_destroy;
1746 	viewer->mimeviewer.text_search = pdf_viewer_text_search;
1747 	viewer->mimeviewer.scroll_page = pdf_viewer_scroll_page;
1748 	viewer->mimeviewer.scroll_one_line = pdf_viewer_scroll_one_line;
1749 #if POPPLER_HAS_CAIRO
1750 	viewer->mimeviewer.print = pdf_viewer_print;
1751 #endif
1752 	viewer->scrollwin = gtk_scrolled_window_new(NULL, NULL);
1753 	viewer->scrollwin_index = gtk_scrolled_window_new(NULL, NULL);
1754 	viewer->pdf_view_ebox = gtk_event_box_new();
1755 	gtk_event_box_set_visible_window(GTK_EVENT_BOX(viewer->pdf_view_ebox), FALSE);
1756 
1757 	viewer->mimeinfo  = NULL;
1758 
1759 	viewer->pdf_view = gtk_image_new();
1760 	gtk_widget_set_events(viewer->pdf_view_ebox,
1761 						GDK_BUTTON_RELEASE_MASK
1762 						| GDK_POINTER_MOTION_MASK
1763 						| GDK_BUTTON_PRESS_MASK
1764 						| GDK_BUTTON_MOTION_MASK
1765 					    );
1766 	gtk_container_add (GTK_CONTAINER(viewer->pdf_view_ebox), viewer->pdf_view);
1767 	viewer->icon_type = gtk_image_new();
1768 	viewer->icon_type_ebox = gtk_event_box_new();
1769 
1770 	gtk_container_add(GTK_CONTAINER(viewer->icon_type_ebox), viewer->icon_type);
1771 
1772 	viewer->doc_label = gtk_label_new("");
1773 
1774 	viewer->widgets_table = gtk_table_new(1, 1, FALSE);
1775 
1776 	viewer->doc_index_pane = gtk_hpaned_new();
1777 
1778 	viewer->frame_index = gtk_frame_new(NULL);
1779 	gtk_frame_set_shadow_type(GTK_FRAME(viewer->frame_index), GTK_SHADOW_IN);
1780 	gtk_widget_set_size_request(viewer->frame_index, 18, -1);
1781 	gtk_frame_set_label(GTK_FRAME(viewer->frame_index), _("Document Index"));
1782 
1783 	ADD_SEP_TO_TABLE
1784 	ADD_BUTTON_TO_TABLE(viewer->first_page, STOCK_PIXMAP_FIRST_ARROW)
1785 	ADD_BUTTON_TO_TABLE(viewer->prev_page, STOCK_PIXMAP_LEFT_ARROW)
1786 	viewer->cur_page = gtk_spin_button_new_with_range(0.0, 0.0, 1.0);
1787 	viewer->zoom_scroll = gtk_spin_button_new_with_range(0.20, 8.0, 0.20);
1788 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer->zoom_scroll), 1.0);
1789 	viewer->zoom = 1.0;
1790 	gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(viewer->cur_page), TRUE);
1791 	gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(viewer->zoom_scroll), TRUE);
1792 	gtk_table_attach(GTK_TABLE(viewer->widgets_table), GTK_WIDGET(viewer->cur_page),
1793 					col, col+1,
1794 					0, 1, 0, 0,
1795 					BUTTON_H_PADDING,
1796 					0);
1797 	col++;
1798 	gtk_table_attach(GTK_TABLE(viewer->widgets_table), GTK_WIDGET(viewer->doc_label),
1799 					col, col+1,
1800 					0, 1, 0, 0,
1801 					BUTTON_H_PADDING,
1802 					0);
1803 	col++;
1804 
1805 	ADD_BUTTON_TO_TABLE(viewer->next_page, STOCK_PIXMAP_RIGHT_ARROW)
1806 	ADD_BUTTON_TO_TABLE(viewer->last_page, STOCK_PIXMAP_LAST_ARROW)
1807 	ADD_SEP_TO_TABLE
1808 	ADD_BUTTON_TO_TABLE(viewer->zoom_fit, STOCK_PIXMAP_ZOOM_FIT)
1809 	ADD_BUTTON_TO_TABLE(viewer->zoom_in, STOCK_PIXMAP_ZOOM_IN)
1810 	gtk_table_attach(GTK_TABLE(viewer->widgets_table), GTK_WIDGET(viewer->zoom_scroll),
1811 					col, col+1,
1812 					0, 1, 0, 0,
1813 					BUTTON_H_PADDING,
1814 					0);
1815 	col++;
1816 	ADD_BUTTON_TO_TABLE(viewer->zoom_out, STOCK_PIXMAP_ZOOM_OUT)
1817 	ADD_BUTTON_TO_TABLE(viewer->zoom_width, STOCK_PIXMAP_ZOOM_WIDTH)
1818 	ADD_SEP_TO_TABLE
1819 	ADD_BUTTON_TO_TABLE(viewer->rotate_left, STOCK_PIXMAP_ROTATE_LEFT)
1820 	ADD_BUTTON_TO_TABLE(viewer->rotate_right, STOCK_PIXMAP_ROTATE_RIGHT)
1821 	ADD_SEP_TO_TABLE
1822 	ADD_BUTTON_TO_TABLE(viewer->print, STOCK_PIXMAP_PRINTER)
1823 	ADD_BUTTON_TO_TABLE(viewer->doc_info, STOCK_PIXMAP_DOC_INFO)
1824 	ADD_TOGGLE_BUTTON_TO_TABLE(viewer->doc_index, STOCK_PIXMAP_DOC_INDEX)
1825 
1826 	gtk_scrolled_window_set_policy(
1827 			GTK_SCROLLED_WINDOW(viewer->scrollwin),
1828 			GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1829 
1830 	gtk_scrolled_window_set_shadow_type(
1831 			GTK_SCROLLED_WINDOW(viewer->scrollwin),
1832 			GTK_SHADOW_IN);
1833 
1834 	gtk_scrolled_window_add_with_viewport(
1835 			GTK_SCROLLED_WINDOW(viewer->scrollwin),
1836 			viewer->pdf_view_ebox);
1837 
1838 	viewer->vbox = gtk_vbox_new(FALSE, 4);
1839 	viewer->hbox = gtk_hbox_new(FALSE, 4);
1840 
1841     /* treeview */
1842 	tree_store = gtk_tree_store_new(N_INDEX_COLUMNS,
1843 					G_TYPE_STRING,
1844 					G_TYPE_INT,
1845 					G_TYPE_DOUBLE);
1846 
1847 	viewer->index_list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(tree_store));
1848 	g_object_unref(tree_store);
1849 
1850 	renderer = gtk_cell_renderer_text_new();
1851 	column = gtk_tree_view_column_new_with_attributes(_("Name"),  renderer, "text", 0,  NULL);
1852 	gtk_tree_view_append_column(GTK_TREE_VIEW(viewer->index_list), column);
1853 	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(viewer->index_list), FALSE);
1854 
1855 	viewer->index_model = GTK_TREE_MODEL(tree_store);
1856 
1857 	gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(viewer->index_list)),
1858 								GTK_SELECTION_SINGLE);
1859 
1860 	g_signal_connect(G_OBJECT(viewer->index_list), "row_activated",
1861 	                 G_CALLBACK(pdf_viewer_index_row_activated),
1862 					 viewer);
1863 
1864 	gtk_scrolled_window_set_policy(
1865 			GTK_SCROLLED_WINDOW(viewer->scrollwin_index),
1866 			GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1867 
1868 	gtk_scrolled_window_set_shadow_type(
1869 			GTK_SCROLLED_WINDOW(viewer->scrollwin_index),
1870 			GTK_SHADOW_IN);
1871 
1872 	gtk_scrolled_window_add_with_viewport(
1873 			GTK_SCROLLED_WINDOW(viewer->scrollwin_index),
1874 			viewer->index_list);
1875 
1876 	/* end treeview */
1877 
1878 	stock_pixbuf_gdk(STOCK_PIXMAP_MIME_TEXT_PLAIN,
1879 			&viewer->icon_pixbuf);
1880 
1881 	gtk_image_set_from_pixbuf(GTK_IMAGE(viewer->icon_type),
1882 				viewer->icon_pixbuf);
1883 
1884 	/* pack widgets*/
1885 	gtk_box_pack_start(GTK_BOX(viewer->hbox), viewer->icon_type_ebox, FALSE, FALSE, 0);
1886 	gtk_box_pack_start(GTK_BOX(viewer->hbox), viewer->widgets_table, FALSE, FALSE, 0);
1887 
1888 	gtk_container_add(GTK_CONTAINER(viewer->frame_index), viewer->scrollwin_index);
1889 
1890 	gtk_paned_pack1(GTK_PANED(viewer->doc_index_pane), viewer->frame_index, FALSE, FALSE);
1891 	gtk_paned_pack2(GTK_PANED(viewer->doc_index_pane), viewer->scrollwin, FALSE, FALSE);
1892 
1893 	gtk_box_pack_start(GTK_BOX(viewer->vbox), viewer->hbox, FALSE, FALSE, 0);
1894 	gtk_box_pack_start(GTK_BOX(viewer->vbox), viewer->doc_index_pane, TRUE, TRUE, 0);
1895 	/* show widgets */
1896 	gtk_widget_show(GTK_WIDGET(viewer->doc_index_pane));
1897 	g_object_ref(GTK_WIDGET(viewer->doc_index_pane));
1898 	gtk_widget_show(GTK_WIDGET(viewer->scrollwin));
1899 	g_object_ref(GTK_WIDGET(viewer->scrollwin));
1900 	gtk_widget_show(GTK_WIDGET(viewer->icon_type_ebox));
1901 	g_object_ref(GTK_WIDGET(viewer->icon_type_ebox));
1902 	gtk_widget_show(GTK_WIDGET(viewer->pdf_view_ebox));
1903 	g_object_ref(GTK_WIDGET(viewer->pdf_view_ebox));
1904 	gtk_widget_show(GTK_WIDGET(viewer->scrollwin_index));
1905 	g_object_ref(GTK_WIDGET(viewer->scrollwin_index));
1906 	gtk_widget_show(GTK_WIDGET(viewer->hbox));
1907 	g_object_ref(GTK_WIDGET(viewer->hbox));
1908 	gtk_widget_show(GTK_WIDGET(viewer->vbox));
1909 	g_object_ref(GTK_WIDGET(viewer->vbox));
1910 
1911 	gtk_widget_show(GTK_WIDGET(viewer->widgets_table));
1912 	g_object_ref(GTK_WIDGET(viewer->widgets_table));
1913 
1914 	gtk_widget_show(GTK_WIDGET(viewer->cur_page));
1915 	g_object_ref(GTK_WIDGET(viewer->cur_page));
1916 
1917 	gtk_widget_show(GTK_WIDGET(viewer->first_page));
1918 	g_object_ref(GTK_WIDGET(viewer->first_page));
1919 
1920 	gtk_widget_show(GTK_WIDGET(viewer->last_page));
1921 	g_object_ref(GTK_WIDGET(viewer->last_page));
1922 
1923 	gtk_widget_show(GTK_WIDGET(viewer->prev_page));
1924 	g_object_ref(GTK_WIDGET(viewer->prev_page));
1925 
1926 	gtk_widget_show(GTK_WIDGET(viewer->next_page));
1927 	g_object_ref(GTK_WIDGET(viewer->next_page));
1928 
1929 	gtk_widget_show(GTK_WIDGET(viewer->zoom_in));
1930 	g_object_ref(GTK_WIDGET(viewer->zoom_in));
1931 	gtk_widget_show(GTK_WIDGET(viewer->zoom_out));
1932 	g_object_ref(GTK_WIDGET(viewer->zoom_out));
1933 	gtk_widget_show(GTK_WIDGET(viewer->zoom_fit));
1934 	g_object_ref(GTK_WIDGET(viewer->zoom_fit));
1935 	gtk_widget_show(GTK_WIDGET(viewer->zoom_width));
1936 	g_object_ref(GTK_WIDGET(viewer->zoom_width));
1937 
1938 	gtk_widget_show(GTK_WIDGET(viewer->rotate_right));
1939 	g_object_ref(GTK_WIDGET(viewer->rotate_right));
1940 	gtk_widget_show(GTK_WIDGET(viewer->rotate_left));
1941 	g_object_ref(GTK_WIDGET(viewer->rotate_left));
1942 	gtk_widget_show(GTK_WIDGET(viewer->print));
1943 	g_object_ref(GTK_WIDGET(viewer->print));
1944 	gtk_widget_show(GTK_WIDGET(viewer->doc_info));
1945 	g_object_ref(GTK_WIDGET(viewer->doc_info));
1946 	gtk_widget_show(GTK_WIDGET(viewer->doc_index));
1947 	g_object_ref(GTK_WIDGET(viewer->doc_index));
1948 
1949 	gtk_widget_show(GTK_WIDGET(viewer->doc_label));
1950 	g_object_ref(GTK_WIDGET(viewer->doc_label));
1951 	gtk_widget_show(GTK_WIDGET(viewer->icon_type));
1952 	g_object_ref(GTK_WIDGET(viewer->icon_type));
1953 	gtk_widget_show(GTK_WIDGET(viewer->pdf_view));
1954 	g_object_ref(GTK_WIDGET(viewer->pdf_view));
1955 	gtk_widget_show(GTK_WIDGET(viewer->zoom_scroll));
1956 	g_object_ref(GTK_WIDGET(viewer->zoom_scroll));
1957 
1958 	gtk_widget_show(GTK_WIDGET(viewer->index_list));
1959 	g_object_ref(GTK_WIDGET(viewer->index_list));
1960 
1961 	/* Set Tooltips*/
1962 	CLAWS_SET_TIP(viewer->first_page,
1963 				_("First Page"));
1964 
1965 	CLAWS_SET_TIP(viewer->prev_page,
1966 				_("Previous Page"));
1967 
1968 	CLAWS_SET_TIP(viewer->next_page,
1969 				_("Next Page"));
1970 
1971 	CLAWS_SET_TIP(viewer->last_page,
1972 				_("Last Page"));
1973 
1974 	CLAWS_SET_TIP(viewer->zoom_in,
1975 				_("Zoom In"));
1976 	CLAWS_SET_TIP(viewer->zoom_out,
1977 				_("Zoom Out"));
1978 
1979 	CLAWS_SET_TIP(viewer->zoom_fit,
1980 				_("Fit Page"));
1981 
1982 	CLAWS_SET_TIP(viewer->zoom_width,
1983 				_("Fit Page Width"));
1984 
1985 	CLAWS_SET_TIP(viewer->rotate_left,
1986 				_("Rotate Left"));
1987 
1988 	CLAWS_SET_TIP(viewer->rotate_right,
1989 				_("Rotate Right"));
1990 
1991 	CLAWS_SET_TIP(viewer->print,
1992 				_("Print Document"));
1993 
1994 	CLAWS_SET_TIP(viewer->doc_info,
1995 				_("Document Info"));
1996 
1997 	CLAWS_SET_TIP(viewer->doc_index,
1998 				_("Document Index"));
1999 	CLAWS_SET_TIP(viewer->cur_page,
2000 				_("Page Number"));
2001 	CLAWS_SET_TIP(viewer->zoom_scroll,
2002 				_("Zoom Factor"));
2003 	/* Connect Signals */
2004 	g_signal_connect(G_OBJECT(viewer->cur_page),
2005 				    "value-changed",
2006 				    G_CALLBACK(pdf_viewer_spin_change_page_cb),
2007 				   (gpointer) viewer);
2008 
2009 	g_signal_connect(G_OBJECT(viewer->first_page),
2010 				    "clicked",
2011 				    G_CALLBACK(pdf_viewer_button_first_page_cb),
2012 				   (gpointer) viewer);
2013 	g_signal_connect(G_OBJECT(viewer->prev_page),
2014 				    "clicked",
2015 				    G_CALLBACK(pdf_viewer_button_prev_page_cb),
2016 				   (gpointer) viewer);
2017 	g_signal_connect(G_OBJECT(viewer->next_page),
2018 				    "clicked",
2019 				    G_CALLBACK(pdf_viewer_button_next_page_cb),
2020 				   (gpointer) viewer);
2021 	g_signal_connect(G_OBJECT(viewer->last_page),
2022 				    "clicked",
2023 				    G_CALLBACK(pdf_viewer_button_last_page_cb),
2024 				   (gpointer) viewer);
2025 	g_signal_connect(G_OBJECT(viewer->zoom_in),
2026 				    "clicked",
2027 				    G_CALLBACK(pdf_viewer_button_zoom_in_cb),
2028 				   (gpointer) viewer);
2029 	g_signal_connect(G_OBJECT(viewer->zoom_out),
2030 				    "clicked",
2031 				    G_CALLBACK(pdf_viewer_button_zoom_out_cb),
2032 				   (gpointer) viewer);
2033 	g_signal_connect(G_OBJECT(viewer->zoom_scroll),
2034 				    "value-changed",
2035 				    G_CALLBACK(pdf_viewer_spin_zoom_scroll_cb),
2036 				   (gpointer) viewer);
2037 
2038 	g_signal_connect(G_OBJECT(viewer->zoom_fit),
2039 				   "clicked",
2040 				    G_CALLBACK(pdf_viewer_button_zoom_fit_cb),
2041 				   (gpointer) viewer);
2042 
2043 	g_signal_connect(G_OBJECT(viewer->zoom_width),
2044 				    "clicked",
2045 				    G_CALLBACK(pdf_viewer_button_zoom_width_cb),
2046 				   (gpointer) viewer);
2047 
2048 	g_signal_connect(G_OBJECT(viewer->rotate_right),
2049 				    "clicked",
2050 				    G_CALLBACK(pdf_viewer_button_rotate_right_cb),
2051 				   (gpointer) viewer);
2052 
2053 	g_signal_connect(G_OBJECT(viewer->rotate_left),
2054 				    "clicked",
2055 				    G_CALLBACK(pdf_viewer_button_rotate_left_cb),
2056 				   (gpointer) viewer);
2057 
2058 	g_signal_connect(G_OBJECT(viewer->print),
2059 				    "clicked",
2060 				    G_CALLBACK(pdf_viewer_button_print_cb),
2061 				   (gpointer) viewer);
2062 
2063 	g_signal_connect(G_OBJECT(viewer->doc_info),
2064 				    "clicked",
2065 				    G_CALLBACK(pdf_viewer_button_document_info_cb),
2066 				   (gpointer) viewer);
2067 
2068 	g_signal_connect(G_OBJECT(viewer->doc_index),
2069 				    "clicked",
2070 				    G_CALLBACK(pdf_viewer_show_document_index_cb),
2071 				   (gpointer) viewer);
2072 	g_signal_connect(G_OBJECT(viewer->scrollwin),
2073 				    "scroll-event",
2074 				    G_CALLBACK(pdf_viewer_scroll_cb),
2075 				   (gpointer) viewer);
2076 	g_signal_connect(G_OBJECT(viewer->pdf_view_ebox),
2077 				    "button_press_event",
2078 				    G_CALLBACK(pdf_viewer_button_press_events_cb),
2079 				   (gpointer) viewer);
2080 	g_signal_connect(G_OBJECT(viewer->pdf_view_ebox),
2081 				    "button_release_event",
2082 				    G_CALLBACK(pdf_viewer_mouse_scroll_destroy_cb),
2083 				   (gpointer) viewer);
2084 	g_signal_connect(G_OBJECT(viewer->pdf_view_ebox),
2085 				    "motion_notify_event",
2086 				    G_CALLBACK(pdf_viewer_move_events_cb),
2087 				   (gpointer) viewer);
2088 
2089 	viewer->target_filename = NULL;
2090 	viewer->filename = NULL;
2091 	viewer->fsname = NULL;
2092 
2093 	return(MimeViewer *) viewer;
2094 }
2095 
2096 #undef ADD_BUTTON_TO_TABLE
2097 #undef ADD_TOGGLE_BUTTON_TO_TABLE
2098 #undef ADD_SEP_TO_TABLE
2099 #undef BUTTON_H_PADDING
2100 #undef SEP_H_PADDING
2101 
2102 static MimeViewerFactory pdf_viewer_factory =
2103 {
2104 	content_types,
2105 	0,
2106 	pdf_viewer_create,
2107 };
2108 
plugin_init(gchar ** error)2109 gint plugin_init(gchar **error)
2110 {
2111 	gchar *gspath = NULL;
2112 
2113 	msg = g_strdup_printf(_("This plugin enables the viewing of PDF and PostScript "
2114 				"attachments using the Poppler %s Lib and the gs tool.\n\n"
2115 				"Any feedback is welcome: iwkse@claws-mail.org"
2116 				), poppler_get_version());
2117 
2118 	if (!check_plugin_version(MAKE_NUMERIC_VERSION(3,8,1,46),
2119 		    VERSION_NUMERIC, _("PDF Viewer"), error)) return -1;
2120 
2121 	if ((gspath = g_find_program_in_path("gs")) == NULL) {
2122 		gchar *pmsg = msg;
2123 		msg = g_strdup_printf(_("Warning: could not find ghostscript binary (gs) required "
2124 					"for %s plugin to process PostScript attachments, only PDF "
2125 					"attachments will be displayed. To enable PostScript "
2126 					"support please install gs program.\n\n%s"
2127 					), _("PDF Viewer"), pmsg);
2128 		g_free(pmsg);
2129 	}
2130 	else {
2131 		g_free(gspath);
2132 	}
2133 
2134 	mimeview_register_viewer_factory(&pdf_viewer_factory);
2135 	return 0;
2136 }
2137 
plugin_done(void)2138 gboolean plugin_done(void)
2139 {
2140 	g_free(msg);
2141 	mimeview_unregister_viewer_factory(&pdf_viewer_factory);
2142 	return TRUE;
2143 }
2144 
plugin_name(void)2145 const gchar *plugin_name(void)
2146 {
2147 	return _("PDF Viewer");
2148 }
2149 
plugin_desc(void)2150 const gchar *plugin_desc(void)
2151 {
2152 	return msg;
2153 }
2154 
plugin_type(void)2155 const gchar *plugin_type(void)
2156 {
2157 	return "GTK2";
2158 }
2159 
plugin_licence(void)2160 const gchar *plugin_licence(void)
2161 {
2162 	return "GPL3+";
2163 }
2164 
plugin_version(void)2165 const gchar *plugin_version(void)
2166 {
2167 	return VERSION;
2168 }
2169 
plugin_provides(void)2170 struct PluginFeature *plugin_provides(void)
2171 {
2172 	static struct PluginFeature features[] =
2173 		{ {PLUGIN_MIMEVIEWER, "application/pdf"},
2174 		  {PLUGIN_MIMEVIEWER, "application/postscript"},
2175 		  {PLUGIN_NOTHING, NULL} };
2176 	return features;
2177 }
2178 
2179