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