2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2022 the Claws Mail Team and Salvatore De Paolis
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.
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.
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/>.
21 #include "claws-features.h"
25 #include <glib/gi18n.h>
27 #include "poppler_viewer.h"
29 #include "prefs_common.h"
30 #include "gtk/gtkutils.h"
31 #include "gtk/inputdialog.h"
33 #include "summaryview.h"
34 #include "file-utils.h"
35 #ifndef POPPLER_WITH_GDK
39 static FileType
pdf_viewer_mimepart_get_type(MimeInfo
*partinfo
);
40 static MimeViewerFactory pdf_viewer_factory
;
42 static void pdf_viewer_show_mimepart(MimeViewer
*_viewer
, const gchar
*infile
,
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
);
50 static GtkWidget
*pdf_viewer_get_widget(MimeViewer
*_viewer
);
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
);
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
);
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
,
66 GtkTreeViewColumn
*column
,
69 static GtkGrid
* pdf_viewer_fill_info_table(PdfViewer
*viewer
);
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
);
90 static void pdf_viewer_show_controls(PdfViewer
*viewer
, gboolean show
);
91 static gboolean
pdf_viewer_scroll_page(MimeViewer
*_viewer
, gboolean up
);
92 static void pdf_viewer_scroll_one_line(MimeViewer
*_viewer
, gboolean up
);
94 /** Claws Mail Plugin functions */
95 gint
plugin_init(gchar
**error
);
96 const gchar
*plugin_name(void);
97 const gchar
*plugin_desc(void);
98 const gchar
*plugin_type(void);
99 const gchar
*plugin_licence(void);
100 const gchar
*plugin_version(void);
101 struct PluginFeature
*plugin_provides(void);
103 #ifndef POPPLER_WITH_GDK
105 copy_cairo_surface_to_pixbuf (cairo_surface_t
*surface
,
108 int cairo_width
, cairo_height
, cairo_rowstride
;
109 unsigned char *pixbuf_data
, *dst
, *cairo_data
;
110 int pixbuf_rowstride
, pixbuf_n_channels
;
114 cairo_width
= cairo_image_surface_get_width (surface
);
115 cairo_height
= cairo_image_surface_get_height (surface
);
116 cairo_rowstride
= cairo_image_surface_get_stride (surface
);
117 cairo_data
= cairo_image_surface_get_data (surface
);
119 pixbuf_data
= gdk_pixbuf_get_pixels (pixbuf
);
120 pixbuf_rowstride
= gdk_pixbuf_get_rowstride (pixbuf
);
121 pixbuf_n_channels
= gdk_pixbuf_get_n_channels (pixbuf
);
123 if (cairo_width
> gdk_pixbuf_get_width (pixbuf
))
124 cairo_width
= gdk_pixbuf_get_width (pixbuf
);
125 if (cairo_height
> gdk_pixbuf_get_height (pixbuf
))
126 cairo_height
= gdk_pixbuf_get_height (pixbuf
);
127 for (y
= 0; y
< cairo_height
; y
++) {
128 src
= (unsigned int *) (cairo_data
+ y
* cairo_rowstride
);
129 dst
= pixbuf_data
+ y
* pixbuf_rowstride
;
130 for (x
= 0; x
< cairo_width
; x
++) {
131 dst
[0] = (*src
>> 16) & 0xff;
132 dst
[1] = (*src
>> 8) & 0xff;
133 dst
[2] = (*src
>> 0) & 0xff;
134 if (pixbuf_n_channels
== 4)
135 dst
[3] = (*src
>> 24) & 0xff;
136 dst
+= pixbuf_n_channels
;
142 _poppler_page_render_to_pixbuf (PopplerPage
*page
,
143 int src_x
, int src_y
,
144 int src_width
, int src_height
,
151 cairo_surface_t
*surface
;
153 surface
= cairo_image_surface_create (CAIRO_FORMAT_ARGB32
,
154 src_width
, src_height
);
155 cr
= cairo_create (surface
);
159 cairo_translate (cr
, src_x
+ src_width
, -src_y
);
162 cairo_translate (cr
, src_x
+ src_width
, src_y
+ src_height
);
165 cairo_translate (cr
, -src_x
, src_y
+ src_height
);
168 cairo_translate (cr
, -src_x
, -src_y
);
172 cairo_scale (cr
, scale
, scale
);
175 cairo_rotate (cr
, rotation
* G_PI
/ 180.0);
178 poppler_page_render_for_printing (page
, cr
);
180 poppler_page_render (page
, cr
);
183 cairo_set_operator (cr
, CAIRO_OPERATOR_DEST_OVER
);
184 cairo_set_source_rgb (cr
, 1., 1., 1.);
189 copy_cairo_surface_to_pixbuf (surface
, pixbuf
);
190 cairo_surface_destroy (surface
);
194 * poppler_page_render_to_pixbuf:
195 * @page: the page to render from
196 * @src_x: x coordinate of upper left corner
197 * @src_y: y coordinate of upper left corner
198 * @src_width: width of rectangle to render
199 * @src_height: height of rectangle to render
200 * @scale: scale specified as pixels per point
201 * @rotation: rotate the document by the specified degree
202 * @pixbuf: pixbuf to render into
204 * First scale the document to match the specified pixels per point,
205 * then render the rectangle given by the upper left corner at
206 * (src_x, src_y) and src_width and src_height.
207 * This function is for rendering a page that will be displayed.
208 * If you want to render a page that will be printed use
209 * poppler_page_render_to_pixbuf_for_printing() instead
214 poppler_page_render_to_pixbuf (PopplerPage
*page
,
215 int src_x
, int src_y
,
216 int src_width
, int src_height
,
221 g_return_if_fail (POPPLER_IS_PAGE (page
));
222 g_return_if_fail (scale
> 0.0);
223 g_return_if_fail (pixbuf
!= NULL
);
225 _poppler_page_render_to_pixbuf (page
, src_x
, src_y
,
226 src_width
, src_height
,
232 static GtkWidget
*pdf_viewer_get_widget(MimeViewer
*_viewer
)
234 PdfViewer
*viewer
= (PdfViewer
*) _viewer
;
235 debug_print("pdf_viewer_get_widget: %p\n", viewer
->vbox
);
237 return GTK_WIDGET(viewer
->vbox
);
239 /** Hide the index panel */
240 static void pdf_viewer_hide_index_pane(PdfViewer
*viewer
)
242 if (viewer
->pdf_index
) {
243 poppler_index_iter_free(viewer
->pdf_index
);
244 viewer
->pdf_index
= NULL
;
245 gtk_widget_hide(GTK_WIDGET(viewer
->frame_index
));
249 static void search_matches_free(PdfViewer
*viewer
)
252 for(cur
= viewer
->text_found
; cur
; cur
= cur
->next
) {
253 PageResult
*res
= (PageResult
*)cur
->data
;
254 g_list_free(res
->results
);
257 g_list_free(viewer
->text_found
);
258 viewer
->text_found
= NULL
;
259 g_free(viewer
->last_search
);
260 viewer
->last_search
= NULL
;
261 if (viewer
->last_rect
&& viewer
->last_page_result
) {
262 viewer
->last_rect
= NULL
;
263 viewer
->last_page_result
= NULL
;
264 pdf_viewer_update((MimeViewer
*)viewer
,
266 gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer
->cur_page
)));
270 static void pdf_viewer_scroll_to(PdfViewer
*viewer
, gfloat x
, gfloat y
)
274 vadj
= gtk_scrolled_window_get_vadjustment(
275 GTK_SCROLLED_WINDOW(viewer
->scrollwin
));
277 if (y
< gtk_adjustment_get_value(vadj
)) {
278 gtk_adjustment_set_value(vadj
, y
);
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
));
287 hadj
= gtk_scrolled_window_get_hadjustment(
288 GTK_SCROLLED_WINDOW(viewer
->scrollwin
));
290 if (x
< gtk_adjustment_get_value(hadj
)) {
291 gtk_adjustment_set_value(hadj
, x
);
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
));
300 g_signal_emit_by_name(G_OBJECT(hadj
), "value-changed", 0);
301 g_signal_emit_by_name(G_OBJECT(vadj
), "value-changed", 0);
303 static void pdf_viewer_render_page(PopplerPage
*page
, GtkWidget
*view
, double width
,
304 double height
, double zoom
, gint rotate
)
308 debug_print("width: %f\n", width
);
309 pb
= gdk_pixbuf_new(GDK_COLORSPACE_RGB
,
312 (int)(height
* zoom
));
314 poppler_page_render_to_pixbuf(page
, 0, 0,
316 (int)(height
* zoom
),
319 gtk_image_set_from_pixbuf(GTK_IMAGE(view
), pb
);
320 g_object_unref(G_OBJECT(pb
));
322 static void pdf_viewer_render_selection(PdfViewer
*viewer
, PopplerRectangle
*rect
, PageResult
*page_results
)
325 double width_points
, height_points
;
327 GdkPixbuf
*sel_pb
, *page_pb
;
328 gfloat x1
, x2
, y1
, y2
;
332 gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer
->cur_page
));
334 viewer
->last_match
= viewer
->res_cnt
;
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
);
344 viewer
->last_rect
= rect
;
345 viewer
->last_page_result
= page_results
;
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);
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
;
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
;
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
;
379 x1
= rect
->x1
* viewer
->zoom
;
380 x2
= rect
->x2
* viewer
->zoom
;
381 y1
= rect
->y1
* viewer
->zoom
;
382 y2
= rect
->y2
* viewer
->zoom
;
389 sel_pb
= gdk_pixbuf_new(GDK_COLORSPACE_RGB
, FALSE
, 8,
392 gdk_pixbuf_fill(sel_pb
, SELECTION_COLOR
);
394 page_pb
= gdk_pixbuf_new(GDK_COLORSPACE_RGB
,
396 (int)(viewer
->width
* viewer
->zoom
),
397 (int)(viewer
->height
* viewer
->zoom
));
399 poppler_page_render_to_pixbuf(viewer
->pdf_page
,
402 (int)(viewer
->width
* viewer
->zoom
),
403 (int)(viewer
->height
* viewer
->zoom
),
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
);
413 gtk_image_set_from_pixbuf(GTK_IMAGE(viewer
->pdf_view
), page_pb
);
415 pdf_viewer_scroll_to(viewer
, MIN(x1
,x2
), MIN(y1
,y2
));
417 g_object_unref(G_OBJECT(sel_pb
));
418 g_object_unref(G_OBJECT(page_pb
));
422 static gboolean
pdf_viewer_text_search(MimeViewer
*_viewer
, gboolean backward
,
423 const gchar
*str
, gboolean case_sens
)
425 PdfViewer
*viewer
= (PdfViewer
*)_viewer
;
426 GList
*all_pages_results
, *cur_page_results
;
429 debug_print("pdf_viewer_text_search: %s\n", str
);
430 main_window_cursor_wait(mainwindow_get_mainwindow());
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;
440 /* It's a new search, build list of matches
441 * across all pages */
442 if (viewer
->last_match
== -1) {
445 for(i
= 1; i
<= viewer
->num_pages
; i
++) {
447 PopplerPage
*pdf_page
= poppler_document_get_page(viewer
->pdf_doc
, i
- 1);
448 viewer
->page_results
= poppler_page_find_text(pdf_page
, str
);
450 if (viewer
->page_results
!= NULL
) {
451 debug_print("page_results %p\n", viewer
->page_results
);
452 /* store results for this page */
454 PageResult
*res
= g_new0(PageResult
, 1);
455 res
->results
= viewer
->page_results
;
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
;
463 g_object_unref(G_OBJECT(pdf_page
));
466 if (viewer
->text_found
== NULL
) {
467 main_window_cursor_normal(mainwindow_get_mainwindow());
470 /* put back the list in the correct order */
471 viewer
->text_found
= g_list_reverse(viewer
->text_found
);
474 if (!viewer
->text_found
) {
475 main_window_cursor_normal(mainwindow_get_mainwindow());
478 viewer
->last_search
= g_strdup(str
);
482 /* if backward, we have to initialize stuff to search
484 viewer
->res_cnt
= viewer
->num_matches
-1;
485 if (viewer
->last_match
== -1) {
486 viewer
->last_match
= viewer
->num_matches
+1;
488 all_pages_results
= g_list_last(viewer
->text_found
);
491 all_pages_results
= viewer
->text_found
;
494 for(; all_pages_results
; all_pages_results
= (backward
?all_pages_results
->prev
:all_pages_results
->next
)) {
496 PageResult
* page_results
= (PageResult
*)all_pages_results
->data
;
499 cur_page_results
= g_list_last(page_results
->results
);
502 cur_page_results
= page_results
->results
;
505 for(; cur_page_results
; cur_page_results
= (backward
?cur_page_results
->prev
:cur_page_results
->next
)) {
507 gboolean valid
= FALSE
;
508 /* first valid result is the last+1 if searching
509 * forward, last-1 if searching backward */
511 valid
= (viewer
->res_cnt
< viewer
->last_match
);
514 valid
= (viewer
->res_cnt
> viewer
->last_match
);
517 pdf_viewer_render_selection(viewer
,
518 (PopplerRectangle
*)cur_page_results
->data
,
520 main_window_cursor_normal(mainwindow_get_mainwindow());
532 main_window_cursor_normal(mainwindow_get_mainwindow());
533 search_matches_free(viewer
);
537 static void pdf_viewer_get_document_index(PdfViewer
*viewer
, PopplerIndexIter
*index_iter
, GtkTreeIter
*parentiter
)
539 PopplerAction
*action
;
540 PopplerIndexIter
*child
;
541 GtkTreeIter childiter
;
543 debug_print("get document index\n");
547 action
= poppler_index_iter_get_action(index_iter
);
549 if (action
->type
!= POPPLER_ACTION_GOTO_DEST
) {
550 poppler_action_free(action
);
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
;
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
);
566 page_num
= dest
->page_num
;
567 poppler_dest_free(dest
);
571 #ifdef HAVE_POPPLER_DEST_NAMED
572 g_warning("unhandled link type %d. please contact developers", action
->goto_dest
.dest
->type
);
574 g_warning("unhandled link type %d. please upgrade libpoppler-glib to 0.5.4", action
->goto_dest
.dest
->type
);
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
,
584 poppler_action_free(action
);
585 child
= poppler_index_iter_get_child(index_iter
);
587 pdf_viewer_get_document_index(viewer
, child
, &childiter
);
588 poppler_index_iter_free(child
);
591 while(poppler_index_iter_next(index_iter
));
594 static void pdf_viewer_index_row_activated(GtkTreeView
*tree_view
,
596 GtkTreeViewColumn
*column
,
600 GtkTreeModel
*model
= gtk_tree_view_get_model(tree_view
);
601 PdfViewer
*viewer
= (PdfViewer
*)data
;
604 debug_print("index_row_activated\n");
605 if (!gtk_tree_model_get_iter(model
, &iter
, path
)) return;
607 gtk_tree_model_get(model
, &iter
,
608 INDEX_PAGE
, &page_num
,
612 gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer
->cur_page
),(gdouble
)page_num
);
613 debug_print("Page num: %d\n", page_num
);
618 /** Disable the index button if the document doesn't have an index */
619 static void pdf_viewer_set_index_button_sensitive(PdfViewer
*viewer
)
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
);
628 gtk_widget_set_sensitive(viewer
->doc_index
, FALSE
);
631 poppler_index_iter_free(viewer
->pdf_index
);
632 viewer
->pdf_index
= NULL
;
635 static char * pdf_viewer_get_document_format_data(GDateTime
*utime
)
637 time_t time
= (time_t) utime
;
640 const char *fmt_hack
= "%c";
643 if (time
== 0 || !localtime_r(&time
, &t
)) return NULL
;
645 len
= strftime(s
, sizeof(s
), fmt_hack
, &t
);
647 if (len
== 0 || s
[0] == '\0') return NULL
;
649 return g_locale_to_utf8(s
, -1, NULL
, NULL
, NULL
);
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); \
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); \
669 static GtkGrid
* pdf_viewer_fill_info_table(PdfViewer
*viewer
)
672 const gchar
*title
, *format
, *author
, *subject
, *keywords
, *creator
, *producer
;
677 GDateTime
*creation_date
, *mod_date
;
679 PopplerPageLayout layout
;
680 PopplerPageMode mode
;
681 PopplerPermissions permissions
;
682 PopplerViewerPreferences view_prefs
;
684 title
= format
= author
= subject
= keywords
= creator
= producer
= tmp
= 0;
686 g_object_get(viewer
->pdf_doc
,
691 "keywords", &keywords
,
692 "creation-date", &creation_date
,
693 "permissions", &permissions
,
694 "mod-date", &mod_date
,
696 "producer", &producer
,
697 "linearized", &linearized
,
699 "page-layout", &layout
,
700 "viewer-preferences", &view_prefs
,
703 viewer
->table_doc_info
= gtk_grid_new();
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
)
715 tmp
= pdf_viewer_get_document_format_data(creation_date
);
716 ADD_TO_GRID(_("Created:"), tmp
)
719 tmp
= pdf_viewer_get_document_format_data(mod_date
);
720 ADD_TO_GRID(_("Modified:"), tmp
)
723 ADD_TO_GRID(_("Format:"), format
)
725 ADD_TO_GRID(_("Optimized:"), _("Yes"))
728 ADD_TO_GRID(_("Optimized:"), _("No"))
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))
733 return(GtkGrid
*) viewer
->table_doc_info
;
737 static FileType
pdf_viewer_mimepart_get_type(MimeInfo
*partinfo
)
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"))) {
745 const gchar
*filename
;
747 filename
= procmime_mimeinfo_get_parameter(partinfo
, "filename");
749 if (filename
== NULL
)
750 filename
= procmime_mimeinfo_get_parameter(partinfo
, "name");
751 if (filename
!= NULL
)
752 content_type
= procmime_get_mime_type(filename
);
755 content_type
= procmime_get_content_type_str(partinfo
->type
, partinfo
->subtype
);
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
;
763 g_free(content_type
);
768 static void pdf_viewer_button_first_page_cb(GtkButton
*button
, PdfViewer
*viewer
)
771 gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer
->cur_page
), GTK_SPIN_HOME
, 1);
774 static void pdf_viewer_button_prev_page_cb(GtkButton
*button
, PdfViewer
*viewer
)
777 gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer
->cur_page
), GTK_SPIN_STEP_BACKWARD
, 1);
780 static void pdf_viewer_button_next_page_cb(GtkButton
*button
, PdfViewer
*viewer
)
783 gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer
->cur_page
), GTK_SPIN_STEP_FORWARD
, 1);
786 static void pdf_viewer_button_last_page_cb(GtkButton
*button
, PdfViewer
*viewer
)
789 gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer
->cur_page
), GTK_SPIN_END
, 1);
792 static void pdf_viewer_spin_change_page_cb(GtkSpinButton
*button
, PdfViewer
*viewer
)
794 pdf_viewer_update((MimeViewer
*)viewer
,
796 gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer
->cur_page
)));
799 static void pdf_viewer_button_zoom_in_cb(GtkButton
*button
, PdfViewer
*viewer
)
802 gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer
->zoom_scroll
), GTK_SPIN_STEP_FORWARD
, ZOOM_FACTOR
);
805 static void pdf_viewer_spin_zoom_scroll_cb(GtkSpinButton
*button
, PdfViewer
*viewer
)
807 viewer
->zoom
= gtk_spin_button_get_value(GTK_SPIN_BUTTON(viewer
->zoom_scroll
));
808 pdf_viewer_update((MimeViewer
*)viewer
,
810 gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer
->cur_page
)));
813 static void pdf_viewer_button_zoom_out_cb(GtkButton
*button
, PdfViewer
*viewer
)
816 gtk_spin_button_spin(GTK_SPIN_BUTTON(viewer
->zoom_scroll
), GTK_SPIN_STEP_BACKWARD
, ZOOM_FACTOR
);
820 static void pdf_viewer_button_press_events_cb(GtkWidget
*widget
, GdkEventButton
*event
, PdfViewer
*viewer
)
824 #ifdef HAVE_POPPLER_DEST_NAMED
827 static GdkCursor
*hand_cur
= NULL
;
829 if (!hand_cur
) hand_cur
= gdk_cursor_new_for_display(
830 gtk_widget_get_display(widget
), GDK_FLEUR
);
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");
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
);
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
);
853 gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer
->cur_page
),
854 (gdouble
)dest
->page_num
);
855 poppler_dest_free(dest
);
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
);
868 gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer
->cur_page
),
869 (gdouble
)dest
->page_num
);
870 poppler_dest_free(dest
);
873 case POPPLER_ACTION_LAUNCH
:
874 debug_print("action launch not yet implemented\n");
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
);
881 open_uri(uri
, prefs_common_get_uri_cmd());
884 case POPPLER_ACTION_NAMED
:
885 debug_print("action named not yet implemented\n");
887 case POPPLER_ACTION_NONE
:
888 debug_print("action none does nothing, surprise!\n");
890 case POPPLER_ACTION_MOVIE
:
891 debug_print("yoyoyo ;-) a movie?\n");
893 #if POPPLER_CHECK_VERSION(0,14,0)
894 case POPPLER_ACTION_RENDITION
:
895 debug_print("yoyoyo ;-) multimedia?\n");
897 case POPPLER_ACTION_OCG_STATE
:
898 debug_print("yoyoyo ;-) layer state?\n");
900 #if POPPLER_CHECK_VERSION(0,18,0)
901 case POPPLER_ACTION_JAVASCRIPT
:
902 debug_print("yoyoyo ;-) javascript?\n");
904 #if POPPLER_CHECK_VERSION(0,90,0)
905 case POPPLER_ACTION_RESET_FORM
:
906 debug_print("yoyoyo ;-) reset form?\n");
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
);
918 gdk_window_set_cursor (gtk_widget_get_window(mainwindow_get_mainwindow()->window
), NULL
);
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
);
930 gdk_window_set_cursor (gtk_widget_get_window(mainwindow_get_mainwindow()->window
), hand_cur
);
932 viewer
->last_x
= event
->x
;
933 viewer
->last_y
= event
->y
;
934 viewer
->last_dir_x
= 0;
935 viewer
->last_dir_y
= 0;
938 /* Set the normal cursor*/
939 static void pdf_viewer_mouse_scroll_destroy_cb(GtkWidget
*widget
, GdkEventButton
*event
, PdfViewer
*viewer
)
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
);
951 gdk_window_set_cursor (gtk_widget_get_window(mainwindow_get_mainwindow()->window
), NULL
);
955 static void pdf_viewer_move_events_cb(GtkWidget
*widget
, GdkEventMotion
*event
, PdfViewer
*viewer
)
959 /* Grab the document and scroll it with mouse */
960 if (viewer
->pdf_view_scroll
) {
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
));
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
)
972 g_signal_emit_by_name(G_OBJECT(viewer
->pdf_view_hadj
),
975 viewer
->last_dir_x
= -1;
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
)
984 g_signal_emit_by_name(G_OBJECT(viewer
->pdf_view_hadj
),
987 viewer
->last_dir_x
= +1;
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
)
997 g_signal_emit_by_name(G_OBJECT(viewer
->pdf_view_vadj
),
1000 viewer
->last_dir_y
= -1;
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
)
1009 g_signal_emit_by_name(G_OBJECT(viewer
->pdf_view_vadj
),
1010 "value_changed", 0);
1012 viewer
->last_dir_y
= +1;
1014 viewer
->last_x
= event
->x
;
1015 viewer
->last_y
= event
->y
;
1021 static GdkCursor
*link_cur
= NULL
;
1022 static GtkRequisition size
;
1023 static gdouble x
,y
, x1
, y1
, x2
, y2
;
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
));
1029 if (!link_cur
) link_cur
= gdk_cursor_new_for_display(
1030 gtk_widget_get_display(viewer
->scrollwin
), GDK_HAND2
);
1033 viewer
->in_link
= FALSE
;
1034 for (l
= viewer
->link_map
; l
; l
= g_list_next (l
)) {
1036 PopplerLinkMapping
*lmapping
;
1037 lmapping
= (PopplerLinkMapping
*)l
->data
;
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
);
1045 upper
= gtk_adjustment_get_upper(viewer
->pdf_view_hadj
);
1046 switch (viewer
->rotate
) {
1049 if (size
.width
!= upper
)
1050 x
= (event
->x
- (upper
- size
.width
) / 2) / viewer
->zoom
;
1052 x
= event
->x
/ viewer
->zoom
;
1054 y
= (upper
- event
->y
) / viewer
->zoom
;
1057 if (size
.width
!= upper
)
1058 y
= (event
->x
- (upper
- size
.width
) / 2) / viewer
->zoom
;
1060 y
= event
->x
/ viewer
->zoom
;
1062 x
= (event
->y
) / viewer
->zoom
;
1065 if (size
.width
!= upper
)
1066 x
= ((upper
- event
->x
) - ((upper
- size
.width
) / 2)) / viewer
->zoom
;
1068 x
= ((upper
- event
->x
) - (upper
- size
.width
)) / viewer
->zoom
;
1070 y
= (event
->y
) / viewer
->zoom
;
1073 if (size
.width
!= upper
)
1074 y
= ((upper
- event
->x
) - ((upper
- size
.width
) / 2)) / viewer
->zoom
;
1076 y
= ((upper
- event
->x
) - (upper
- size
.width
)) / viewer
->zoom
;
1078 x
= (upper
- event
->y
) / viewer
->zoom
;
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
);
1090 gdk_window_set_cursor (gtk_widget_get_window(mainwindow_get_mainwindow()->window
), link_cur
);
1092 viewer
->link_action
= lmapping
->action
;
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
);
1102 gdk_window_set_cursor (gtk_widget_get_window(mainwindow_get_mainwindow()->window
), NULL
);
1108 static gboolean
pdf_viewer_scroll_cb(GtkWidget
*widget
, GdkEventScroll
*event
,
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
));
1120 in_scroll_cb
= TRUE
;
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
);
1126 pdf_viewer_button_zoom_out_cb(NULL
, viewer
);
1128 in_scroll_cb
= FALSE
;
1132 if (event
->direction
== GDK_SCROLL_SMOOTH
) {
1133 gdk_event_get_scroll_deltas((GdkEvent
*)event
, &delta_x
, &delta_y
);
1136 if ((delta_y
< 0.0 || event
->direction
== GDK_SCROLL_UP
) &&
1137 gtk_adjustment_get_value(adj
) == gtk_adjustment_get_lower(adj
) &&
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
));
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);
1150 in_scroll_cb
= FALSE
;
1154 static void pdf_viewer_button_zoom_fit_cb(GtkButton
*button
, PdfViewer
*viewer
)
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
;
1164 if (xratio
>= yratio
) {
1165 viewer
->zoom
= yratio
;
1166 gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer
->zoom_scroll
),viewer
->zoom
);
1169 viewer
->zoom
= xratio
;
1170 gtk_spin_button_set_value(GTK_SPIN_BUTTON(viewer
->zoom_scroll
),viewer
->zoom
);
1174 static void pdf_viewer_button_zoom_width_cb(GtkButton
*button
, PdfViewer
*viewer
)
1176 GtkAllocation allocation
;
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
);
1184 static void pdf_viewer_button_rotate_right_cb(GtkButton
*button
, PdfViewer
*viewer
)
1186 if (viewer
->rotate
== 360) {
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
)));
1195 static void pdf_viewer_button_rotate_left_cb(GtkButton
*button
, PdfViewer
*viewer
)
1197 if (viewer
->rotate
== 0) {
1198 viewer
->rotate
= 360;
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
)));
1206 /* Show/Hide the index pane */
1207 static void pdf_viewer_show_document_index_cb(GtkToggleButton
*button
, PdfViewer
*viewer
)
1209 if (!viewer
->pdf_index
) {
1210 viewer
->pdf_index
= poppler_index_iter_new(viewer
->pdf_doc
);
1213 gtk_tree_store_clear(GTK_TREE_STORE(viewer
->index_model
));
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
));
1220 pdf_viewer_hide_index_pane(viewer
);
1225 static void pdf_viewer_button_print_cb(GtkButton
*button
, PdfViewer
*viewer
)
1227 MainWindow
*mainwin
= mainwindow_get_mainwindow();
1228 summary_print(mainwin
->summaryview
);
1231 static void pdf_viewer_button_document_info_cb(GtkButton
*button
, PdfViewer
*viewer
)
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
)),
1240 static const char * poppler_get_document_info_mode(PopplerPageMode mode)
1242 GEnumValue *enum_value;
1244 enum_value = g_enum_get_value((GEnumClass *) g_type_class_peek(POPPLER_TYPE_PAGE_MODE), mode);
1245 return(gchar *) enum_value->value_name;
1247 static const char * poppler_get_document_info_layout(PopplerPageLayout layout)
1250 GEnumValue *enum_value;
1252 enum_value = g_enum_get_value((GEnumClass *) g_type_class_peek(POPPLER_TYPE_PAGE_LAYOUT), layout);
1253 return(gchar *) enum_value->value_name;
1256 static void pdf_viewer_show_controls(PdfViewer
*viewer
, gboolean 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
);
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
);
1294 /** Render the current page, page_num on the viewer */
1295 static void pdf_viewer_update(MimeViewer
*_viewer
, gboolean reload_file
, int page_num
)
1298 PdfViewer
*viewer
= (PdfViewer
*) _viewer
;
1299 GError
*error
= NULL
;
1300 gchar
*tmpfile
= NULL
;
1302 gchar
*password
= NULL
;
1304 debug_print("pdf_viewer_update\n");
1307 if (viewer
->pdf_doc
) {
1308 g_object_unref(G_OBJECT(viewer
->pdf_doc
));
1309 viewer
->pdf_doc
= NULL
;
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
);
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
);
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
);
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());
1337 if (pdf_viewer_mimepart_get_type(viewer
->to_load
) == TYPE_PS
) {
1338 gchar
*cmdline
= NULL
, *tmp
= NULL
, *gspath
= NULL
;
1341 if ((gspath
= g_find_program_in_path("gs")) != NULL
) {
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
);
1351 tmp
= g_filename_to_uri(tmpfile
, NULL
, NULL
);
1352 viewer
->pdf_doc
= poppler_document_new_from_file( tmp
, NULL
, &error
);
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
);
1363 claws_unlink(tmpfile
);
1367 g_warning("gs conversion disabled: gs binary was not found");
1368 alertpanel_warning("PostScript view disabled: required gs program not found");
1373 main_window_cursor_normal(mainwindow_get_mainwindow());
1378 viewer
->pdf_doc
= poppler_document_new_from_file( viewer
->fsname
, NULL
, &error
);
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."),
1385 viewer
->pdf_doc
= poppler_document_new_from_file(viewer
->fsname
, password
, &error
);
1389 viewer
->num_pages
= poppler_document_get_n_pages(viewer
->pdf_doc
);
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
),
1394 (gdouble
)viewer
->num_pages
);
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");
1400 GTK_WIDGET(viewer
->icon_type_ebox
),
1404 tmp
= g_strdup_printf(_("of %d"), viewer
->num_pages
);
1405 gtk_label_set_text(GTK_LABEL(viewer
->doc_label
), tmp
);
1408 pdf_viewer_show_controls(viewer
, TRUE
);
1409 main_window_cursor_normal(mainwindow_get_mainwindow());
1411 if (viewer
->pdf_doc
== NULL
) {
1412 stock_pixbuf_gdk(STOCK_PIXMAP_MIME_APPLICATION
,
1413 &viewer
->icon_pixbuf
);
1415 gtk_image_set_from_pixbuf(GTK_IMAGE(viewer
->icon_type
), viewer
->icon_pixbuf
);
1417 strretchomp(error
->message
);
1418 alertpanel_error("%s", error
->message
);
1420 alertpanel_error(_("PDF rendering failed for an unknown reason."));
1422 pdf_viewer_show_controls(viewer
, FALSE
);
1423 g_error_free(error
);
1427 if (page_num
== 1) {
1428 gtk_widget_set_sensitive(viewer
->first_page
, FALSE
);
1429 gtk_widget_set_sensitive(viewer
->prev_page
, FALSE
);
1432 gtk_widget_set_sensitive(viewer
->first_page
, TRUE
);
1433 gtk_widget_set_sensitive(viewer
->prev_page
, TRUE
);
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
);
1441 gtk_widget_set_sensitive(viewer
->last_page
, TRUE
);
1442 gtk_widget_set_sensitive(viewer
->next_page
, TRUE
);
1445 /* check for the index if exists */
1446 pdf_viewer_set_index_button_sensitive((PdfViewer
*) viewer
);
1448 if (page_num
> 0 && page_num
<= viewer
->num_pages
) {
1452 if (viewer
->pdf_page
) {
1453 g_object_unref(G_OBJECT(viewer
->pdf_page
));
1456 viewer
->pdf_page
= poppler_document_get_page(viewer
->pdf_doc
, page_num
- 1);
1458 if (viewer
->pdf_page
== NULL
) {
1459 g_warning("page not found");
1463 if (viewer
->rotate
== 90 || viewer
->rotate
== 270) {
1464 poppler_page_get_size(viewer
->pdf_page
, &viewer
->height
, &viewer
->width
);
1467 poppler_page_get_size(viewer
->pdf_page
, &viewer
->width
, &viewer
->height
);
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
);
1475 pdf_viewer_render_page(viewer
->pdf_page
, viewer
->pdf_view
, viewer
->width
,
1476 viewer
->height
, viewer
->zoom
, viewer
->rotate
);
1480 /* Get Links Mapping */
1481 if (viewer
->link_map
) {
1482 poppler_page_free_link_mapping(viewer
->link_map
);
1484 viewer
->link_map
= poppler_page_get_link_mapping(viewer
->pdf_page
);
1490 static void pdf_viewer_show_mimepart(MimeViewer
*_viewer
, const gchar
*infile
,
1493 PdfViewer
*viewer
= (PdfViewer
*) _viewer
;
1495 const gchar
*charset
= NULL
;
1496 MessageView
*messageview
= ((MimeViewer
*)viewer
)->mimeview
1497 ?((MimeViewer
*)viewer
)->mimeview
->messageview
1501 viewer
->to_load
= partinfo
;
1504 messageview
->updating
= TRUE
;
1506 memset(buf
, 0, sizeof(buf
));
1507 debug_print("pdf_viewer_show_mimepart\n");
1509 if (viewer
->filename
!= NULL
) {
1510 claws_unlink(viewer
->filename
);
1511 g_free(viewer
->filename
);
1512 viewer
->filename
= NULL
;
1515 viewer
->mimeinfo
= NULL
;
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
);
1523 if (partinfo
&& !(procmime_get_part(viewer
->filename
, partinfo
) < 0)) {
1525 if (messageview
&& messageview
->forced_charset
)
1526 charset
= _viewer
->mimeview
->messageview
->forced_charset
;
1528 charset
= procmime_mimeinfo_get_parameter(partinfo
, "charset");
1530 if (charset
== NULL
) {
1531 charset
= conv_get_locale_charset_str();
1534 debug_print("using charset %s\n", charset
);
1536 viewer
->mimeinfo
= partinfo
;
1539 pdf_viewer_update((MimeViewer
*)viewer
, TRUE
, 1);
1542 messageview
->updating
= FALSE
;
1545 static void pdf_viewer_clear(MimeViewer
*_viewer
)
1547 PdfViewer
*viewer
= (PdfViewer
*) _viewer
;
1548 GtkAdjustment
*vadj
;
1550 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(viewer
->doc_index
), FALSE
);
1551 gtk_widget_hide(viewer
->frame_index
);
1553 debug_print("pdf_viewer_clear\n");
1554 viewer
->to_load
= NULL
;
1556 if (viewer
->pdf_doc
) {
1557 g_object_unref(G_OBJECT(viewer
->pdf_doc
));
1558 viewer
->pdf_doc
= NULL
;
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
);
1571 static void pdf_viewer_destroy(MimeViewer
*_viewer
)
1573 PdfViewer
*viewer
= (PdfViewer
*) _viewer
;
1575 debug_print("pdf_viewer_destroy\n");
1577 if (viewer
->pdf_index
) poppler_index_iter_free(viewer
->pdf_index
);
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
);
1590 static gboolean
pdf_viewer_scroll_page(MimeViewer
*_viewer
, gboolean up
)
1592 PdfViewer
*viewer
= (PdfViewer
*)_viewer
;
1593 GtkAdjustment
*vadj
= gtk_scrolled_window_get_vadjustment(
1594 GTK_SCROLLED_WINDOW(viewer
->scrollwin
));
1596 gint cur_p
= gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer
->cur_page
));
1598 if (viewer
->pdf_view
== NULL
) return FALSE
;
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);
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);
1623 static void pdf_viewer_scroll_one_line(MimeViewer
*_viewer
, gboolean up
)
1625 PdfViewer
*viewer
= (PdfViewer
*)_viewer
;
1626 GtkAdjustment
*vadj
= gtk_scrolled_window_get_vadjustment(
1627 GTK_SCROLLED_WINDOW(viewer
->scrollwin
));
1629 cur_p
= gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(viewer
->cur_page
));
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
);
1637 if (cur_p
!= viewer
->num_pages
) {
1638 pdf_viewer_scroll_page((MimeViewer
*)viewer
, up
);
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), \
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), \
1659 #define ADD_SEP_TO_GRID \
1660 sep = gtk_label_new(""); \
1661 gtk_grid_attach(GTK_GRID(viewer->widgets_table), GTK_WIDGET(sep), \
1663 gtk_grid_set_column_spacing(GTK_GRID(viewer->widgets_table), 3); \
1666 #if POPPLER_HAS_CAIRO
1667 static PangoContext
*pdf_viewer_get_pango_context(gpointer data
)
1672 static gpointer
pdf_viewer_get_data_to_print(gpointer data
, gint sel_start
, gint sel_end
)
1674 return NULL
; /* we don't need it */
1677 static void pdf_viewer_cb_begin_print(GtkPrintOperation
*op
, GtkPrintContext
*context
,
1680 PrintData
*print_data
;
1681 PopplerDocument
*pdf_doc
;
1683 print_data
= (PrintData
*) user_data
;
1684 pdf_doc
= (PopplerDocument
*)printing_get_renderer_data(print_data
);
1686 debug_print("Preparing print job...\n");
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
);
1692 debug_print("Starting print job...\n");
1695 static void pdf_viewer_cb_draw_page(GtkPrintOperation
*op
, GtkPrintContext
*context
,
1696 int page_nr
, gpointer user_data
)
1699 PrintData
*print_data
;
1700 PopplerDocument
*pdf_doc
;
1701 PopplerPage
*pdf_page
;
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
);
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.);
1711 poppler_page_render_for_printing(pdf_page
, cr
);
1713 g_object_unref(G_OBJECT(pdf_page
));
1715 debug_print("Sent page %d to printer\n", page_nr
+1);
1718 static void pdf_viewer_print(MimeViewer
*mviewer
)
1720 PdfViewer
*viewer
= (PdfViewer
*)mviewer
;
1721 PrintRenderer
*pdf_renderer
= g_new0(PrintRenderer
, 1);
1722 MainWindow
*mainwin
= mainwindow_get_mainwindow();
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
;
1729 printing_print_full(mainwin
? GTK_WINDOW(mainwin
->window
):NULL
,
1730 pdf_renderer
, viewer
->pdf_doc
, -1, -1, NULL
);
1732 g_free(pdf_renderer
);
1736 static MimeViewer
*pdf_viewer_create(void)
1739 GtkTreeViewColumn
*column
;
1740 GtkCellRenderer
*renderer
;
1741 GtkTreeStore
*tree_store
;
1746 viewer
= g_new0(PdfViewer
, 1);
1747 debug_print("pdf_viewer_create\n");
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
;
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
);
1768 viewer
->mimeinfo
= NULL
;
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
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();
1781 gtk_container_add(GTK_CONTAINER(viewer
->icon_type_ebox
), viewer
->icon_type
);
1783 viewer
->doc_label
= gtk_label_new("");
1785 viewer
->widgets_table
= gtk_grid_new();
1787 viewer
->doc_index_pane
= gtk_paned_new(GTK_ORIENTATION_HORIZONTAL
);
1788 gtk_widget_set_name(GTK_WIDGET(viewer
->doc_index_pane
), "document_pane");
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"));
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);
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
),
1809 gtk_grid_attach(GTK_GRID(viewer
->widgets_table
), GTK_WIDGET(viewer
->doc_label
),
1813 ADD_BUTTON_TO_GRID(viewer
->next_page
, STOCK_PIXMAP_RIGHT_ARROW
)
1814 ADD_BUTTON_TO_GRID(viewer
->last_page
, STOCK_PIXMAP_LAST_ARROW
)
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
),
1821 ADD_BUTTON_TO_GRID(viewer
->zoom_out
, STOCK_PIXMAP_ZOOM_OUT
)
1822 ADD_BUTTON_TO_GRID(viewer
->zoom_width
, STOCK_PIXMAP_ZOOM_WIDTH
)
1824 ADD_BUTTON_TO_GRID(viewer
->rotate_left
, STOCK_PIXMAP_ROTATE_LEFT
)
1825 ADD_BUTTON_TO_GRID(viewer
->rotate_right
, STOCK_PIXMAP_ROTATE_RIGHT
)
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
)
1831 gtk_scrolled_window_set_policy(
1832 GTK_SCROLLED_WINDOW(viewer
->scrollwin
),
1833 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
1835 gtk_scrolled_window_set_shadow_type(
1836 GTK_SCROLLED_WINDOW(viewer
->scrollwin
),
1840 GTK_CONTAINER(viewer
->scrollwin
),
1841 viewer
->pdf_view_ebox
);
1843 viewer
->vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 4);
1844 viewer
->hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 4);
1846 gtk_widget_set_name(GTK_WIDGET(viewer
->vbox
), "pdf_viewer");
1847 gtk_widget_set_name(GTK_WIDGET(viewer
->hbox
), "buttons");
1850 tree_store
= gtk_tree_store_new(N_INDEX_COLUMNS
,
1855 viewer
->index_list
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(tree_store
));
1856 g_object_unref(tree_store
);
1858 renderer
= gtk_cell_renderer_text_new();
1859 column
= gtk_tree_view_column_new_with_attributes(_("Name"), renderer
, "text", 0, NULL
);
1860 gtk_tree_view_append_column(GTK_TREE_VIEW(viewer
->index_list
), column
);
1861 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(viewer
->index_list
), FALSE
);
1863 viewer
->index_model
= GTK_TREE_MODEL(tree_store
);
1865 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(viewer
->index_list
)),
1866 GTK_SELECTION_SINGLE
);
1868 g_signal_connect(G_OBJECT(viewer
->index_list
), "row_activated",
1869 G_CALLBACK(pdf_viewer_index_row_activated
),
1872 gtk_scrolled_window_set_policy(
1873 GTK_SCROLLED_WINDOW(viewer
->scrollwin_index
),
1874 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
1876 gtk_scrolled_window_set_shadow_type(
1877 GTK_SCROLLED_WINDOW(viewer
->scrollwin_index
),
1881 GTK_CONTAINER(viewer
->scrollwin_index
),
1882 viewer
->index_list
);
1886 stock_pixbuf_gdk(STOCK_PIXMAP_MIME_TEXT_PLAIN
,
1887 &viewer
->icon_pixbuf
);
1889 gtk_image_set_from_pixbuf(GTK_IMAGE(viewer
->icon_type
),
1890 viewer
->icon_pixbuf
);
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);
1896 gtk_container_add(GTK_CONTAINER(viewer
->frame_index
), viewer
->scrollwin_index
);
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
);
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);
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
));
1919 gtk_widget_show(GTK_WIDGET(viewer
->widgets_table
));
1920 g_object_ref(GTK_WIDGET(viewer
->widgets_table
));
1922 gtk_widget_show(GTK_WIDGET(viewer
->cur_page
));
1923 g_object_ref(GTK_WIDGET(viewer
->cur_page
));
1925 gtk_widget_show(GTK_WIDGET(viewer
->first_page
));
1926 g_object_ref(GTK_WIDGET(viewer
->first_page
));
1928 gtk_widget_show(GTK_WIDGET(viewer
->last_page
));
1929 g_object_ref(GTK_WIDGET(viewer
->last_page
));
1931 gtk_widget_show(GTK_WIDGET(viewer
->prev_page
));
1932 g_object_ref(GTK_WIDGET(viewer
->prev_page
));
1934 gtk_widget_show(GTK_WIDGET(viewer
->next_page
));
1935 g_object_ref(GTK_WIDGET(viewer
->next_page
));
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
));
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
));
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
));
1966 gtk_widget_show(GTK_WIDGET(viewer
->index_list
));
1967 g_object_ref(GTK_WIDGET(viewer
->index_list
));
1970 CLAWS_SET_TIP(viewer
->first_page
,
1973 CLAWS_SET_TIP(viewer
->prev_page
,
1974 _("Previous Page"));
1976 CLAWS_SET_TIP(viewer
->next_page
,
1979 CLAWS_SET_TIP(viewer
->last_page
,
1982 CLAWS_SET_TIP(viewer
->zoom_in
,
1984 CLAWS_SET_TIP(viewer
->zoom_out
,
1987 CLAWS_SET_TIP(viewer
->zoom_fit
,
1990 CLAWS_SET_TIP(viewer
->zoom_width
,
1991 _("Fit Page Width"));
1993 CLAWS_SET_TIP(viewer
->rotate_left
,
1996 CLAWS_SET_TIP(viewer
->rotate_right
,
1999 CLAWS_SET_TIP(viewer
->print
,
2000 _("Print Document"));
2002 CLAWS_SET_TIP(viewer
->doc_info
,
2003 _("Document Info"));
2005 CLAWS_SET_TIP(viewer
->doc_index
,
2006 _("Document Index"));
2007 CLAWS_SET_TIP(viewer
->cur_page
,
2009 CLAWS_SET_TIP(viewer
->zoom_scroll
,
2011 /* Connect Signals */
2012 g_signal_connect(G_OBJECT(viewer
->cur_page
),
2014 G_CALLBACK(pdf_viewer_spin_change_page_cb
),
2017 g_signal_connect(G_OBJECT(viewer
->first_page
),
2019 G_CALLBACK(pdf_viewer_button_first_page_cb
),
2021 g_signal_connect(G_OBJECT(viewer
->prev_page
),
2023 G_CALLBACK(pdf_viewer_button_prev_page_cb
),
2025 g_signal_connect(G_OBJECT(viewer
->next_page
),
2027 G_CALLBACK(pdf_viewer_button_next_page_cb
),
2029 g_signal_connect(G_OBJECT(viewer
->last_page
),
2031 G_CALLBACK(pdf_viewer_button_last_page_cb
),
2033 g_signal_connect(G_OBJECT(viewer
->zoom_in
),
2035 G_CALLBACK(pdf_viewer_button_zoom_in_cb
),
2037 g_signal_connect(G_OBJECT(viewer
->zoom_out
),
2039 G_CALLBACK(pdf_viewer_button_zoom_out_cb
),
2041 g_signal_connect(G_OBJECT(viewer
->zoom_scroll
),
2043 G_CALLBACK(pdf_viewer_spin_zoom_scroll_cb
),
2046 g_signal_connect(G_OBJECT(viewer
->zoom_fit
),
2048 G_CALLBACK(pdf_viewer_button_zoom_fit_cb
),
2051 g_signal_connect(G_OBJECT(viewer
->zoom_width
),
2053 G_CALLBACK(pdf_viewer_button_zoom_width_cb
),
2056 g_signal_connect(G_OBJECT(viewer
->rotate_right
),
2058 G_CALLBACK(pdf_viewer_button_rotate_right_cb
),
2061 g_signal_connect(G_OBJECT(viewer
->rotate_left
),
2063 G_CALLBACK(pdf_viewer_button_rotate_left_cb
),
2066 g_signal_connect(G_OBJECT(viewer
->print
),
2068 G_CALLBACK(pdf_viewer_button_print_cb
),
2071 g_signal_connect(G_OBJECT(viewer
->doc_info
),
2073 G_CALLBACK(pdf_viewer_button_document_info_cb
),
2076 g_signal_connect(G_OBJECT(viewer
->doc_index
),
2078 G_CALLBACK(pdf_viewer_show_document_index_cb
),
2080 g_signal_connect(G_OBJECT(viewer
->scrollwin
),
2082 G_CALLBACK(pdf_viewer_scroll_cb
),
2084 g_signal_connect(G_OBJECT(viewer
->pdf_view_ebox
),
2085 "button_press_event",
2086 G_CALLBACK(pdf_viewer_button_press_events_cb
),
2088 g_signal_connect(G_OBJECT(viewer
->pdf_view_ebox
),
2089 "button_release_event",
2090 G_CALLBACK(pdf_viewer_mouse_scroll_destroy_cb
),
2092 g_signal_connect(G_OBJECT(viewer
->pdf_view_ebox
),
2093 "motion_notify_event",
2094 G_CALLBACK(pdf_viewer_move_events_cb
),
2097 viewer
->target_filename
= NULL
;
2098 viewer
->filename
= NULL
;
2099 viewer
->fsname
= NULL
;
2101 return(MimeViewer
*) viewer
;
2104 #undef ADD_BUTTON_TO_GRID
2105 #undef ADD_TOGGLE_BUTTON_TO_GRID
2106 #undef ADD_SEP_TO_GRID
2107 #undef SEP_H_PADDING
2109 static MimeViewerFactory pdf_viewer_factory
=
2116 gint
plugin_init(gchar
**error
)
2118 gchar
*gspath
= NULL
;
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());
2125 if (!check_plugin_version(MAKE_NUMERIC_VERSION(3,8,1,46),
2126 VERSION_NUMERIC
, _("PDF Viewer"), error
)) return -1;
2128 if ((gspath
= g_find_program_in_path("gs")) == NULL
) {
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
);
2141 mimeview_register_viewer_factory(&pdf_viewer_factory
);
2145 gboolean
plugin_done(void)
2148 mimeview_unregister_viewer_factory(&pdf_viewer_factory
);
2152 const gchar
*plugin_name(void)
2154 return _("PDF Viewer");
2157 const gchar
*plugin_desc(void)
2162 const gchar
*plugin_type(void)
2167 const gchar
*plugin_licence(void)
2172 const gchar
*plugin_version(void)
2177 struct PluginFeature
*plugin_provides(void)
2179 static struct PluginFeature features
[] =
2180 { {PLUGIN_MIMEVIEWER
, "application/pdf"},
2181 {PLUGIN_MIMEVIEWER
, "application/postscript"},
2182 {PLUGIN_NOTHING
, NULL
} };