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