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