2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright(C) 1999-2007 the Claws Mail Team
4 * This file Copyright (C) 2007 Salvatore De Paolis
5 * <iwkse@claws-mail.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 *(at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include "claws-features.h"
28 #include <glib/gi18n.h>
30 #include "poppler_viewer.h"
32 #include "prefs_common.h"
33 #include "gtk/gtkutils.h"
34 #include "gtk/inputdialog.h"
36 #ifndef POPPLER_WITH_GDK
40 static FileType pdf_viewer_mimepart_get_type(MimeInfo *partinfo);
41 static MimeViewerFactory pdf_viewer_factory;
43 static void pdf_viewer_show_mimepart(MimeViewer *_viewer, const gchar *infile,
46 static MimeViewer *pdf_viewer_create(void);
47 static void pdf_viewer_clear(MimeViewer *_viewer);
48 static void pdf_viewer_destroy(MimeViewer *_viewer);
49 static void pdf_viewer_update(MimeViewer *_viewer, gboolean reload_file, int page_num);
51 static GtkWidget *pdf_viewer_get_widget(MimeViewer *_viewer);
53 static void pdf_viewer_hide_index_pane(PdfViewer *viewer);
54 static void pdf_viewer_set_index_button_sensitive(PdfViewer *viewer);
55 static void pdf_viewer_scroll_to(PdfViewer *viewer, gfloat x, gfloat y);
57 static void search_matches_free(PdfViewer *viewer);
58 static gboolean pdf_viewer_text_search(MimeViewer *_viewer, gboolean backward,
59 const gchar *str, gboolean case_sens);
60 static void pdf_viewer_render_selection(PdfViewer *viewer, PopplerRectangle *rect, PageResult *page_results);
61 static void pdf_viewer_render_page(PopplerPage *page, GtkWidget *view, double width, double height, double zoom, gint rotate);
63 static char * pdf_viewer_get_document_format_data(GTime utime);
64 static void pdf_viewer_get_document_index(PdfViewer *viewer, PopplerIndexIter *index_iter, GtkTreeIter *parentiter);
65 static void pdf_viewer_index_row_activated(GtkTreeView *tree_view,
67 GtkTreeViewColumn *column,
70 static GtkTable * pdf_viewer_fill_info_table(PdfViewer *viewer);
73 static void pdf_viewer_move_events_cb(GtkWidget *widget, GdkEventMotion *event, PdfViewer *viewer);
74 static void pdf_viewer_button_press_events_cb(GtkWidget *widget, GdkEventButton *event, PdfViewer *viewer);
75 static void pdf_viewer_mouse_scroll_destroy_cb(GtkWidget *widget, GdkEventButton *event, PdfViewer *viewer);
76 static void pdf_viewer_button_first_page_cb(GtkButton *button, PdfViewer *viewer);
77 static void pdf_viewer_button_last_page_cb(GtkButton *button, PdfViewer *viewer);
78 static void pdf_viewer_button_zoom_in_cb(GtkButton *button, PdfViewer *viewer);
79 static void pdf_viewer_button_zoom_out_cb(GtkButton *button, PdfViewer *viewer);
80 static void pdf_viewer_button_zoom_fit_cb(GtkButton *button, PdfViewer *viewer);
81 static void pdf_viewer_button_zoom_width_cb(GtkButton *button, PdfViewer *viewer);
82 static void pdf_viewer_button_rotate_right_cb(GtkButton *button, PdfViewer *viewer);
83 static void pdf_viewer_button_rotate_left_cb(GtkButton *button, PdfViewer *viewer);
84 static void pdf_viewer_spin_change_page_cb(GtkSpinButton *button, PdfViewer *viewer);
85 static void pdf_viewer_spin_zoom_scroll_cb(GtkSpinButton *button, PdfViewer *viewer);
86 /* Show/Hide the index pane */
87 static void pdf_viewer_show_document_index_cb(GtkButton *button, PdfViewer *viewer);
88 static void pdf_viewer_button_document_info_cb(GtkButton *button, PdfViewer *viewer);
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);
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);
103 #ifndef POPPLER_WITH_GDK
105 copy_cairo_surface_to_pixbuf (cairo_surface_t *surface,
108 int cairo_width, cairo_height, cairo_rowstride;
109 unsigned char *pixbuf_data, *dst, *cairo_data;
110 int pixbuf_rowstride, pixbuf_n_channels;
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);
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);
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;
142 _poppler_page_render_to_pixbuf (PopplerPage *page,
143 int src_x, int src_y,
144 int src_width, int src_height,
151 cairo_surface_t *surface;
153 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
154 src_width, src_height);
155 cr = cairo_create (surface);
159 cairo_translate (cr, src_x + src_width, -src_y);
162 cairo_translate (cr, src_x + src_width, src_y + src_height);
165 cairo_translate (cr, -src_x, src_y + src_height);
168 cairo_translate (cr, -src_x, -src_y);
172 cairo_scale (cr, scale, scale);
175 cairo_rotate (cr, rotation * G_PI / 180.0);
178 poppler_page_render_for_printing (page, cr);
180 poppler_page_render (page, cr);
183 cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER);
184 cairo_set_source_rgb (cr, 1., 1., 1.);
189 copy_cairo_surface_to_pixbuf (surface, pixbuf);
190 cairo_surface_destroy (surface);
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
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
214 poppler_page_render_to_pixbuf (PopplerPage *page,
215 int src_x, int src_y,
216 int src_width, int src_height,
221 g_return_if_fail (POPPLER_IS_PAGE (page));
222 g_return_if_fail (scale > 0.0);
223 g_return_if_fail (pixbuf != NULL);
225 _poppler_page_render_to_pixbuf (page, src_x, src_y,
226 src_width, src_height,
232 static GtkWidget *pdf_viewer_get_widget(MimeViewer *_viewer)
234 PdfViewer *viewer = (PdfViewer *) _viewer;
235 debug_print("pdf_viewer_get_widget: %p\n", viewer->vbox);
237 return GTK_WIDGET(viewer->vbox);
239 /** Hide the index panel */
240 static void pdf_viewer_hide_index_pane(PdfViewer *viewer)
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));
249 static void search_matches_free(PdfViewer *viewer)
252 for(cur = viewer->text_found; cur; cur = cur->next) {
253 PageResult *res = (PageResult *)cur->data;
254 g_list_free(res->results);
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,
266 gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer->cur_page)));
270 static void pdf_viewer_scroll_to(PdfViewer *viewer, gfloat x, gfloat y)
274 vadj = gtk_scrolled_window_get_vadjustment(
275 GTK_SCROLLED_WINDOW(viewer->scrollwin));
277 if (y < vadj->value) {
281 while(y > vadj->value + vadj->page_size) {
282 vadj->value += vadj->page_size;
286 hadj = gtk_scrolled_window_get_hadjustment(
287 GTK_SCROLLED_WINDOW(viewer->scrollwin));
289 if (x < hadj->value) {
293 while(x > hadj->value + hadj->page_size) {
294 hadj->value += hadj->page_size;
298 g_signal_emit_by_name(G_OBJECT(hadj), "value-changed", 0);
299 g_signal_emit_by_name(G_OBJECT(vadj), "value-changed", 0);
301 static void pdf_viewer_render_page(PopplerPage *page, GtkWidget *view, double width,
302 double height, double zoom, gint rotate)
306 debug_print("width: %f\n", width);
307 pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
310 (int)(height * zoom));
312 poppler_page_render_to_pixbuf(page, 0, 0,
314 (int)(height * zoom),
317 gtk_image_set_from_pixbuf(GTK_IMAGE(view), pb);
318 g_object_unref(G_OBJECT(pb));
320 static void pdf_viewer_render_selection(PdfViewer *viewer, PopplerRectangle *rect, PageResult *page_results)
323 double width_points, height_points;
325 GdkPixbuf *sel_pb, *page_pb;
326 gfloat x1, x2, y1, y2;
330 gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer->cur_page));
332 viewer->last_match = viewer->res_cnt;
334 viewer->last_rect = NULL;
335 viewer->last_page_result = NULL;
336 if (cur_page_num != page_results->page_num) {
337 /* we changed page. update the view */
338 gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer->cur_page),
339 (gdouble) page_results->page_num);
342 viewer->last_rect = rect;
343 viewer->last_page_result = page_results;
347 poppler_page_get_size(POPPLER_PAGE(viewer->pdf_page), &width_points, &height_points);
348 width = (int)((width_points * viewer->zoom) + 0.5);
349 height = (int)((height_points * viewer->zoom) + 0.5);
351 if (viewer->rotate == 90) {
352 x1 = MIN(rect->y1,rect->y2) * viewer->zoom;
353 x2 = MAX(rect->y1,rect->y2) * viewer->zoom;
354 y1 = MAX(rect->x1,rect->x2) * viewer->zoom;
355 y2 = MIN(rect->x1,rect->x2) * viewer->zoom;
359 } else if (viewer->rotate == 180) {
360 x1 = width - rect->x2 * viewer->zoom;
361 x2 = width - rect->x1 * viewer->zoom;
362 y1 = height - rect->y2 * viewer->zoom;
363 y2 = height - rect->y1 * viewer->zoom;
369 } else if (viewer->rotate == 270) {
370 x1 = height - MAX(rect->y1,rect->y2) * viewer->zoom;
371 x2 = height - MIN(rect->y1,rect->y2) * viewer->zoom;
372 y1 = width - MIN(rect->x1,rect->x2) * viewer->zoom;
373 y2 = width - MAX(rect->x1,rect->x2) * viewer->zoom;
377 x1 = rect->x1 * viewer->zoom;
378 x2 = rect->x2 * viewer->zoom;
379 y1 = rect->y1 * viewer->zoom;
380 y2 = rect->y2 * viewer->zoom;
387 sel_pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
390 gdk_pixbuf_fill(sel_pb, SELECTION_COLOR);
392 page_pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
394 (int)(viewer->width * viewer->zoom),
395 (int)(viewer->height * viewer->zoom));
397 poppler_page_render_to_pixbuf(viewer->pdf_page,
400 (int)(viewer->width * viewer->zoom),
401 (int)(viewer->height * viewer->zoom),
406 gdk_pixbuf_composite(sel_pb, page_pb,
407 x1, y2, selw, selh, 0, 0,
408 viewer->zoom, viewer->zoom,
409 GDK_INTERP_BILINEAR, ALPHA_CHANNEL);
411 gtk_image_set_from_pixbuf(GTK_IMAGE(viewer->pdf_view), page_pb);
413 pdf_viewer_scroll_to(viewer, MIN(x1,x2), MIN(y1,y2));
415 g_object_unref(G_OBJECT(sel_pb));
416 g_object_unref(G_OBJECT(page_pb));
420 static gboolean pdf_viewer_text_search(MimeViewer *_viewer, gboolean backward,
421 const gchar *str, gboolean case_sens)
423 PdfViewer *viewer = (PdfViewer *)_viewer;
424 GList *all_pages_results, *cur_page_results;
427 debug_print("pdf_viewer_text_search: %s\n", str);
428 main_window_cursor_wait(mainwindow_get_mainwindow());
430 if (viewer->last_search && strcmp(str, viewer->last_search)) {
431 search_matches_free(viewer);
432 viewer->last_match = -1;
433 viewer->num_matches = 0;
434 } else if (!viewer->last_search) {
435 viewer->last_match = -1;
436 viewer->num_matches = 0;
438 /* It's a new search, build list of matches
439 * across all pages */
440 if (viewer->last_match == -1) {
443 for(i = 1; i <= viewer->num_pages; i++) {
445 PopplerPage *pdf_page = poppler_document_get_page(viewer->pdf_doc, i - 1);
446 viewer->page_results = poppler_page_find_text(pdf_page, str);
448 if (viewer->page_results != NULL) {
449 debug_print("page_results %p\n", viewer->page_results);
450 /* store results for this page */
452 PageResult *res = g_new0(PageResult, 1);
453 res->results = viewer->page_results;
455 /* found text, prepend this page(faster than append) */
456 viewer->text_found = g_list_prepend(viewer->text_found, res);
457 num_res = g_list_length(viewer->page_results);
458 debug_print("%d results on page %d\n", num_res, i);
459 viewer->num_matches += num_res;
461 g_object_unref(G_OBJECT(pdf_page));
464 if (viewer->text_found == NULL) {
465 main_window_cursor_normal(mainwindow_get_mainwindow());
468 /* put back the list in the correct order */
469 viewer->text_found = g_list_reverse(viewer->text_found);
472 if (!viewer->text_found) {
473 main_window_cursor_normal(mainwindow_get_mainwindow());
476 viewer->last_search = g_strdup(str);
480 /* if backward, we have to initialize stuff to search
482 viewer->res_cnt = viewer->num_matches-1;
483 if (viewer->last_match == -1) {
484 viewer->last_match = viewer->num_matches+1;
486 all_pages_results = g_list_last(viewer->text_found);
489 all_pages_results = viewer->text_found;
492 for(; all_pages_results; all_pages_results = (backward?all_pages_results->prev:all_pages_results->next)) {
494 PageResult * page_results = (PageResult *)all_pages_results->data;
497 cur_page_results = g_list_last(page_results->results);
500 cur_page_results = page_results->results;
503 for(; cur_page_results; cur_page_results = (backward?cur_page_results->prev:cur_page_results->next)) {
505 gboolean valid = FALSE;
506 /* first valid result is the last+1 if searching
507 * forward, last-1 if searching backward */
509 valid = (viewer->res_cnt < viewer->last_match);
512 valid = (viewer->res_cnt > viewer->last_match);
515 pdf_viewer_render_selection(viewer,
516 (PopplerRectangle *)cur_page_results->data,
518 main_window_cursor_normal(mainwindow_get_mainwindow());
530 main_window_cursor_normal(mainwindow_get_mainwindow());
531 search_matches_free(viewer);
535 static void pdf_viewer_get_document_index(PdfViewer *viewer, PopplerIndexIter *index_iter, GtkTreeIter *parentiter)
537 PopplerAction *action;
538 PopplerIndexIter *child;
539 GtkTreeIter childiter;
541 debug_print("get document index\n");
545 action = poppler_index_iter_get_action(index_iter);
547 if (action->type != POPPLER_ACTION_GOTO_DEST) {
548 poppler_action_free(action);
552 if (action->goto_dest.dest->type == POPPLER_DEST_XYZ || action->goto_dest.dest->type == POPPLER_DEST_FITH) {
553 page_num = action->goto_dest.dest->page_num;
555 #ifdef HAVE_POPPLER_DEST_NAMED
556 else if (action->goto_dest.dest->type == POPPLER_DEST_NAMED) {
557 PopplerDest *dest = poppler_document_find_dest(
558 viewer->pdf_doc, action->goto_dest.dest->named_dest);
559 if (dest->type != POPPLER_DEST_XYZ) {
560 g_warning("couldn't figure out link");
561 poppler_dest_free(dest);
564 page_num = dest->page_num;
565 poppler_dest_free(dest);
569 #ifdef HAVE_POPPLER_DEST_NAMED
570 g_warning("unhandled link type %d. please contact developers", action->goto_dest.dest->type);
572 g_warning("unhandled link type %d. please upgrade libpoppler-glib to 0.5.4", action->goto_dest.dest->type);
576 gtk_tree_store_append(GTK_TREE_STORE(viewer->index_model), &childiter, parentiter);
577 gtk_tree_store_set(GTK_TREE_STORE(viewer->index_model), &childiter,
578 INDEX_NAME, action->named.title,
579 INDEX_PAGE, page_num,
580 INDEX_TOP, action->goto_dest.dest->top,
582 poppler_action_free(action);
583 child = poppler_index_iter_get_child(index_iter);
585 pdf_viewer_get_document_index(viewer, child, &childiter);
586 poppler_index_iter_free(child);
589 while(poppler_index_iter_next(index_iter));
592 static void pdf_viewer_index_row_activated(GtkTreeView *tree_view,
594 GtkTreeViewColumn *column,
598 GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
599 PdfViewer *viewer = (PdfViewer *)data;
602 debug_print("index_row_activated\n");
603 if (!gtk_tree_model_get_iter(model, &iter, path)) return;
605 gtk_tree_model_get(model, &iter,
606 INDEX_PAGE, &page_num,
610 gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer->cur_page),(gdouble)page_num);
611 debug_print("Page num: %d\n", page_num);
616 /** Disable the index button if the document doesn't have an index */
617 static void pdf_viewer_set_index_button_sensitive(PdfViewer *viewer)
619 viewer->pdf_index = poppler_index_iter_new(viewer->pdf_doc);
620 if (viewer->pdf_index) {
621 if (!gtk_widget_is_sensitive(viewer->doc_index)) {
622 gtk_widget_set_sensitive(viewer->doc_index, TRUE);
626 gtk_widget_set_sensitive(viewer->doc_index, FALSE);
629 poppler_index_iter_free(viewer->pdf_index);
630 viewer->pdf_index = NULL;
633 static char * pdf_viewer_get_document_format_data(GTime utime)
635 time_t time = (time_t) utime;
638 const char *fmt_hack = "%c";
641 if (time == 0 || !localtime_r(&time, &t)) return NULL;
643 len = strftime(s, sizeof(s), fmt_hack, &t);
645 if (len == 0 || s[0] == '\0') return NULL;
647 return g_locale_to_utf8(s, -1, NULL, NULL, NULL);
650 #define ADD_TO_TABLE(LABEL, VALUE) \
651 label = gtk_label_new(LABEL); \
652 gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); \
653 gtk_misc_set_padding(GTK_MISC(label), 4, 0); \
654 gtk_table_attach(viewer->table_doc_info, label, 0, 1, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0); \
656 label = gtk_label_new(VALUE); \
657 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); \
658 gtk_misc_set_padding(GTK_MISC(label), 4, 0); \
659 gtk_table_attach(viewer->table_doc_info, label, 1, 2, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0); \
663 static GtkTable * pdf_viewer_fill_info_table(PdfViewer *viewer)
666 const gchar *title, *format, *author, *subject, *keywords, *creator, *producer;
671 GTime creation_date, mod_date;
673 PopplerPageLayout layout;
674 PopplerPageMode mode;
675 PopplerPermissions permissions;
676 PopplerViewerPreferences view_prefs;
678 title = format = author = subject = keywords = creator = producer = tmp = 0;
680 g_object_get(viewer->pdf_doc,
685 "keywords", &keywords,
686 "creation-date", &creation_date,
687 "permissions", &permissions,
688 "mod-date", &mod_date,
690 "producer", &producer,
691 "linearized", &linearized,
693 "page-layout", &layout,
694 "viewer-preferences", &view_prefs,
697 viewer->table_doc_info = GTK_TABLE(gtk_table_new(13, 2, FALSE));
699 ADD_TO_TABLE(_("Filename:"), viewer->target_filename)
700 ADD_TO_TABLE(_("Size:"), to_human_readable(viewer->to_load->length))
701 ADD_TO_TABLE(NULL, NULL)
702 ADD_TO_TABLE(_("Title:"), title)
703 ADD_TO_TABLE(_("Subject:"), subject)
704 ADD_TO_TABLE(_("Author:"), author)
705 ADD_TO_TABLE(_("Keywords:"), keywords)
706 ADD_TO_TABLE(_("Creator:"), creator)
707 ADD_TO_TABLE(_("Producer:"), producer)
709 tmp = pdf_viewer_get_document_format_data(creation_date);
710 ADD_TO_TABLE(_("Created:"), tmp)
713 tmp = pdf_viewer_get_document_format_data(mod_date);
714 ADD_TO_TABLE(_("Modified:"), tmp)
717 ADD_TO_TABLE(_("Format:"), format)
719 ADD_TO_TABLE(_("Optimized:"), _("Yes"))
722 ADD_TO_TABLE(_("Optimized:"), _("No"))
724 //ADD_TO_TABLE(_("Page Mode:"), pdf_viewer_get_document_info_mode(mode))
725 //ADD_TO_TABLE(_("Page Layout:"), pdf_viewer_get_document_info_layout(layout))
727 return(GtkTable *) viewer->table_doc_info;
731 static FileType pdf_viewer_mimepart_get_type(MimeInfo *partinfo)
733 gchar *content_type = NULL;
734 FileType type = TYPE_UNKNOWN;
735 debug_print("mimepart_get_type\n");
736 if ((partinfo->type == MIMETYPE_APPLICATION) &&
737 (!g_ascii_strcasecmp(partinfo->subtype, "octet-stream"))) {
739 const gchar *filename;
741 filename = procmime_mimeinfo_get_parameter(partinfo, "filename");
743 if (filename == NULL)
744 filename = procmime_mimeinfo_get_parameter(partinfo, "name");
745 if (filename != NULL)
746 content_type = procmime_get_mime_type(filename);
749 content_type = procmime_get_content_type_str(partinfo->type, partinfo->subtype);
752 if (content_type == NULL) type = TYPE_UNKNOWN;
753 else if (!strcmp(content_type, "application/pdf")) type = TYPE_PDF;
754 else if (!strcmp(content_type, "application/postscript")) type = TYPE_PS;
755 else type = TYPE_UNKNOWN;
757 g_free(content_type);
762 static void pdf_viewer_button_first_page_cb(GtkButton *button, PdfViewer *viewer)
765 gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->cur_page), GTK_SPIN_HOME, 1);
768 static void pdf_viewer_button_prev_page_cb(GtkButton *button, PdfViewer *viewer)
771 gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->cur_page), GTK_SPIN_STEP_BACKWARD, 1);
774 static void pdf_viewer_button_next_page_cb(GtkButton *button, PdfViewer *viewer)
777 gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->cur_page), GTK_SPIN_STEP_FORWARD, 1);
780 static void pdf_viewer_button_last_page_cb(GtkButton *button, PdfViewer *viewer)
783 gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->cur_page), GTK_SPIN_END, 1);
786 static void pdf_viewer_spin_change_page_cb(GtkSpinButton *button, PdfViewer *viewer)
788 pdf_viewer_update((MimeViewer *)viewer,
790 gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer->cur_page)));
793 static void pdf_viewer_button_zoom_in_cb(GtkButton *button, PdfViewer *viewer)
796 gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->zoom_scroll), GTK_SPIN_STEP_FORWARD, ZOOM_FACTOR);
799 static void pdf_viewer_spin_zoom_scroll_cb(GtkSpinButton *button, PdfViewer *viewer)
801 viewer->zoom = gtk_spin_button_get_value(GTK_SPIN_BUTTON(viewer->zoom_scroll));
802 pdf_viewer_update((MimeViewer *)viewer,
804 gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer->cur_page)));
807 static void pdf_viewer_button_zoom_out_cb(GtkButton *button, PdfViewer *viewer)
810 gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->zoom_scroll), GTK_SPIN_STEP_BACKWARD, ZOOM_FACTOR);
814 static void pdf_viewer_button_press_events_cb(GtkWidget *widget, GdkEventButton *event, PdfViewer *viewer)
817 #ifdef HAVE_POPPLER_DEST_NAMED
820 static GdkCursor *hand_cur = NULL;
822 if (!hand_cur) hand_cur = gdk_cursor_new(GDK_FLEUR);
824 /* Execute Poppler Links */
825 if (event->button == 1 && viewer->in_link) {
826 switch (viewer->link_action->type) {
827 case POPPLER_ACTION_UNKNOWN:
828 debug_print("action unknown\n");
830 case POPPLER_ACTION_GOTO_DEST:
831 if (viewer->link_action->goto_dest.dest->type == POPPLER_DEST_XYZ ||
832 viewer->link_action->goto_dest.dest->type == POPPLER_DEST_FITH) {
833 gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer->cur_page),
834 (gdouble)viewer->link_action->goto_dest.dest->page_num);
836 #ifdef HAVE_POPPLER_DEST_NAMED
837 else if (viewer->link_action->goto_dest.dest->type == POPPLER_DEST_NAMED) {
838 dest = poppler_document_find_dest(
839 viewer->pdf_doc, viewer->link_action->goto_dest.dest->named_dest);
840 if (dest->type != POPPLER_DEST_XYZ) {
841 g_warning("couldn't figure out link");
842 poppler_dest_free(dest);
845 gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer->cur_page),
846 (gdouble)dest->page_num);
847 poppler_dest_free(dest);
851 case POPPLER_ACTION_GOTO_REMOTE:
852 #ifdef HAVE_POPPLER_DEST_NAMED
853 dest = poppler_document_find_dest(
854 viewer->pdf_doc, viewer->link_action->goto_remote.dest->named_dest);
855 if (dest->type != POPPLER_DEST_XYZ) {
856 g_warning ("couldn't figure out link");
857 poppler_dest_free(dest);
860 gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer->cur_page),
861 (gdouble)dest->page_num);
862 poppler_dest_free(dest);
865 case POPPLER_ACTION_LAUNCH:
866 debug_print("action launch not yet implemented\n");
868 case POPPLER_ACTION_URI:
869 uri = g_strdup(viewer->link_action->uri.uri);
870 if (!g_ascii_strncasecmp(uri, "mailto:", 7))
871 compose_new(NULL, uri + 7, NULL);
873 open_uri(uri, prefs_common_get_uri_cmd());
876 case POPPLER_ACTION_NAMED:
877 debug_print("action named not yet implemented\n");
879 case POPPLER_ACTION_NONE:
880 debug_print("action none does nothing, surprise!\n");
882 #if POPPLER_CHECK_VERSION(0,14,0)
883 case POPPLER_ACTION_MOVIE:
884 debug_print("yoyoyo ;-) a movie?\n");
886 case POPPLER_ACTION_RENDITION:
887 debug_print("yoyoyo ;-) multimedia?\n");
889 case POPPLER_ACTION_OCG_STATE:
890 debug_print("yoyoyo ;-) layer state?\n");
892 #if POPPLER_CHECK_VERSION(0,18,0)
893 case POPPLER_ACTION_JAVASCRIPT:
894 debug_print("yoyoyo ;-) javascript?\n");
899 if (((MimeViewer *)viewer)->mimeview &&
900 ((MimeViewer *)viewer)->mimeview->messageview &&
901 ((MimeViewer *)viewer)->mimeview->messageview->window &&
902 ((MimeViewer *)viewer)->mimeview->messageview->window->window)
903 gdk_window_set_cursor (((MimeViewer *)viewer)->mimeview->messageview->window->window, NULL);
905 gdk_window_set_cursor (mainwindow_get_mainwindow()->window->window, NULL);
908 /* Init document to be scrolled with left mouse click */
909 if (event->button == 1 && !viewer->in_link) {
910 viewer->pdf_view_scroll = TRUE;
911 if (((MimeViewer *)viewer)->mimeview &&
912 ((MimeViewer *)viewer)->mimeview->messageview &&
913 ((MimeViewer *)viewer)->mimeview->messageview->window &&
914 ((MimeViewer *)viewer)->mimeview->messageview->window->window)
915 gdk_window_set_cursor (((MimeViewer *)viewer)->mimeview->messageview->window->window, hand_cur);
917 gdk_window_set_cursor (mainwindow_get_mainwindow()->window->window, hand_cur);
919 viewer->last_x = event->x;
920 viewer->last_y = event->y;
921 viewer->last_dir_x = 0;
922 viewer->last_dir_y = 0;
925 /* Set the normal cursor*/
926 static void pdf_viewer_mouse_scroll_destroy_cb(GtkWidget *widget, GdkEventButton *event, PdfViewer *viewer)
929 if (event->button == 1) {
930 viewer->pdf_view_scroll = FALSE;
931 if (((MimeViewer *)viewer)->mimeview &&
932 ((MimeViewer *)viewer)->mimeview->messageview &&
933 ((MimeViewer *)viewer)->mimeview->messageview->window &&
934 ((MimeViewer *)viewer)->mimeview->messageview->window->window)
935 gdk_window_set_cursor (((MimeViewer *)viewer)->mimeview->messageview->window->window, NULL);
937 gdk_window_set_cursor (mainwindow_get_mainwindow()->window->window, NULL);
941 static void pdf_viewer_move_events_cb(GtkWidget *widget, GdkEventMotion *event, PdfViewer *viewer)
943 /* Grab the document and scroll it with mouse */
944 if (viewer->pdf_view_scroll) {
946 viewer->pdf_view_vadj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(viewer->scrollwin));
947 viewer->pdf_view_hadj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(viewer->scrollwin));
949 if (event->x < viewer->last_x
950 && viewer->pdf_view_hadj->value < (viewer->pdf_view_hadj->upper - viewer->pdf_view_hadj->page_size)) {
951 if (viewer->last_dir_x == -1) {
952 viewer->pdf_view_hadj->value += viewer->last_x - event->x;
953 g_signal_emit_by_name(G_OBJECT(viewer->pdf_view_hadj),
956 viewer->last_dir_x = -1;
958 else if (event->x > viewer->last_x
959 && viewer->pdf_view_hadj->value > 0.0) {
960 if (viewer->last_dir_x == +1) {
961 viewer->pdf_view_hadj->value += viewer->last_x - event->x;
962 g_signal_emit_by_name(G_OBJECT(viewer->pdf_view_hadj),
965 viewer->last_dir_x = +1;
968 if (event->y < viewer->last_y
969 && viewer->pdf_view_vadj->value < (viewer->pdf_view_vadj->upper - viewer->pdf_view_vadj->page_size)) {
970 if (viewer->last_dir_y == -1) {
971 viewer->pdf_view_vadj->value += viewer->last_y - event->y;
972 g_signal_emit_by_name(G_OBJECT(viewer->pdf_view_vadj),
975 viewer->last_dir_y = -1;
977 else if (event->y > viewer->last_y
978 && viewer->pdf_view_vadj->value > 0.0) {
979 if (viewer->last_dir_y == +1) {
980 viewer->pdf_view_vadj->value += viewer->last_y - event->y;
981 g_signal_emit_by_name(G_OBJECT(viewer->pdf_view_vadj),
984 viewer->last_dir_y = +1;
986 viewer->last_x = event->x;
987 viewer->last_y = event->y;
993 static GdkCursor *link_cur = NULL;
994 static GtkRequisition size;
995 static gdouble x,y, x1, y1, x2, y2;
998 viewer->pdf_view_vadj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(viewer->scrollwin));
999 viewer->pdf_view_hadj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(viewer->scrollwin));
1001 if (!link_cur) link_cur = gdk_cursor_new(GDK_HAND2);
1004 viewer->in_link = FALSE;
1005 for (l = viewer->link_map; l; l = g_list_next (l)) {
1006 PopplerLinkMapping *lmapping;
1007 lmapping = (PopplerLinkMapping *)l->data;
1009 x1 = lmapping->area.x1;
1010 y1 = lmapping->area.y1;
1011 x2 = lmapping->area.x2;
1012 y2 = lmapping->area.y2;
1013 gtk_widget_size_request(viewer->pdf_view, &size);
1015 switch (viewer->rotate) {
1018 if (size.width != viewer->pdf_view_hadj->upper)
1019 x = (event->x - (viewer->pdf_view_hadj->upper - size.width) / 2) / viewer->zoom;
1021 x = event->x / viewer->zoom;
1023 y = (viewer->pdf_view_vadj->upper - event->y) / viewer->zoom;
1026 if (size.width != viewer->pdf_view_hadj->upper)
1027 y = (event->x - (viewer->pdf_view_hadj->upper - size.width) / 2) / viewer->zoom;
1029 y = event->x / viewer->zoom;
1031 x = (event->y) / viewer->zoom;
1034 if (size.width != viewer->pdf_view_hadj->upper)
1035 x = ((viewer->pdf_view_hadj->upper - event->x) - ((viewer->pdf_view_hadj->upper - size.width) / 2)) / viewer->zoom;
1037 x = ((viewer->pdf_view_hadj->upper - event->x) - (viewer->pdf_view_hadj->upper - size.width)) / viewer->zoom;
1039 y = (event->y) / viewer->zoom;
1042 if (size.width != viewer->pdf_view_hadj->upper)
1043 y = ((viewer->pdf_view_hadj->upper - event->x) - ((viewer->pdf_view_hadj->upper - size.width) / 2)) / viewer->zoom;
1045 y = ((viewer->pdf_view_hadj->upper - event->x) - (viewer->pdf_view_hadj->upper - size.width)) / viewer->zoom;
1047 x = (viewer->pdf_view_vadj->upper - event->y) / viewer->zoom;
1051 if ( (x > x1 && x < x2) && (y > y1 && y < y2) ) {
1052 viewer->in_link = TRUE;
1053 if (((MimeViewer *)viewer)->mimeview &&
1054 ((MimeViewer *)viewer)->mimeview->messageview &&
1055 ((MimeViewer *)viewer)->mimeview->messageview->window &&
1056 ((MimeViewer *)viewer)->mimeview->messageview->window->window)
1057 gdk_window_set_cursor (((MimeViewer *)viewer)->mimeview->messageview->window->window, link_cur);
1059 gdk_window_set_cursor (mainwindow_get_mainwindow()->window->window, link_cur);
1061 viewer->link_action = lmapping->action;
1065 if (((MimeViewer *)viewer)->mimeview &&
1066 ((MimeViewer *)viewer)->mimeview->messageview &&
1067 ((MimeViewer *)viewer)->mimeview->messageview->window &&
1068 ((MimeViewer *)viewer)->mimeview->messageview->window->window)
1069 gdk_window_set_cursor (((MimeViewer *)viewer)->mimeview->messageview->window->window, NULL);
1071 gdk_window_set_cursor (mainwindow_get_mainwindow()->window->window, NULL);
1077 static gboolean pdf_viewer_scroll_cb(GtkWidget *widget, GdkEventScroll *event,
1080 GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(viewer->scrollwin));
1081 static gboolean in_scroll_cb = FALSE;
1082 gboolean handled = FALSE;
1083 gint cur_p = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer->cur_page));
1088 in_scroll_cb = TRUE;
1090 if (event->direction == GDK_SCROLL_UP &&
1091 adj->value == adj->lower &&
1093 gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->cur_page), GTK_SPIN_STEP_BACKWARD, 1);
1094 adj->value = adj->upper - adj->page_size;
1096 } else if (event->direction == GDK_SCROLL_DOWN &&
1097 adj->value + adj->page_size == adj->upper &&
1098 cur_p < viewer->num_pages) {
1099 gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->cur_page), GTK_SPIN_STEP_FORWARD, 1);
1103 in_scroll_cb = FALSE;
1107 static void pdf_viewer_button_zoom_fit_cb(GtkButton *button, PdfViewer *viewer)
1109 GtkAllocation *allocation;
1110 double xratio, yratio;
1111 allocation = &(viewer->scrollwin->allocation);
1112 debug_print("width: %d\n", allocation->width);
1113 debug_print("height: %d\n", allocation->height);
1114 xratio = allocation->width / viewer->width;
1115 yratio = allocation->height / viewer->height;
1117 if (xratio >= yratio) {
1118 viewer->zoom = yratio;
1119 gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer->zoom_scroll),viewer->zoom);
1122 viewer->zoom = xratio;
1123 gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer->zoom_scroll),viewer->zoom);
1127 static void pdf_viewer_button_zoom_width_cb(GtkButton *button, PdfViewer *viewer)
1129 GtkAllocation *allocation;
1131 allocation = &(viewer->scrollwin->allocation);
1132 debug_print("width: %d\n", allocation->width);
1133 xratio = allocation->width / viewer->width;
1134 gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer->zoom_scroll), xratio);
1137 static void pdf_viewer_button_rotate_right_cb(GtkButton *button, PdfViewer *viewer)
1139 if (viewer->rotate == 360) {
1143 viewer->rotate += (gint) ROTATION;
1144 pdf_viewer_update((MimeViewer *)viewer, FALSE,
1145 gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer->cur_page)));
1148 static void pdf_viewer_button_rotate_left_cb(GtkButton *button, PdfViewer *viewer)
1150 if (viewer->rotate == 0) {
1151 viewer->rotate = 360;
1154 viewer->rotate = abs(viewer->rotate -(gint) ROTATION);
1155 pdf_viewer_update((MimeViewer *)viewer, FALSE,
1156 gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer->cur_page)));
1159 /* Show/Hide the index pane */
1160 static void pdf_viewer_show_document_index_cb(GtkButton *button, PdfViewer *viewer)
1162 if (!viewer->pdf_index) {
1163 viewer->pdf_index = poppler_index_iter_new(viewer->pdf_doc);
1166 gtk_tree_store_clear(GTK_TREE_STORE(viewer->index_model));
1168 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(viewer->doc_index))) {
1169 pdf_viewer_get_document_index(viewer,(PopplerIndexIter *) viewer->pdf_index, NULL);
1170 gtk_widget_show(GTK_WIDGET(viewer->frame_index));
1173 pdf_viewer_hide_index_pane(viewer);
1178 static void pdf_viewer_button_document_info_cb(GtkButton *button, PdfViewer *viewer)
1180 alertpanel_full(_("PDF properties"), NULL, GTK_STOCK_CLOSE, NULL, NULL,
1181 FALSE, (GtkWidget *) pdf_viewer_fill_info_table(viewer),
1182 ALERT_NOTICE, G_ALERTDEFAULT);
1186 static const char * poppler_get_document_info_mode(PopplerPageMode mode)
1188 GEnumValue *enum_value;
1190 enum_value = g_enum_get_value((GEnumClass *) g_type_class_peek(POPPLER_TYPE_PAGE_MODE), mode);
1191 return(gchar *) enum_value->value_name;
1193 static const char * poppler_get_document_info_layout(PopplerPageLayout layout)
1196 GEnumValue *enum_value;
1198 enum_value = g_enum_get_value((GEnumClass *) g_type_class_peek(POPPLER_TYPE_PAGE_LAYOUT), layout);
1199 return(gchar *) enum_value->value_name;
1202 static void pdf_viewer_show_controls(PdfViewer *viewer, gboolean show)
1205 gtk_widget_show(viewer->first_page);
1206 gtk_widget_show(viewer->cur_page);
1207 gtk_widget_show(viewer->prev_page);
1208 gtk_widget_show(viewer->next_page);
1209 gtk_widget_show(viewer->last_page);
1210 gtk_widget_show(viewer->zoom_in);
1211 gtk_widget_show(viewer->zoom_out);
1212 gtk_widget_show(viewer->zoom_fit);
1213 gtk_widget_show(viewer->zoom_width);
1214 gtk_widget_show(viewer->zoom_scroll);
1215 gtk_widget_show(viewer->widgets_table);
1216 gtk_widget_show(viewer->rotate_right);
1217 gtk_widget_show(viewer->rotate_left);
1218 gtk_widget_show(viewer->doc_info);
1219 gtk_widget_show(viewer->doc_index);
1221 gtk_widget_hide(viewer->first_page);
1222 gtk_widget_hide(viewer->cur_page);
1223 gtk_widget_hide(viewer->prev_page);
1224 gtk_widget_hide(viewer->next_page);
1225 gtk_widget_hide(viewer->last_page);
1226 gtk_widget_hide(viewer->zoom_in);
1227 gtk_widget_hide(viewer->zoom_out);
1228 gtk_widget_hide(viewer->zoom_fit);
1229 gtk_widget_hide(viewer->zoom_width);
1230 gtk_widget_hide(viewer->widgets_table);
1231 gtk_widget_hide(viewer->rotate_right);
1232 gtk_widget_hide(viewer->rotate_left);
1233 gtk_widget_hide(viewer->doc_info);
1234 gtk_widget_hide(viewer->doc_index);
1235 gtk_widget_hide(viewer->zoom_scroll);
1238 /** Render the current page, page_num on the viewer */
1239 static void pdf_viewer_update(MimeViewer *_viewer, gboolean reload_file, int page_num)
1242 PdfViewer *viewer = (PdfViewer *) _viewer;
1243 GError *error = NULL;
1244 gchar *tmpfile = NULL;
1246 gchar *password = NULL;
1248 debug_print("pdf_viewer_update\n");
1251 if (viewer->pdf_doc) {
1252 g_object_unref(G_OBJECT(viewer->pdf_doc));
1253 viewer->pdf_doc = NULL;
1256 if (pdf_viewer_mimepart_get_type(viewer->to_load) == TYPE_PS) {
1257 stock_pixbuf_gdk(viewer->hbox,
1258 STOCK_PIXMAP_MIME_PS,
1259 &viewer->icon_pixbuf);
1260 gtk_image_set_from_pixbuf(GTK_IMAGE(viewer->icon_type),
1261 viewer->icon_pixbuf);
1263 else if (pdf_viewer_mimepart_get_type(viewer->to_load) == TYPE_PDF) {
1264 stock_pixbuf_gdk(viewer->hbox,
1265 STOCK_PIXMAP_MIME_PDF,
1266 &viewer->icon_pixbuf);
1267 gtk_image_set_from_pixbuf(GTK_IMAGE(viewer->icon_type),
1268 viewer->icon_pixbuf);
1271 stock_pixbuf_gdk(viewer->hbox,
1272 STOCK_PIXMAP_MIME_APPLICATION,
1273 &viewer->icon_pixbuf);
1274 gtk_image_set_from_pixbuf(GTK_IMAGE(viewer->icon_type),
1275 viewer->icon_pixbuf);
1278 gtk_label_set_text(GTK_LABEL(viewer->doc_label), _("Loading..."));
1279 pdf_viewer_show_controls(viewer, FALSE);
1280 main_window_cursor_wait(mainwindow_get_mainwindow());
1284 if (pdf_viewer_mimepart_get_type(viewer->to_load) == TYPE_PS) {
1285 gchar *cmdline = NULL, *tmp = NULL, *gspath = NULL;
1288 if ((gspath = g_find_program_in_path("gs")) != NULL) {
1290 /* convert postscript to pdf */
1291 tmpfile = get_tmp_file();
1292 cmdline = g_strdup_printf(
1293 "gs -dSAFER -dCompatibilityLevel=1.2 -q -dNOPAUSE -dBATCH "
1294 "-sDEVICE=pdfwrite -sOutputFile=%s -c .setpdfwrite -f \"%s\"",
1295 tmpfile, viewer->filename);
1296 result = execute_command_line(cmdline, FALSE);
1298 tmp = g_filename_to_uri(tmpfile, NULL, NULL);
1299 viewer->pdf_doc = poppler_document_new_from_file( tmp, NULL, &error);
1303 g_warning("gs conversion failed: %s returned %d", cmdline, result);
1304 tmp = g_strdup_printf("gs: err %d", result);
1305 alertpanel_warning("%s", tmp);
1310 claws_unlink(tmpfile);
1314 g_warning("gs conversion disabled: gs binary was not found");
1315 alertpanel_warning("PostScript view disabled: required gs program not found");
1320 main_window_cursor_normal(mainwindow_get_mainwindow());
1325 viewer->pdf_doc = poppler_document_new_from_file( viewer->fsname, NULL, &error);
1327 if (error && g_error_matches(error, POPPLER_ERROR, POPPLER_ERROR_ENCRYPTED)) {
1328 g_clear_error(&error);
1329 password = input_dialog_with_invisible(_("Enter password"),
1330 _("This document is locked and requires a password before it can be opened."),
1332 viewer->pdf_doc = poppler_document_new_from_file(viewer->fsname, password, &error);
1336 viewer->num_pages = poppler_document_get_n_pages(viewer->pdf_doc);
1338 g_signal_handlers_block_by_func(G_OBJECT(viewer->cur_page), pdf_viewer_spin_change_page_cb,(gpointer *)viewer);
1339 gtk_spin_button_set_range(GTK_SPIN_BUTTON(viewer->cur_page),
1341 (gdouble)viewer->num_pages );
1343 g_signal_handlers_unblock_by_func(G_OBJECT(viewer->cur_page), pdf_viewer_spin_change_page_cb,(gpointer *)viewer);
1344 gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->cur_page), GTK_SPIN_HOME, 1);
1345 tmp = g_strdup_printf(_("%s Document"),pdf_viewer_mimepart_get_type(viewer->to_load) == TYPE_PDF ? "PDF":"Postscript");
1347 GTK_WIDGET(viewer->icon_type_ebox),
1351 tmp = g_strdup_printf(_("of %d"), viewer->num_pages);
1352 gtk_label_set_text(GTK_LABEL(viewer->doc_label), tmp);
1355 pdf_viewer_show_controls(viewer, TRUE);
1356 main_window_cursor_normal(mainwindow_get_mainwindow());
1358 if (viewer->pdf_doc == NULL) {
1359 stock_pixbuf_gdk(viewer->hbox,
1360 STOCK_PIXMAP_MIME_APPLICATION,
1361 &viewer->icon_pixbuf);
1363 gtk_image_set_from_pixbuf(GTK_IMAGE(viewer->icon_type), viewer->icon_pixbuf);
1365 strretchomp(error->message);
1366 alertpanel_error("%s", error->message);
1368 alertpanel_error(_("PDF rendering failed for an unknown reason."));
1370 pdf_viewer_show_controls(viewer, FALSE);
1371 g_error_free(error);
1375 if (page_num == 1) {
1376 gtk_widget_set_sensitive(viewer->first_page, FALSE);
1377 gtk_widget_set_sensitive(viewer->prev_page, FALSE);
1380 gtk_widget_set_sensitive(viewer->first_page, TRUE);
1381 gtk_widget_set_sensitive(viewer->prev_page, TRUE);
1384 if (page_num == viewer->num_pages) {
1385 gtk_widget_set_sensitive(viewer->last_page, FALSE);
1386 gtk_widget_set_sensitive(viewer->next_page, FALSE);
1389 gtk_widget_set_sensitive(viewer->last_page, TRUE);
1390 gtk_widget_set_sensitive(viewer->next_page, TRUE);
1393 /* check for the index if exists */
1394 pdf_viewer_set_index_button_sensitive((PdfViewer *) viewer);
1396 if (page_num > 0 && page_num <= viewer->num_pages) {
1400 if (viewer->pdf_page) {
1401 g_object_unref(G_OBJECT(viewer->pdf_page));
1404 viewer->pdf_page = poppler_document_get_page(viewer->pdf_doc, page_num - 1);
1406 if (viewer->pdf_page == NULL) {
1407 g_warning("Page not found");
1411 if (viewer->rotate == 90 || viewer->rotate == 270) {
1412 poppler_page_get_size(viewer->pdf_page, &viewer->height, &viewer->width);
1415 poppler_page_get_size(viewer->pdf_page, &viewer->width, &viewer->height);
1418 if (viewer->last_rect && viewer->last_page_result &&
1419 viewer->last_page_result->page_num == page_num) {
1420 pdf_viewer_render_selection(viewer, viewer->last_rect, viewer->last_page_result);
1423 pdf_viewer_render_page(viewer->pdf_page, viewer->pdf_view, viewer->width,
1424 viewer->height, viewer->zoom, viewer->rotate);
1428 /* Get Links Mapping */
1429 if (viewer->link_map) {
1430 poppler_page_free_link_mapping(viewer->link_map);
1432 viewer->link_map = poppler_page_get_link_mapping(viewer->pdf_page);
1438 static void pdf_viewer_show_mimepart(MimeViewer *_viewer, const gchar *infile,
1441 PdfViewer *viewer = (PdfViewer *) _viewer;
1443 const gchar *charset = NULL;
1444 MessageView *messageview = ((MimeViewer *)viewer)->mimeview
1445 ?((MimeViewer *)viewer)->mimeview->messageview
1449 viewer->to_load = partinfo;
1452 messageview->updating = TRUE;
1454 memset(buf, 0, sizeof(buf));
1455 debug_print("pdf_viewer_show_mimepart\n");
1457 if (viewer->filename != NULL) {
1458 claws_unlink(viewer->filename);
1459 g_free(viewer->filename);
1460 viewer->filename = NULL;
1463 viewer->mimeinfo = NULL;
1466 viewer->target_filename = procmime_get_part_file_name(partinfo);
1467 viewer->filename = procmime_get_tmp_file_name(partinfo);
1468 viewer->fsname = g_filename_to_uri(viewer->filename, NULL, NULL);
1471 if (partinfo && !(procmime_get_part(viewer->filename, partinfo) < 0)) {
1473 if (messageview && messageview->forced_charset)
1474 charset = _viewer->mimeview->messageview->forced_charset;
1476 charset = procmime_mimeinfo_get_parameter(partinfo, "charset");
1478 if (charset == NULL) {
1479 charset = conv_get_locale_charset_str();
1482 debug_print("using charset %s\n", charset);
1484 viewer->mimeinfo = partinfo;
1487 pdf_viewer_update((MimeViewer *)viewer, TRUE, 1);
1490 messageview->updating = FALSE;
1493 static void pdf_viewer_clear(MimeViewer *_viewer)
1495 PdfViewer *viewer = (PdfViewer *) _viewer;
1496 GtkAdjustment *vadj;
1498 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(viewer->doc_index), FALSE);
1499 gtk_widget_hide(viewer->frame_index);
1501 debug_print("pdf_viewer_clear\n");
1502 viewer->to_load = NULL;
1504 if (viewer->pdf_doc) {
1505 g_object_unref(G_OBJECT(viewer->pdf_doc));
1506 viewer->pdf_doc = NULL;
1509 vadj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(viewer->scrollwin));
1511 g_signal_emit_by_name(G_OBJECT(vadj), "value-changed", 0);
1512 vadj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(viewer->scrollwin_index));
1514 g_signal_emit_by_name(G_OBJECT(vadj), "value-changed", 0);
1515 gtk_tree_store_clear(GTK_TREE_STORE(viewer->index_model));
1516 gtk_image_set_from_pixbuf(GTK_IMAGE(viewer->pdf_view), NULL);
1519 static void pdf_viewer_destroy(MimeViewer *_viewer)
1521 PdfViewer *viewer = (PdfViewer *) _viewer;
1523 debug_print("pdf_viewer_destroy\n");
1525 if (viewer->pdf_index) poppler_index_iter_free(viewer->pdf_index);
1527 poppler_page_free_link_mapping (viewer->link_map);
1528 g_object_unref(GTK_WIDGET(viewer->vbox));
1529 g_object_unref(GTK_WIDGET(viewer->pdf_view));
1530 g_object_unref(GTK_WIDGET(viewer->doc_index_pane));
1531 g_object_unref(GTK_WIDGET(viewer->scrollwin));
1532 g_object_unref(GTK_WIDGET(viewer->scrollwin_index));
1533 claws_unlink(viewer->filename);
1534 g_free(viewer->filename);
1538 static gboolean pdf_viewer_scroll_page(MimeViewer *_viewer, gboolean up)
1540 PdfViewer *viewer = (PdfViewer *)_viewer;
1541 GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment(
1542 GTK_SCROLLED_WINDOW(viewer->scrollwin));
1544 gint cur_p = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer->cur_page));
1546 if (viewer->pdf_view == NULL) return FALSE;
1548 if (!gtkutils_scroll_page(GTK_WIDGET(viewer->pdf_view), vadj, up)) {
1549 if (!up && cur_p != viewer->num_pages) {
1550 gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->cur_page), GTK_SPIN_STEP_FORWARD, 1);
1551 vadj = gtk_scrolled_window_get_vadjustment(
1552 GTK_SCROLLED_WINDOW(viewer->scrollwin));
1554 g_signal_emit_by_name(G_OBJECT(vadj), "value-changed", 0);
1557 else if (up && cur_p != 1) {
1558 gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer->cur_page), GTK_SPIN_STEP_BACKWARD, 1);
1559 vadj = gtk_scrolled_window_get_vadjustment(
1560 GTK_SCROLLED_WINDOW(viewer->scrollwin));
1561 vadj->value = vadj->upper - vadj->page_size;
1562 g_signal_emit_by_name(G_OBJECT(vadj), "value-changed", 0);
1570 static void pdf_viewer_scroll_one_line(MimeViewer *_viewer, gboolean up)
1572 PdfViewer *viewer = (PdfViewer *)_viewer;
1573 GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment(
1574 GTK_SCROLLED_WINDOW(viewer->scrollwin));
1576 cur_p = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer->cur_page));
1578 if (viewer->pdf_view == NULL) return;
1579 debug_print("up: %d\n", up);
1580 if (vadj->value <(vadj->upper - vadj->page_size)) {
1581 gtkutils_scroll_one_line(GTK_WIDGET(viewer->pdf_view), vadj, up);
1584 if (cur_p != viewer->num_pages) {
1585 pdf_viewer_scroll_page((MimeViewer *)viewer, up);
1591 #define BUTTON_H_PADDING 3
1592 #define ADD_BUTTON_TO_TABLE(widget, stock_image) \
1593 widget = gtk_button_new(); \
1594 img = gtk_image_new_from_stock(stock_image, GTK_ICON_SIZE_MENU); \
1595 gtk_button_set_image(GTK_BUTTON(widget), img); \
1596 gtk_table_attach(GTK_TABLE(viewer->widgets_table), GTK_WIDGET(widget), \
1597 col, col+1, 0, 1, 0, 0, BUTTON_H_PADDING, 0); \
1600 #define ADD_SEP_TO_TABLE \
1601 sep = gtk_label_new(""); \
1602 gtk_table_attach(GTK_TABLE(viewer->widgets_table), GTK_WIDGET(sep), \
1603 col, col+1, 0, 1, 0, 0, 0, 0); \
1604 gtk_table_set_col_spacing(GTK_TABLE(viewer->widgets_table), col, 3*BUTTON_H_PADDING); \
1607 #if POPPLER_HAS_CAIRO
1608 static PangoContext *pdf_viewer_get_pango_context(gpointer data)
1613 static gpointer pdf_viewer_get_data_to_print(gpointer data, gint sel_start, gint sel_end)
1615 return NULL; /* we don't need it */
1618 static void pdf_viewer_cb_begin_print(GtkPrintOperation *op, GtkPrintContext *context,
1621 PrintData *print_data;
1622 PopplerDocument *pdf_doc;
1624 print_data = (PrintData*) user_data;
1625 pdf_doc = (PopplerDocument *)printing_get_renderer_data(print_data);
1627 debug_print("Preparing print job...\n");
1629 n_pages = poppler_document_get_n_pages(pdf_doc);
1630 printing_set_n_pages(print_data, n_pages);
1631 gtk_print_operation_set_n_pages(op, n_pages);
1633 debug_print("Starting print job...\n");
1636 static void pdf_viewer_cb_draw_page(GtkPrintOperation *op, GtkPrintContext *context,
1637 int page_nr, gpointer user_data)
1640 PrintData *print_data;
1641 PopplerDocument *pdf_doc;
1642 PopplerPage *pdf_page;
1644 print_data = (PrintData*) user_data;
1645 pdf_doc = (PopplerDocument *)printing_get_renderer_data(print_data);
1646 pdf_page = poppler_document_get_page(pdf_doc, page_nr);
1648 cr = gtk_print_context_get_cairo_context(context);
1649 cairo_scale(cr, printing_get_zoom(print_data), printing_get_zoom(print_data));
1650 cairo_set_source_rgb(cr, 0., 0., 0.);
1652 poppler_page_render_for_printing(pdf_page, cr);
1654 g_object_unref(G_OBJECT(pdf_page));
1656 debug_print("Sent page %d to printer\n", page_nr+1);
1659 static void pdf_viewer_print(MimeViewer *mviewer)
1661 PdfViewer *viewer = (PdfViewer *)mviewer;
1662 PrintRenderer *pdf_renderer = g_new0(PrintRenderer, 1);
1663 MainWindow *mainwin = mainwindow_get_mainwindow();
1665 pdf_renderer->get_pango_context = pdf_viewer_get_pango_context;
1666 pdf_renderer->get_data_to_print = pdf_viewer_get_data_to_print;
1667 pdf_renderer->cb_begin_print = pdf_viewer_cb_begin_print;
1668 pdf_renderer->cb_draw_page = pdf_viewer_cb_draw_page;
1670 printing_print_full(mainwin ? GTK_WINDOW(mainwin->window):NULL,
1671 pdf_renderer, viewer->pdf_doc, -1, -1, NULL);
1673 g_free(pdf_renderer);
1677 static MimeViewer *pdf_viewer_create(void)
1680 GtkTreeViewColumn *column;
1681 GtkCellRenderer *renderer;
1682 GtkTreeStore *tree_store;
1687 viewer = g_new0(PdfViewer, 1);
1688 debug_print("pdf_viewer_create\n");
1692 viewer->mimeviewer.factory = &pdf_viewer_factory;
1693 viewer->mimeviewer.get_widget = pdf_viewer_get_widget;
1694 viewer->mimeviewer.show_mimepart = pdf_viewer_show_mimepart;
1695 viewer->mimeviewer.clear_viewer = pdf_viewer_clear;
1696 viewer->mimeviewer.destroy_viewer = pdf_viewer_destroy;
1697 viewer->mimeviewer.text_search = pdf_viewer_text_search;
1698 viewer->mimeviewer.scroll_page = pdf_viewer_scroll_page;
1699 viewer->mimeviewer.scroll_one_line = pdf_viewer_scroll_one_line;
1700 #if POPPLER_HAS_CAIRO
1701 viewer->mimeviewer.print = pdf_viewer_print;
1703 viewer->scrollwin = gtk_scrolled_window_new(NULL, NULL);
1704 viewer->scrollwin_index = gtk_scrolled_window_new(NULL, NULL);
1705 viewer->pdf_view_ebox = gtk_event_box_new();
1706 gtk_event_box_set_visible_window(GTK_EVENT_BOX(viewer->pdf_view_ebox), FALSE);
1708 viewer->mimeinfo = NULL;
1710 viewer->pdf_view = gtk_image_new();
1711 gtk_widget_set_events(viewer->pdf_view_ebox,
1712 GDK_BUTTON_RELEASE_MASK
1713 | GDK_POINTER_MOTION_MASK
1714 | GDK_BUTTON_PRESS_MASK
1715 | GDK_BUTTON_MOTION_MASK
1717 gtk_container_add (GTK_CONTAINER(viewer->pdf_view_ebox), viewer->pdf_view);
1718 viewer->icon_type = gtk_image_new();
1719 viewer->icon_type_ebox = gtk_event_box_new();
1721 gtk_container_add(GTK_CONTAINER(viewer->icon_type_ebox), viewer->icon_type);
1723 viewer->doc_label = gtk_label_new("");
1725 viewer->widgets_table = gtk_table_new(1, 1, FALSE);
1727 viewer->doc_index_pane = gtk_hpaned_new();
1729 viewer->frame_index = gtk_frame_new(NULL);
1730 gtk_frame_set_shadow_type(GTK_FRAME(viewer->frame_index), GTK_SHADOW_IN);
1731 gtk_widget_set_size_request(viewer->frame_index, 18, -1);
1732 gtk_frame_set_label(GTK_FRAME(viewer->frame_index), _("Document Index"));
1735 ADD_BUTTON_TO_TABLE(viewer->first_page, GTK_STOCK_GOTO_FIRST)
1736 ADD_BUTTON_TO_TABLE(viewer->prev_page, GTK_STOCK_GO_BACK)
1737 viewer->cur_page = gtk_spin_button_new_with_range(0.0, 0.0, 1.0);
1738 viewer->zoom_scroll = gtk_spin_button_new_with_range(0.20, 8.0, 0.20);
1739 gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer->zoom_scroll), 1.0);
1741 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(viewer->cur_page), TRUE);
1742 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(viewer->zoom_scroll), TRUE);
1743 gtk_table_attach(GTK_TABLE(viewer->widgets_table), GTK_WIDGET(viewer->cur_page),
1749 gtk_table_attach(GTK_TABLE(viewer->widgets_table), GTK_WIDGET(viewer->doc_label),
1756 ADD_BUTTON_TO_TABLE(viewer->next_page, GTK_STOCK_GO_FORWARD)
1757 ADD_BUTTON_TO_TABLE(viewer->last_page, GTK_STOCK_GOTO_LAST)
1759 ADD_BUTTON_TO_TABLE(viewer->zoom_fit, GTK_STOCK_ZOOM_FIT)
1760 ADD_BUTTON_TO_TABLE(viewer->zoom_in, GTK_STOCK_ZOOM_IN)
1761 gtk_table_attach(GTK_TABLE(viewer->widgets_table), GTK_WIDGET(viewer->zoom_scroll),
1767 ADD_BUTTON_TO_TABLE(viewer->zoom_out, GTK_STOCK_ZOOM_OUT)
1768 ADD_BUTTON_TO_TABLE(viewer->zoom_width, GTK_STOCK_FULLSCREEN)
1770 ADD_BUTTON_TO_TABLE(viewer->rotate_left, GTK_STOCK_UNDO)
1771 ADD_BUTTON_TO_TABLE(viewer->rotate_right, GTK_STOCK_REDO)
1773 ADD_BUTTON_TO_TABLE(viewer->doc_info, GTK_STOCK_INFO)
1775 viewer->doc_index = GTK_WIDGET(gtk_toggle_tool_button_new_from_stock(GTK_STOCK_INDEX));
1776 gtk_widget_set_size_request(GTK_WIDGET(viewer->doc_index), 26, 26);
1777 gtk_table_attach(GTK_TABLE(viewer->widgets_table), GTK_WIDGET(viewer->doc_index),
1784 gtk_scrolled_window_set_policy(
1785 GTK_SCROLLED_WINDOW(viewer->scrollwin),
1786 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1788 gtk_scrolled_window_set_shadow_type(
1789 GTK_SCROLLED_WINDOW(viewer->scrollwin),
1792 gtk_scrolled_window_add_with_viewport(
1793 GTK_SCROLLED_WINDOW(viewer->scrollwin),
1794 viewer->pdf_view_ebox);
1796 viewer->vbox = gtk_vbox_new(FALSE, 4);
1797 viewer->hbox = gtk_hbox_new(FALSE, 4);
1800 tree_store = gtk_tree_store_new(N_INDEX_COLUMNS,
1805 viewer->index_list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(tree_store));
1806 renderer = gtk_cell_renderer_text_new();
1807 column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer, "text", 0, NULL);
1808 gtk_tree_view_append_column(GTK_TREE_VIEW(viewer->index_list), column);
1809 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(viewer->index_list), FALSE);
1811 viewer->index_model = GTK_TREE_MODEL(tree_store);
1813 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(viewer->index_list)),
1814 GTK_SELECTION_SINGLE);
1816 g_signal_connect(G_OBJECT(viewer->index_list), "row_activated",
1817 G_CALLBACK(pdf_viewer_index_row_activated),
1820 gtk_scrolled_window_set_policy(
1821 GTK_SCROLLED_WINDOW(viewer->scrollwin_index),
1822 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1824 gtk_scrolled_window_set_shadow_type(
1825 GTK_SCROLLED_WINDOW(viewer->scrollwin_index),
1828 gtk_scrolled_window_add_with_viewport(
1829 GTK_SCROLLED_WINDOW(viewer->scrollwin_index),
1830 viewer->index_list);
1834 stock_pixbuf_gdk(viewer->hbox,
1835 STOCK_PIXMAP_MIME_TEXT_PLAIN,
1836 &viewer->icon_pixbuf);
1838 gtk_image_set_from_pixbuf(GTK_IMAGE(viewer->icon_type),
1839 viewer->icon_pixbuf);
1842 gtk_box_pack_start(GTK_BOX(viewer->hbox), viewer->icon_type_ebox, FALSE, FALSE, 0);
1843 gtk_box_pack_start(GTK_BOX(viewer->hbox), viewer->widgets_table, FALSE, FALSE, 0);
1845 gtk_container_add(GTK_CONTAINER(viewer->frame_index), viewer->scrollwin_index);
1847 gtk_paned_pack1(GTK_PANED(viewer->doc_index_pane), viewer->frame_index, FALSE, FALSE);
1848 gtk_paned_pack2(GTK_PANED(viewer->doc_index_pane), viewer->scrollwin, FALSE, FALSE);
1850 gtk_box_pack_start(GTK_BOX(viewer->vbox), viewer->hbox, FALSE, FALSE, 0);
1851 gtk_box_pack_start(GTK_BOX(viewer->vbox), viewer->doc_index_pane, TRUE, TRUE, 0);
1853 gtk_widget_show(GTK_WIDGET(viewer->doc_index_pane));
1854 g_object_ref(GTK_WIDGET(viewer->doc_index_pane));
1855 gtk_widget_show(GTK_WIDGET(viewer->scrollwin));
1856 g_object_ref(GTK_WIDGET(viewer->scrollwin));
1857 gtk_widget_show(GTK_WIDGET(viewer->icon_type_ebox));
1858 g_object_ref(GTK_WIDGET(viewer->icon_type_ebox));
1859 gtk_widget_show(GTK_WIDGET(viewer->pdf_view_ebox));
1860 g_object_ref(GTK_WIDGET(viewer->pdf_view_ebox));
1861 gtk_widget_show(GTK_WIDGET(viewer->scrollwin_index));
1862 g_object_ref(GTK_WIDGET(viewer->scrollwin_index));
1863 gtk_widget_show(GTK_WIDGET(viewer->hbox));
1864 g_object_ref(GTK_WIDGET(viewer->hbox));
1865 gtk_widget_show(GTK_WIDGET(viewer->vbox));
1866 g_object_ref(GTK_WIDGET(viewer->vbox));
1868 gtk_widget_show(GTK_WIDGET(viewer->widgets_table));
1869 g_object_ref(GTK_WIDGET(viewer->widgets_table));
1871 gtk_widget_show(GTK_WIDGET(viewer->cur_page));
1872 g_object_ref(GTK_WIDGET(viewer->cur_page));
1874 gtk_widget_show(GTK_WIDGET(viewer->first_page));
1875 g_object_ref(GTK_WIDGET(viewer->first_page));
1877 gtk_widget_show(GTK_WIDGET(viewer->last_page));
1878 g_object_ref(GTK_WIDGET(viewer->last_page));
1880 gtk_widget_show(GTK_WIDGET(viewer->prev_page));
1881 g_object_ref(GTK_WIDGET(viewer->prev_page));
1883 gtk_widget_show(GTK_WIDGET(viewer->next_page));
1884 g_object_ref(GTK_WIDGET(viewer->next_page));
1886 gtk_widget_show(GTK_WIDGET(viewer->zoom_in));
1887 g_object_ref(GTK_WIDGET(viewer->zoom_in));
1888 gtk_widget_show(GTK_WIDGET(viewer->zoom_out));
1889 g_object_ref(GTK_WIDGET(viewer->zoom_out));
1890 gtk_widget_show(GTK_WIDGET(viewer->zoom_fit));
1891 g_object_ref(GTK_WIDGET(viewer->zoom_fit));
1892 gtk_widget_show(GTK_WIDGET(viewer->zoom_width));
1893 g_object_ref(GTK_WIDGET(viewer->zoom_width));
1895 gtk_widget_show(GTK_WIDGET(viewer->rotate_right));
1896 g_object_ref(GTK_WIDGET(viewer->rotate_right));
1897 gtk_widget_show(GTK_WIDGET(viewer->rotate_left));
1898 g_object_ref(GTK_WIDGET(viewer->rotate_left));
1899 gtk_widget_show(GTK_WIDGET(viewer->doc_info));
1900 g_object_ref(GTK_WIDGET(viewer->doc_info));
1901 gtk_widget_show(GTK_WIDGET(viewer->doc_index));
1902 g_object_ref(GTK_WIDGET(viewer->doc_index));
1904 gtk_widget_show(GTK_WIDGET(viewer->doc_label));
1905 g_object_ref(GTK_WIDGET(viewer->doc_label));
1906 gtk_widget_show(GTK_WIDGET(viewer->icon_type));
1907 g_object_ref(GTK_WIDGET(viewer->icon_type));
1908 gtk_widget_show(GTK_WIDGET(viewer->pdf_view));
1909 g_object_ref(GTK_WIDGET(viewer->pdf_view));
1910 gtk_widget_show(GTK_WIDGET(viewer->zoom_scroll));
1911 g_object_ref(GTK_WIDGET(viewer->zoom_scroll));
1913 gtk_widget_show(GTK_WIDGET(viewer->index_list));
1914 g_object_ref(GTK_WIDGET(viewer->index_list));
1917 CLAWS_SET_TIP(viewer->first_page,
1920 CLAWS_SET_TIP(viewer->prev_page,
1921 _("Previous Page"));
1923 CLAWS_SET_TIP(viewer->next_page,
1926 CLAWS_SET_TIP(viewer->last_page,
1929 CLAWS_SET_TIP(viewer->zoom_in,
1931 CLAWS_SET_TIP(viewer->zoom_out,
1934 CLAWS_SET_TIP(viewer->zoom_fit,
1937 CLAWS_SET_TIP(viewer->zoom_width,
1938 _("Fit Page Width"));
1940 CLAWS_SET_TIP(viewer->rotate_left,
1943 CLAWS_SET_TIP(viewer->rotate_right,
1946 CLAWS_SET_TIP(viewer->doc_info,
1947 _("Document Info"));
1949 CLAWS_SET_TIP(viewer->doc_index,
1950 _("Document Index"));
1951 CLAWS_SET_TIP(viewer->cur_page,
1953 CLAWS_SET_TIP(viewer->zoom_scroll,
1955 /* Connect Signals */
1956 g_signal_connect(G_OBJECT(viewer->cur_page),
1958 G_CALLBACK(pdf_viewer_spin_change_page_cb),
1961 g_signal_connect(G_OBJECT(viewer->first_page),
1963 G_CALLBACK(pdf_viewer_button_first_page_cb),
1965 g_signal_connect(G_OBJECT(viewer->prev_page),
1967 G_CALLBACK(pdf_viewer_button_prev_page_cb),
1969 g_signal_connect(G_OBJECT(viewer->next_page),
1971 G_CALLBACK(pdf_viewer_button_next_page_cb),
1973 g_signal_connect(G_OBJECT(viewer->last_page),
1975 G_CALLBACK(pdf_viewer_button_last_page_cb),
1977 g_signal_connect(G_OBJECT(viewer->zoom_in),
1979 G_CALLBACK(pdf_viewer_button_zoom_in_cb),
1981 g_signal_connect(G_OBJECT(viewer->zoom_out),
1983 G_CALLBACK(pdf_viewer_button_zoom_out_cb),
1985 g_signal_connect(G_OBJECT(viewer->zoom_scroll),
1987 G_CALLBACK(pdf_viewer_spin_zoom_scroll_cb),
1990 g_signal_connect(G_OBJECT(viewer->zoom_fit),
1992 G_CALLBACK(pdf_viewer_button_zoom_fit_cb),
1995 g_signal_connect(G_OBJECT(viewer->zoom_width),
1997 G_CALLBACK(pdf_viewer_button_zoom_width_cb),
2000 g_signal_connect(G_OBJECT(viewer->rotate_right),
2002 G_CALLBACK(pdf_viewer_button_rotate_right_cb),
2005 g_signal_connect(G_OBJECT(viewer->rotate_left),
2007 G_CALLBACK(pdf_viewer_button_rotate_left_cb),
2010 g_signal_connect(G_OBJECT(viewer->doc_info),
2012 G_CALLBACK(pdf_viewer_button_document_info_cb),
2015 g_signal_connect(G_OBJECT(viewer->doc_index),
2017 G_CALLBACK(pdf_viewer_show_document_index_cb),
2019 g_signal_connect(G_OBJECT(viewer->scrollwin),
2021 G_CALLBACK(pdf_viewer_scroll_cb),
2023 g_signal_connect(G_OBJECT(viewer->pdf_view_ebox),
2024 "button_press_event",
2025 G_CALLBACK(pdf_viewer_button_press_events_cb),
2027 g_signal_connect(G_OBJECT(viewer->pdf_view_ebox),
2028 "button_release_event",
2029 G_CALLBACK(pdf_viewer_mouse_scroll_destroy_cb),
2031 g_signal_connect(G_OBJECT(viewer->pdf_view_ebox),
2032 "motion_notify_event",
2033 G_CALLBACK(pdf_viewer_move_events_cb),
2036 viewer->target_filename = NULL;
2037 viewer->filename = NULL;
2038 viewer->fsname = NULL;
2040 return(MimeViewer *) viewer;
2043 #undef ADD_BUTTON_TO_TABLE
2044 #undef ADD_SEP_TO_TABLE
2045 #undef BUTTON_H_PADDING
2046 #undef SEP_H_PADDING
2048 static MimeViewerFactory pdf_viewer_factory =
2055 gint plugin_init(gchar **error)
2057 gchar *gspath = NULL;
2059 msg = g_strdup_printf(_("This plugin enables the viewing of PDF and PostScript "
2060 "attachments using the Poppler %s Lib and the gs tool.\n\n"
2061 "Any feedback is welcome: iwkse@claws-mail.org"
2062 ), poppler_get_version());
2064 if (!check_plugin_version(MAKE_NUMERIC_VERSION(3,8,1,46),
2065 VERSION_NUMERIC, _("PDF Viewer"), error)) return -1;
2067 if ((gspath = g_find_program_in_path("gs")) == NULL) {
2069 msg = g_strdup_printf(_("Warning: could not find ghostscript binary (gs) required "
2070 "for %s plugin to process PostScript attachments, only PDF "
2071 "attachments will be displayed. To enable PostScript "
2072 "support please install gs program.\n\n%s"
2073 ), _("PDF Viewer"), pmsg);
2080 mimeview_register_viewer_factory(&pdf_viewer_factory);
2084 gboolean plugin_done(void)
2087 mimeview_unregister_viewer_factory(&pdf_viewer_factory);
2091 const gchar *plugin_name(void)
2093 return _("PDF Viewer");
2096 const gchar *plugin_desc(void)
2101 const gchar *plugin_type(void)
2106 const gchar *plugin_licence(void)
2111 const gchar *plugin_version(void)
2116 struct PluginFeature *plugin_provides(void)
2118 static struct PluginFeature features[] =
2119 { {PLUGIN_MIMEVIEWER, "application/pdf"},
2120 {PLUGIN_MIMEVIEWER, "application/postscript"},
2121 {PLUGIN_NOTHING, NULL} };