1 /* Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
2 * Copyright (C) 2007-2012 Holger Berndt <hb@claws-mail.org>,
3 * Colin Leroy <colin@colino.net>, and the Claws Mail team
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/>.
22 #include "claws-features.h"
28 #include "image_viewer.h"
32 #include "prefs_common.h"
34 #include <glib/gi18n.h>
35 #include <gdk/gdkkeysyms.h>
37 #include <pango/pango.h>
42 PrintRenderer
*renderer
;
43 gpointer renderer_data
;
45 PangoContext
*pango_context
;
59 GtkPrintOperation
*op
;
60 GtkPrintOperationPreview
*preview
;
62 GtkWidget
*scrolled_window
;
64 PrintData
*print_data
;
65 GtkWidget
*page_nr_label
;
66 GList
*pages_to_print
;
80 GtkPrintContext
*context
;
84 static void printing_textview_cb_begin_print(GtkPrintOperation
*,
85 GtkPrintContext
*, gpointer
);
86 static void printing_textview_cb_draw_page(GtkPrintOperation
*,
87 GtkPrintContext
*, gint
,
89 static gboolean
cb_preview(GtkPrintOperation
*, GtkPrintOperationPreview
*,
90 GtkPrintContext
*, GtkWindow
*, gpointer
);
91 static void cb_preview_destroy(GtkWindow
*, gpointer
);
92 static gboolean
cb_preview_close(GtkWidget
*, GdkEventAny
*, gpointer
);
93 static void cb_preview_size_allocate(GtkWidget
*, GtkAllocation
*);
94 static void cb_preview_ready(GtkPrintOperationPreview
*,
95 GtkPrintContext
*, gpointer
);
96 #if !GTK_CHECK_VERSION(3, 0, 0)
97 static gboolean
cb_preview_expose(GtkWidget
*, GdkEventExpose
*, gpointer
);
99 static gboolean
cb_preview_expose(GtkWidget
*, cairo_t
*, gpointer
);
101 static void cb_preview_got_page_size(GtkPrintOperationPreview
*,
103 GtkPageSetup
*, gpointer
);
104 static void cb_preview_go_first(GtkButton
*, gpointer
);
105 static void cb_preview_go_previous(GtkButton
*, gpointer
);
106 static void cb_preview_go_next(GtkButton
*, gpointer
);
107 static void cb_preview_go_last(GtkButton
*, gpointer
);
108 static void cb_preview_btn_close(GtkButton
*, gpointer
);
109 static void cb_preview_zoom_100(GtkButton
*, gpointer
);
110 static void cb_preview_zoom_fit(GtkButton
*, gpointer
);
111 static void cb_preview_zoom_in(GtkButton
*, gpointer
);
112 static void cb_preview_zoom_out(GtkButton
*, gpointer
);
113 static void cb_preview_request_page_setup(GtkPrintOperation
*,
115 gint
,GtkPageSetup
*,gpointer
);
117 static void printing_preview_update_zoom_sensitivity(PreviewData
*);
120 static GtkPrintSettings
*settings
= NULL
;
121 static GtkPageSetup
*page_setup
= NULL
;
123 /* other static functions */
124 static void printing_layout_set_text_attributes(PrintData
*, GtkPrintContext
*, gboolean
*);
125 static gboolean
printing_is_pango_gdk_color_equal(PangoColor
*, GdkColor
*);
126 static gint
printing_text_iter_get_offset_bytes(PrintData
*, const GtkTextIter
*);
128 #define PAGE_MARGIN_STORAGE_UNIT GTK_UNIT_MM
129 #define PREVIEW_SCALE 72
130 #define PREVIEW_SHADOW_OFFSET 3
131 #define PREVIEW_ZOOM_FAC 1.41
132 #define PREVIEW_ZOOM_MAX 10.
133 #define PREVIEW_ZOOM_MIN 0.2
135 static void free_pixbuf(gpointer key
, gpointer value
, gpointer data
)
137 PangoAttrShape
*attr
= (PangoAttrShape
*) value
;
138 g_object_unref(G_OBJECT(attr
->data
));
141 gpointer
printing_get_renderer_data(PrintData
*print_data
)
145 return print_data
->renderer_data
;
148 gdouble
printing_get_zoom(PrintData
*print_data
)
152 return print_data
->zoom
;
155 void printing_set_n_pages(PrintData
*print_data
, gint n_pages
)
159 print_data
->npages
= n_pages
;
162 GtkPrintSettings
*printing_get_settings(void)
164 if (settings
== NULL
) {
165 settings
= gtk_print_settings_new();
166 gtk_print_settings_set_use_color(settings
, prefs_common
.print_use_color
);
167 gtk_print_settings_set_collate(settings
, prefs_common
.print_use_collate
);
168 gtk_print_settings_set_reverse(settings
, prefs_common
.print_use_reverse
);
169 gtk_print_settings_set_duplex(settings
, prefs_common
.print_use_duplex
);
174 void printing_store_settings(GtkPrintSettings
*new_settings
)
176 if (settings
!= NULL
)
177 g_object_unref(settings
);
179 settings
= g_object_ref(new_settings
);
180 prefs_common
.print_use_color
= gtk_print_settings_get_use_color(settings
);
181 prefs_common
.print_use_collate
= gtk_print_settings_get_collate(settings
);
182 prefs_common
.print_use_reverse
= gtk_print_settings_get_reverse(settings
);
183 prefs_common
.print_use_duplex
= gtk_print_settings_get_duplex(settings
);
186 GtkPageSetup
*printing_get_page_setup(void)
188 if (page_setup
== NULL
) {
189 gboolean read_from_file
;
190 char *page_setup_filename
;
192 gboolean key_file_read
;
194 page_setup
= gtk_page_setup_new();
196 read_from_file
= FALSE
;
198 /* try reading the page setup from file */
199 page_setup_filename
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
200 PRINTING_PAGE_SETUP_STORAGE_FILE
, NULL
);
201 keyfile
= g_key_file_new();
202 key_file_read
= g_key_file_load_from_file(keyfile
, page_setup_filename
,
204 g_free(page_setup_filename
);
207 read_from_file
= gtk_page_setup_load_key_file(page_setup
, keyfile
,
209 g_key_file_free(keyfile
);
211 if (read_from_file
) {
212 debug_print("Printing: Read page setup from key file\n");
214 debug_print("Printing: Could not read page setup from key file\n");
217 /* if reading from file did not work, or has not been tried (GTK+ < 2.14), use prefs */
218 if (!read_from_file
) {
220 if (prefs_common
.print_paper_type
&&
221 *prefs_common
.print_paper_type
) {
222 GtkPaperSize
*paper
= gtk_paper_size_new(prefs_common
.print_paper_type
);
223 gtk_page_setup_set_paper_size(page_setup
, paper
);
224 gtk_paper_size_free(paper
);
227 gtk_page_setup_set_orientation(page_setup
,
228 prefs_common
.print_paper_orientation
);
230 if (prefs_common
.print_margin_top
!= -1)
231 gtk_page_setup_set_top_margin(page_setup
,
232 0.01*prefs_common
.print_margin_top
,
233 PAGE_MARGIN_STORAGE_UNIT
);
234 if (prefs_common
.print_margin_bottom
!= -1)
235 gtk_page_setup_set_bottom_margin(page_setup
,
236 0.01*prefs_common
.print_margin_bottom
,
237 PAGE_MARGIN_STORAGE_UNIT
);
238 if (prefs_common
.print_margin_left
!= -1)
239 gtk_page_setup_set_left_margin(page_setup
,
240 0.01*prefs_common
.print_margin_left
,
241 PAGE_MARGIN_STORAGE_UNIT
);
242 if (prefs_common
.print_margin_right
!= -1)
243 gtk_page_setup_set_right_margin(page_setup
,
244 0.01*prefs_common
.print_margin_right
,
245 PAGE_MARGIN_STORAGE_UNIT
);
251 void printing_print_full(GtkWindow
*parent
, PrintRenderer
*renderer
, gpointer renderer_data
,
252 gint sel_start
, gint sel_end
, GtkImage
*avatar
)
254 GtkPrintOperation
*op
;
255 GtkPrintOperationResult res
;
256 PrintData
*print_data
;
258 op
= gtk_print_operation_new();
260 print_data
= g_new0(PrintData
,1);
262 print_data
->renderer
= renderer
;
263 print_data
->renderer_data
= renderer_data
;
264 print_data
->sel_start
= sel_start
;
265 print_data
->sel_end
= sel_end
;
266 print_data
->avatar
= (avatar
!= NULL
? GTK_IMAGE(g_object_ref(avatar
)): NULL
);
268 print_data
->zoom
= 1.;
270 print_data
->images
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
272 print_data
->pango_context
= renderer
->get_pango_context(renderer_data
);
274 print_data
->to_print
= renderer
->get_data_to_print(renderer_data
, sel_start
, sel_end
);
276 printing_get_settings();
277 printing_get_page_setup();
279 /* Config for printing */
280 gtk_print_operation_set_print_settings(op
, settings
);
281 gtk_print_operation_set_default_page_setup(op
, page_setup
);
282 #if GTK_CHECK_VERSION(2,18,0)
283 /* enable Page Size and Orientation in the print dialog */
284 gtk_print_operation_set_embed_page_setup(op
, TRUE
);
287 g_signal_connect(op
, "begin_print", G_CALLBACK(renderer
->cb_begin_print
), print_data
);
288 g_signal_connect(op
, "draw_page", G_CALLBACK(renderer
->cb_draw_page
), print_data
);
289 g_signal_connect(op
, "preview", G_CALLBACK(cb_preview
), print_data
);
291 /* Start printing process */
292 res
= gtk_print_operation_run(op
, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG
,
295 if (res
== GTK_PRINT_OPERATION_RESULT_ERROR
) {
296 GError
*error
= NULL
;
297 gtk_print_operation_get_error(op
, &error
);
298 debug_print("Error printing message: %s\n",
299 error
? error
->message
: "no details");
300 } else if (res
== GTK_PRINT_OPERATION_RESULT_APPLY
) {
301 /* store settings for next printing session */
302 printing_store_settings(gtk_print_operation_get_print_settings(op
));
305 g_hash_table_foreach(print_data
->images
, free_pixbuf
, NULL
);
306 g_hash_table_destroy(print_data
->images
);
307 if (print_data
->to_print
)
308 g_free(print_data
->to_print
);
309 g_list_free(print_data
->page_breaks
);
310 if (print_data
->layout
)
311 g_object_unref(print_data
->layout
);
312 if (print_data
->avatar
)
313 g_object_unref(print_data
->avatar
);
318 debug_print("printing_print finished\n");
321 static PangoContext
*printing_textview_get_pango_context(gpointer data
)
323 return gtk_widget_get_pango_context(GTK_WIDGET(data
));
326 static gpointer
printing_textview_get_data_to_print(gpointer data
, gint sel_start
, gint sel_end
)
328 GtkTextView
*text_view
= GTK_TEXT_VIEW(data
);
329 GtkTextBuffer
*buffer
= gtk_text_view_get_buffer(text_view
);
330 GtkTextIter start
, end
;
332 if (sel_start
< 0 || sel_end
<= sel_start
) {
333 gtk_text_buffer_get_start_iter(buffer
, &start
);
334 gtk_text_buffer_get_end_iter(buffer
, &end
);
336 gtk_text_buffer_get_iter_at_offset(buffer
, &start
, sel_start
);
337 gtk_text_buffer_get_iter_at_offset(buffer
, &end
, sel_end
);
340 return gtk_text_buffer_get_text(buffer
, &start
, &end
, FALSE
);
343 void printing_print(GtkTextView
*text_view
, GtkWindow
*parent
, gint sel_start
, gint sel_end
, GtkImage
*avatar
)
345 PrintRenderer
*textview_renderer
= g_new0(PrintRenderer
, 1);
347 textview_renderer
->get_pango_context
= printing_textview_get_pango_context
;
348 textview_renderer
->get_data_to_print
= printing_textview_get_data_to_print
;
349 textview_renderer
->cb_begin_print
= printing_textview_cb_begin_print
;
350 textview_renderer
->cb_draw_page
= printing_textview_cb_draw_page
;
352 printing_print_full(parent
, textview_renderer
, text_view
, sel_start
, sel_end
, avatar
);
354 g_free(textview_renderer
);
357 void printing_page_setup(GtkWindow
*parent
)
359 GtkPageSetup
*new_page_setup
;
364 printing_get_settings();
365 printing_get_page_setup();
367 new_page_setup
= gtk_print_run_page_setup_dialog(parent
,page_setup
,settings
);
370 g_object_unref(page_setup
);
372 page_setup
= new_page_setup
;
374 g_free(prefs_common
.print_paper_type
);
375 prefs_common
.print_paper_type
= g_strdup(gtk_paper_size_get_name(
376 gtk_page_setup_get_paper_size(page_setup
)));
377 prefs_common
.print_paper_orientation
= gtk_page_setup_get_orientation(page_setup
);
378 /* store 100th millimeters */
379 prefs_common
.print_margin_top
= (int) (100*gtk_page_setup_get_top_margin(page_setup
,
380 PAGE_MARGIN_STORAGE_UNIT
));
381 prefs_common
.print_margin_bottom
= (int) (100*gtk_page_setup_get_bottom_margin(page_setup
,
382 PAGE_MARGIN_STORAGE_UNIT
));
383 prefs_common
.print_margin_left
= (int) (100*gtk_page_setup_get_left_margin(page_setup
,
384 PAGE_MARGIN_STORAGE_UNIT
));
385 prefs_common
.print_margin_right
= (int) (100*gtk_page_setup_get_right_margin(page_setup
,
386 PAGE_MARGIN_STORAGE_UNIT
));
389 keyfile
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
390 PRINTING_PAGE_SETUP_STORAGE_FILE
, NULL
);
391 if (!gtk_page_setup_to_file(page_setup
, keyfile
, NULL
)) {
392 debug_print("Printing: Could not store page setup in file `%s'\n", keyfile
);
397 static gboolean
cb_preview(GtkPrintOperation
*operation
,
398 GtkPrintOperationPreview
*preview
,
399 GtkPrintContext
*context
,
403 PrintData
*print_data
;
405 PreviewData
*preview_data
;
411 GtkToolItem
*separator
;
412 static GdkGeometry geometry
;
413 GtkWidget
*dialog
= NULL
;
414 GtkWidget
*statusbar
= gtk_hbox_new(2, FALSE
);
416 debug_print("Creating internal print preview\n");
418 print_data
= (PrintData
*) data
;
420 preview_data
= g_new0(PreviewData
,1);
421 preview_data
->print_data
= print_data
;
422 preview_data
->op
= g_object_ref(operation
);
423 preview_data
->preview
= preview
;
426 dialog
= gtkut_window_new(GTK_WINDOW_TOPLEVEL
, "print_preview");
427 preview_data
->dialog
= dialog
;
428 if (!geometry
.min_height
) {
429 geometry
.min_width
= 600;
430 geometry
.min_height
= 400;
432 gtk_window_set_geometry_hints(GTK_WINDOW(dialog
), NULL
, &geometry
,
434 gtk_widget_set_size_request(dialog
, prefs_common
.print_previewwin_width
,
435 prefs_common
.print_previewwin_height
);
436 gtk_window_set_title(GTK_WINDOW(dialog
), _("Print preview"));
439 vbox
= gtk_vbox_new(FALSE
, 0);
440 gtk_container_add(GTK_CONTAINER(dialog
), vbox
);
443 toolbar
= gtk_toolbar_new();
444 gtk_orientable_set_orientation(GTK_ORIENTABLE(toolbar
), GTK_ORIENTATION_HORIZONTAL
);
446 switch (prefs_common
.toolbar_style
) {
448 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar
), GTK_TOOLBAR_ICONS
);
451 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar
), GTK_TOOLBAR_TEXT
);
453 case TOOLBAR_BOTH_HORIZ
:
454 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar
), GTK_TOOLBAR_BOTH_HORIZ
);
458 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar
), GTK_TOOLBAR_BOTH
);
460 gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolbar
), TRUE
);
462 gtk_box_pack_start(GTK_BOX(vbox
), toolbar
, FALSE
, FALSE
, 0);
464 #define CLAWS_SET_TOOL_ITEM_TIP(widget,tip) { \
465 gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), tip); \
468 #define TOOLBAR_ITEM(item,text,tooltip,cb,cbdata) { \
469 item = GTK_WIDGET(gtk_tool_button_new_from_stock(text)); \
470 gtk_tool_item_set_homogeneous(GTK_TOOL_ITEM(item), FALSE); \
471 gtk_tool_item_set_is_important(GTK_TOOL_ITEM(item), TRUE); \
472 gtk_toolbar_insert(GTK_TOOLBAR(toolbar), GTK_TOOL_ITEM(item), -1); \
473 g_signal_connect (G_OBJECT(item), "clicked", G_CALLBACK(cb), cbdata); \
474 CLAWS_SET_TOOL_ITEM_TIP(GTK_TOOL_ITEM(item), \
478 TOOLBAR_ITEM(preview_data
->first
, GTK_STOCK_GOTO_FIRST
,
479 _("First page"), cb_preview_go_first
, preview_data
);
480 TOOLBAR_ITEM(preview_data
->previous
, GTK_STOCK_GO_BACK
,
481 _("Previous page"), cb_preview_go_previous
, preview_data
);
483 page
= gtk_label_new("");
484 gtk_widget_set_size_request(page
, 100, -1);
485 preview_data
->page_nr_label
= page
;
487 TOOLBAR_ITEM(preview_data
->next
, GTK_STOCK_GO_FORWARD
,
488 _("Next page"), cb_preview_go_next
, preview_data
);
489 TOOLBAR_ITEM(preview_data
->last
, GTK_STOCK_GOTO_LAST
,
490 _("Last page"), cb_preview_go_last
, preview_data
);
492 separator
= gtk_separator_tool_item_new();
493 gtk_toolbar_insert(GTK_TOOLBAR(toolbar
), GTK_TOOL_ITEM(separator
), -1);
495 TOOLBAR_ITEM(preview_data
->zoom_100
, GTK_STOCK_ZOOM_100
,
496 _("Zoom 100%"), cb_preview_zoom_100
, preview_data
);
497 TOOLBAR_ITEM(preview_data
->zoom_fit
, GTK_STOCK_ZOOM_FIT
,
498 _("Zoom fit"), cb_preview_zoom_fit
, preview_data
);
499 TOOLBAR_ITEM(preview_data
->zoom_in
, GTK_STOCK_ZOOM_IN
,
500 _("Zoom in"), cb_preview_zoom_in
, preview_data
);
501 TOOLBAR_ITEM(preview_data
->zoom_out
, GTK_STOCK_ZOOM_OUT
,
502 _("Zoom out"), cb_preview_zoom_out
, preview_data
);
504 separator
= gtk_separator_tool_item_new();
505 gtk_toolbar_insert(GTK_TOOLBAR(toolbar
), GTK_TOOL_ITEM(separator
), -1);
507 /* tooltip has to be NULL else it triggers an expose_event */
508 TOOLBAR_ITEM(preview_data
->close
, GTK_STOCK_CLOSE
, NULL
,
509 cb_preview_btn_close
, preview_data
);
511 gtk_widget_show(statusbar
);
512 gtk_box_pack_start(GTK_BOX(vbox
), statusbar
, FALSE
, FALSE
, 0);
513 gtk_box_pack_start(GTK_BOX(statusbar
), page
, FALSE
, FALSE
, 0);
515 sw
= gtk_scrolled_window_new(NULL
, NULL
);
516 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
),
517 GTK_POLICY_AUTOMATIC
,
518 GTK_POLICY_AUTOMATIC
);
519 gtk_box_pack_start(GTK_BOX(vbox
), sw
, TRUE
, TRUE
, 0);
520 da
= gtk_drawing_area_new();
521 gtk_widget_set_double_buffered(da
, FALSE
);
522 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw
),
524 gtk_widget_realize(da
);
525 preview_data
->scrolled_window
= sw
;
526 preview_data
->area
= da
;
529 cr
= gdk_cairo_create(gtk_widget_get_window(da
));
530 gtk_print_context_set_cairo_context(context
, cr
, PREVIEW_SCALE
, PREVIEW_SCALE
);
534 g_signal_connect(dialog
, "key_press_event",
535 G_CALLBACK(cb_preview_close
), preview_data
);
536 g_signal_connect(dialog
, "size_allocate",
537 G_CALLBACK(cb_preview_size_allocate
), NULL
);
538 g_signal_connect(dialog
, "destroy",G_CALLBACK(cb_preview_destroy
),
540 g_signal_connect(preview
, "ready", G_CALLBACK(cb_preview_ready
),
542 g_signal_connect(preview
, "got-page-size",
543 G_CALLBACK(cb_preview_got_page_size
), preview_data
);
545 g_signal_connect(operation
, "request-page-setup",
546 G_CALLBACK(cb_preview_request_page_setup
), preview_data
);
548 gtk_widget_show_all(dialog
);
552 static void cb_preview_destroy(GtkWindow
*window
, gpointer data
)
554 PreviewData
*preview_data
;
555 preview_data
= (PreviewData
*) data
;
557 if (preview_data
->rendering
)
559 debug_print("Preview window destroyed\n");
561 gtk_print_operation_preview_end_preview(preview_data
->preview
);
562 g_object_unref(preview_data
->op
);
563 g_list_free(preview_data
->pages_to_print
);
565 g_free(preview_data
);
568 static gboolean
cb_preview_close(GtkWidget
*widget
, GdkEventAny
*event
,
571 PreviewData
*preview_data
= (PreviewData
*)data
;
572 if (event
->type
== GDK_KEY_PRESS
)
573 if (((GdkEventKey
*)event
)->keyval
!= GDK_KEY_Escape
)
575 if (preview_data
->rendering
)
577 gtk_widget_destroy(widget
);
581 static void cb_preview_size_allocate(GtkWidget
*widget
,
582 GtkAllocation
*allocation
)
584 cm_return_if_fail(allocation
!= NULL
);
586 prefs_common
.print_previewwin_width
= allocation
->width
;
587 prefs_common
.print_previewwin_height
= allocation
->height
;
590 static void cb_preview_ready(GtkPrintOperationPreview
*preview
,
591 GtkPrintContext
*context
,
594 PreviewData
*preview_data
;
596 preview_data
= (PreviewData
*) data
;
597 debug_print("preview_ready %d\n", preview_data
->print_data
->npages
);
599 for (iPage
= 0; iPage
< (preview_data
->print_data
->npages
); iPage
++) {
600 if (gtk_print_operation_preview_is_selected(preview_data
->preview
, iPage
)) {
601 preview_data
->pages_to_print
=
602 g_list_prepend(preview_data
->pages_to_print
,
603 GINT_TO_POINTER(iPage
));
604 debug_print("want to print page %d\n",iPage
+1);
608 preview_data
->pages_to_print
= g_list_reverse(preview_data
->pages_to_print
);
609 preview_data
->current_page
= preview_data
->pages_to_print
;
610 preview_data
->context
= context
;
612 #if !GTK_CHECK_VERSION(3, 0, 0)
613 g_signal_connect(preview_data
->area
, "expose_event",
614 G_CALLBACK(cb_preview_expose
),
617 g_signal_connect(preview_data
->area
, "draw",
618 G_CALLBACK(cb_preview_expose
),
622 gtk_widget_queue_draw(preview_data
->area
);
625 static void cb_preview_got_page_size(GtkPrintOperationPreview
*preview
,
626 GtkPrintContext
*context
,
627 GtkPageSetup
*page_setup
,
630 PreviewData
*preview_data
;
631 GtkPaperSize
*paper_size
;
635 preview_data
= (PreviewData
*) data
;
636 debug_print("got_page_size\n");
637 paper_size
= gtk_page_setup_get_paper_size(page_setup
);
638 paper_width
= (gint
)(gtk_paper_size_get_width(paper_size
, GTK_UNIT_INCH
)
640 paper_height
= (gint
)(gtk_paper_size_get_height(paper_size
, GTK_UNIT_INCH
)
643 preview_data
->page_width
= paper_width
;
644 preview_data
->page_height
= paper_height
;
646 debug_print("w/h %d/%d\n", paper_width
, paper_height
);
647 gtk_widget_set_size_request(GTK_WIDGET(preview_data
->area
),
648 paper_width
, paper_height
);
651 #if !GTK_CHECK_VERSION(3, 0, 0)
652 static gboolean
cb_preview_expose(GtkWidget
*widget
, GdkEventExpose
*event
,
655 static gboolean
cb_preview_expose(GtkWidget
*widget
, cairo_t
*cr
,
659 PreviewData
*preview_data
= data
;
660 #if !GTK_CHECK_VERSION(3, 0, 0)
664 debug_print("preview_expose (current %p)\n", preview_data
->current_page
);
666 #if !GTK_CHECK_VERSION(3, 0, 0)
667 cr
= gdk_cairo_create(gtk_widget_get_window(preview_data
->area
));
671 cairo_set_source_rgb(cr
, 0.5, 0.5, 0.5);
672 #if !GTK_CHECK_VERSION(3, 0, 0)
673 cairo_rectangle(cr
, event
->area
.x
, event
->area
.y
, event
->area
.width
, event
->area
.height
);
678 cairo_set_source_rgb(cr
, 0., 0., 0.);
679 cairo_rectangle(cr
, PREVIEW_SHADOW_OFFSET
, PREVIEW_SHADOW_OFFSET
,
680 preview_data
->page_width
+PREVIEW_SHADOW_OFFSET
,
681 preview_data
->page_height
+PREVIEW_SHADOW_OFFSET
);
685 cairo_set_source_rgb(cr
, 1., 1., 1.);
686 cairo_rectangle(cr
, 0, 0,
687 preview_data
->page_width
,
688 preview_data
->page_height
);
691 gtk_print_context_set_cairo_context(preview_data
->context
, cr
, PREVIEW_SCALE
, PREVIEW_SCALE
);
692 #if !GTK_CHECK_VERSION(3, 0, 0)
696 if (preview_data
->current_page
) {
697 preview_data
->rendering
= TRUE
;
698 gtk_widget_set_sensitive(preview_data
->close
, FALSE
);
699 int cur
= GPOINTER_TO_INT(preview_data
->current_page
->data
);
701 str
= g_strdup_printf(_("Page %d"), cur
+1);
702 gtk_label_set_text(GTK_LABEL(preview_data
->page_nr_label
), str
);
704 gtk_print_operation_preview_render_page(preview_data
->preview
,
706 (preview_data
->current_page
->data
));
708 gtk_widget_set_sensitive(preview_data
->first
,
709 preview_data
->current_page
->prev
!= NULL
);
710 gtk_widget_set_sensitive(preview_data
->previous
,
711 preview_data
->current_page
->prev
!= NULL
);
712 gtk_widget_set_sensitive(preview_data
->next
,
713 preview_data
->current_page
->next
!= NULL
);
714 gtk_widget_set_sensitive(preview_data
->last
,
715 preview_data
->current_page
->next
!= NULL
);
716 gtk_widget_set_sensitive(preview_data
->close
, TRUE
);
717 preview_data
->rendering
= FALSE
;
722 static void cb_preview_go_first(GtkButton
*button
, gpointer data
)
724 PreviewData
*preview_data
= (PreviewData
*) data
;
725 preview_data
->current_page
= preview_data
->pages_to_print
;
726 gtk_widget_queue_draw(preview_data
->area
);
729 static void cb_preview_go_previous(GtkButton
*button
, gpointer data
)
732 PreviewData
*preview_data
= (PreviewData
*) data
;
733 next
= g_list_previous(preview_data
->current_page
);
735 preview_data
->current_page
= next
;
736 gtk_widget_queue_draw(preview_data
->area
);
739 static void cb_preview_go_next(GtkButton
*button
, gpointer data
)
742 PreviewData
*preview_data
= (PreviewData
*) data
;
743 next
= g_list_next(preview_data
->current_page
);
745 preview_data
->current_page
= next
;
746 gtk_widget_queue_draw(preview_data
->area
);
749 static void cb_preview_go_last(GtkButton
*button
, gpointer data
)
751 PreviewData
*preview_data
= (PreviewData
*) data
;
752 preview_data
->current_page
= g_list_last(preview_data
->current_page
);
753 gtk_widget_queue_draw(preview_data
->area
);
756 static void cb_preview_btn_close(GtkButton
*button
, gpointer data
)
758 PreviewData
*preview_data
= (PreviewData
*)data
;
759 if (preview_data
->rendering
)
761 gtk_widget_destroy(preview_data
->dialog
);
764 static void cb_preview_zoom_100(GtkButton
*button
, gpointer data
)
766 PreviewData
*preview_data
= (PreviewData
*) data
;
767 if (preview_data
->print_data
->zoom
!= 1.) {
768 preview_data
->print_data
->zoom
= 1.;
769 gtk_widget_queue_draw(preview_data
->area
);
770 printing_preview_update_zoom_sensitivity(preview_data
);
774 static void cb_preview_zoom_fit(GtkButton
*button
, gpointer data
)
776 PreviewData
*preview_data
= (PreviewData
*) data
;
777 GtkAllocation allocation
;
781 gtk_widget_get_allocation(preview_data
->scrolled_window
, &allocation
);
782 zoom_w
= ((gdouble
)allocation
.width
) /
783 ((gdouble
)preview_data
->page_width
/preview_data
->print_data
->zoom
+
784 PREVIEW_SHADOW_OFFSET
);
785 zoom_h
= ((gdouble
)allocation
.height
) /
786 ((gdouble
)preview_data
->page_height
/preview_data
->print_data
->zoom
+
787 PREVIEW_SHADOW_OFFSET
);
789 preview_data
->print_data
->zoom
= MIN(zoom_w
,zoom_h
) - 0.01;
791 if (preview_data
->print_data
->zoom
> PREVIEW_ZOOM_MAX
)
792 preview_data
->print_data
->zoom
= PREVIEW_ZOOM_MAX
;
793 else if (preview_data
->print_data
->zoom
< PREVIEW_ZOOM_MIN
)
794 preview_data
->print_data
->zoom
= PREVIEW_ZOOM_MIN
;
796 printing_preview_update_zoom_sensitivity(preview_data
);
797 gtk_widget_queue_draw(preview_data
->area
);
800 static void cb_preview_zoom_in(GtkButton
*button
, gpointer data
)
802 PreviewData
*preview_data
= (PreviewData
*) data
;
804 new_zoom
= preview_data
->print_data
->zoom
* PREVIEW_ZOOM_FAC
;
805 if (new_zoom
<= PREVIEW_ZOOM_MAX
) {
806 preview_data
->print_data
->zoom
= new_zoom
;
807 printing_preview_update_zoom_sensitivity(preview_data
);
808 gtk_widget_queue_draw(preview_data
->area
);
812 static void cb_preview_zoom_out(GtkButton
*button
, gpointer data
)
814 PreviewData
*preview_data
= (PreviewData
*) data
;
816 new_zoom
= preview_data
->print_data
->zoom
/ PREVIEW_ZOOM_FAC
;
817 if (new_zoom
>= PREVIEW_ZOOM_MIN
) {
818 preview_data
->print_data
->zoom
= new_zoom
;
819 printing_preview_update_zoom_sensitivity(preview_data
);
820 gtk_widget_queue_draw(preview_data
->area
);
824 static void cb_preview_request_page_setup(GtkPrintOperation
*op
,
825 GtkPrintContext
*context
,
827 GtkPageSetup
*setup
,gpointer data
)
829 GtkPaperSize
*paper_size
;
830 GtkPaperSize
*old_size
;
834 gdouble bottom_margin
;
836 gdouble right_margin
;
838 PreviewData
*preview_data
= (PreviewData
*) data
;
840 old_size
= gtk_page_setup_get_paper_size(setup
);
841 width
= gtk_paper_size_get_width(old_size
,GTK_UNIT_INCH
);
842 height
= gtk_paper_size_get_height(old_size
,GTK_UNIT_INCH
);
844 top_margin
= gtk_page_setup_get_top_margin(setup
,GTK_UNIT_INCH
);
845 bottom_margin
= gtk_page_setup_get_bottom_margin(setup
,GTK_UNIT_INCH
);
846 left_margin
= gtk_page_setup_get_left_margin(setup
,GTK_UNIT_INCH
);
847 right_margin
= gtk_page_setup_get_right_margin(setup
,GTK_UNIT_INCH
);
849 paper_size
= gtk_paper_size_new_custom("preview paper", "preview_paper",
850 width
*preview_data
->print_data
->zoom
,
851 height
*preview_data
->print_data
->zoom
,
853 gtk_page_setup_set_paper_size(setup
, paper_size
);
854 gtk_paper_size_free(paper_size
);
856 gtk_page_setup_set_top_margin(setup
,top_margin
*preview_data
->print_data
->zoom
,
858 gtk_page_setup_set_bottom_margin(setup
,bottom_margin
*preview_data
->print_data
->zoom
,
860 gtk_page_setup_set_left_margin(setup
,left_margin
*preview_data
->print_data
->zoom
,
862 gtk_page_setup_set_right_margin(setup
,right_margin
*preview_data
->print_data
->zoom
,
866 static void printing_textview_cb_begin_print(GtkPrintOperation
*op
, GtkPrintContext
*context
,
869 double width
, height
;
873 PrintData
*print_data
;
874 PangoFontDescription
*desc
;
876 PangoLayoutIter
*iter
;
878 gint num_header_lines
;
880 gboolean header_done
;
881 gboolean has_headers
= FALSE
;
883 double line_height
=0.;
885 print_data
= (PrintData
*) user_data
;
887 debug_print("Preparing print job...\n");
889 width
= gtk_print_context_get_width(context
);
890 height
= gtk_print_context_get_height(context
);
892 if (print_data
->layout
== NULL
)
893 print_data
->layout
= gtk_print_context_create_pango_layout(context
);
895 if (prefs_common
.use_different_print_font
)
896 desc
= pango_font_description_from_string(prefs_common
.printfont
);
898 desc
= pango_font_description_copy(
899 pango_context_get_font_description(print_data
->pango_context
));
901 pango_layout_set_font_description(print_data
->layout
, desc
);
902 pango_font_description_free(desc
);
904 pango_layout_set_width(print_data
->layout
, width
* PANGO_SCALE
);
905 pango_layout_set_text(print_data
->layout
, (char *)print_data
->to_print
, -1);
907 printing_layout_set_text_attributes(print_data
, context
, &has_headers
);
909 num_lines
= pango_layout_get_line_count(print_data
->layout
);
915 iter
= pango_layout_get_iter(print_data
->layout
);
917 /* find the last character of the header */
920 text
= pango_layout_get_text(print_data
->layout
);
923 if (text
&& *text
&& *text
!= '\n') {
925 if (text
[0] == '\n' && (text
[1] != '\0') && (text
[1] == '\n'))
930 } while(*text
&& !header_done
);
932 /* find line number for header end */
933 pango_layout_index_to_line_x(print_data
->layout
, header_end_pos
, 1,
934 &num_header_lines
, &dummy
);
935 /* line count is zero-based */
938 print_data
->ypos_line
= -1.0;
942 PangoRectangle logical_rect
;
943 PangoAttrShape
*attr
= NULL
;
946 pango_layout_iter_get_line_extents(iter
, NULL
, &logical_rect
);
948 if ((attr
= g_hash_table_lookup(print_data
->images
,
949 GINT_TO_POINTER(pango_layout_iter_get_index(iter
)))) != NULL
) {
950 line_height
= (double)gdk_pixbuf_get_height(GDK_PIXBUF(attr
->data
));
952 line_height
= ((double)logical_rect
.height
) / PANGO_SCALE
;
955 if ((page_height
+ line_height
) > height
) {
956 page_breaks
= g_list_prepend(page_breaks
, GINT_TO_POINTER(ii
));
960 if (has_headers
&& ii
== num_header_lines
) {
962 pango_layout_iter_get_line_yrange(iter
,&y0
,&y1
);
963 print_data
->ypos_line
= (double)y0
+ 1./3.*((double)(y1
- y0
))/2.;
966 page_height
+= line_height
;
968 } while(ii
< num_lines
&& pango_layout_iter_next_line(iter
));
969 pango_layout_iter_free(iter
);
971 page_breaks
= g_list_reverse(page_breaks
);
972 print_data
->npages
= g_list_length(page_breaks
) + 1;
973 print_data
->page_breaks
= page_breaks
;
975 gtk_print_operation_set_n_pages(op
, print_data
->npages
);
977 debug_print("Starting print job...\n");
980 static cairo_surface_t
*pixbuf_to_surface(GdkPixbuf
*pixbuf
)
982 cairo_surface_t
*surface
;
983 cairo_format_t format
;
984 static const cairo_user_data_key_t key
;
985 guchar
*pixels
= g_malloc(
987 gdk_pixbuf_get_width(pixbuf
)*
988 gdk_pixbuf_get_height(pixbuf
));
989 guchar
*src_pixels
= gdk_pixbuf_get_pixels (pixbuf
);
990 gint width
= gdk_pixbuf_get_width(pixbuf
);
991 gint height
= gdk_pixbuf_get_height(pixbuf
);
992 gint nchans
= gdk_pixbuf_get_n_channels (pixbuf
);
993 gint stride
= gdk_pixbuf_get_rowstride (pixbuf
);
997 format
= CAIRO_FORMAT_RGB24
;
999 format
= CAIRO_FORMAT_ARGB32
;
1000 surface
= cairo_image_surface_create_for_data (pixels
,
1001 format
, width
, height
, 4*width
);
1002 cairo_surface_set_user_data (surface
, &key
,
1003 pixels
, (cairo_destroy_func_t
)g_free
);
1005 for (j
= height
; j
; j
--) {
1006 guchar
*p
= src_pixels
;
1010 guchar
*end
= p
+ 3 * width
;
1013 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1026 guchar
*end
= p
+ 4 * width
;
1029 #define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END
1032 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1033 MULT(q
[0], p
[2], p
[3], t1
);
1034 MULT(q
[1], p
[1], p
[3], t2
);
1035 MULT(q
[2], p
[0], p
[3], t3
);
1039 MULT(q
[1], p
[0], p
[3], t1
);
1040 MULT(q
[2], p
[1], p
[3], t2
);
1041 MULT(q
[3], p
[2], p
[3], t3
);
1051 src_pixels
+= stride
;
1052 pixels
+= 4 * width
;
1058 static void printing_textview_cb_draw_page(GtkPrintOperation
*op
, GtkPrintContext
*context
,
1059 int page_nr
, gpointer user_data
)
1062 PrintData
*print_data
;
1065 PangoLayoutIter
*iter
;
1067 gboolean notlast
= TRUE
;
1069 print_data
= (PrintData
*) user_data
;
1074 pagebreak
= g_list_nth(print_data
->page_breaks
, page_nr
- 1);
1075 start
= GPOINTER_TO_INT(pagebreak
->data
);
1078 pagebreak
= g_list_nth(print_data
->page_breaks
, page_nr
);
1079 if (pagebreak
== NULL
)
1080 end
= pango_layout_get_line_count(print_data
->layout
);
1082 end
= GPOINTER_TO_INT(pagebreak
->data
);
1084 cr
= gtk_print_context_get_cairo_context(context
);
1085 cairo_scale(cr
, print_data
->zoom
, print_data
->zoom
);
1086 cairo_set_source_rgb(cr
, 0., 0., 0.);
1090 iter
= pango_layout_get_iter(print_data
->layout
);
1092 PangoRectangle logical_rect
;
1093 PangoLayoutLine
*line
;
1094 PangoAttrShape
*attr
= NULL
;
1098 line
= pango_layout_iter_get_line(iter
);
1100 pango_layout_iter_get_line_extents(iter
, NULL
, &logical_rect
);
1101 baseline
= pango_layout_iter_get_baseline(iter
);
1104 start_pos
= ((double)logical_rect
.y
) / PANGO_SCALE
;
1106 /* Draw header separator line */
1107 if (ii
== 0 && print_data
->ypos_line
>= 0) {
1108 cairo_surface_t
*surface
;
1109 surface
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32
,
1110 gtk_print_context_get_width(context
)/print_data
->zoom
,
1111 gtk_print_context_get_height(context
)/print_data
->zoom
);
1112 cairo_set_line_width(cr
, .5);
1113 cairo_set_source_surface(cr
, surface
,
1114 ((double)logical_rect
.x
) / PANGO_SCALE
,
1115 ((double)baseline
) / PANGO_SCALE
- start_pos
);
1116 cairo_move_to(cr
, ((double)logical_rect
.x
) / PANGO_SCALE
,
1117 (double)print_data
->ypos_line
/ PANGO_SCALE
);
1118 cairo_rel_line_to(cr
, gtk_print_context_get_width(context
)/print_data
->zoom
, 0);
1119 cairo_set_source_rgb(cr
, 0., 0., 0.);
1121 cairo_surface_destroy(surface
);
1125 ((double)logical_rect
.x
) / PANGO_SCALE
,
1126 ((double)baseline
) / PANGO_SCALE
- start_pos
);
1128 if ((attr
= g_hash_table_lookup(print_data
->images
,
1129 GINT_TO_POINTER(pango_layout_iter_get_index(iter
)))) != NULL
) {
1130 cairo_surface_t
*surface
;
1132 surface
= pixbuf_to_surface(GDK_PIXBUF(attr
->data
));
1133 cairo_set_source_surface (cr
, surface
,
1134 ((double)logical_rect
.x
) / PANGO_SCALE
,
1135 ((double)baseline
) / PANGO_SCALE
- start_pos
);
1137 cairo_surface_destroy (surface
);
1139 pango_cairo_show_layout_line(cr
, line
);
1143 } while(ii
< end
&& (notlast
= pango_layout_iter_next_line(iter
)));
1145 if (print_data
->avatar
&& page_nr
== 0) {
1146 cairo_surface_t
*surface
;
1147 GdkPixbuf
*pixbuf
= gtk_image_get_pixbuf(print_data
->avatar
);
1148 gdouble startx
, starty
;
1150 startx
= gtk_print_context_get_width(context
)/print_data
->zoom
;
1152 startx
-= ((double)gdk_pixbuf_get_width(pixbuf
));
1156 surface
= pixbuf_to_surface(pixbuf
);
1157 cairo_set_source_surface (cr
, surface
, startx
, starty
);
1159 cairo_surface_destroy (surface
);
1162 pango_layout_iter_free(iter
);
1163 debug_print("Sent page %d to printer\n", page_nr
+1);
1166 static void printing_layout_set_text_attributes(PrintData
*print_data
,
1167 GtkPrintContext
*context
,
1168 gboolean
*has_headers
)
1171 PangoAttrList
*attr_list
;
1172 PangoAttribute
*attr
;
1173 GSList
*open_attrs
, *attr_walk
;
1174 GtkTextView
*text_view
= GTK_TEXT_VIEW(print_data
->renderer_data
);
1175 GtkTextBuffer
*buffer
= gtk_text_view_get_buffer(text_view
);
1177 *has_headers
= FALSE
;
1179 attr_list
= pango_attr_list_new();
1180 if (print_data
->sel_start
< 0 || print_data
->sel_end
<= print_data
->sel_start
) {
1181 gtk_text_buffer_get_start_iter(buffer
, &iter
);
1183 gtk_text_buffer_get_iter_at_offset(buffer
, &iter
, print_data
->sel_start
);
1188 gboolean fg_set
, bg_set
, under_set
, strike_set
, weight_set
;
1189 GSList
*tags
, *tag_walk
;
1191 GdkColor
*color
= NULL
;
1192 PangoUnderline underline
;
1193 gboolean strikethrough
;
1197 if (prefs_common
.print_imgs
&& (image
= gtk_text_iter_get_pixbuf(&iter
)) != NULL
) {
1198 PangoRectangle rect
= {0, 0, 0, 0};
1199 gint startpos
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1200 gint h
= gdk_pixbuf_get_height(image
);
1201 gint w
= gdk_pixbuf_get_width(image
);
1202 gint a_h
= gtk_print_context_get_height(context
);
1203 gint a_w
= gtk_print_context_get_width(context
);
1205 GdkPixbuf
*scaled
= NULL
;
1206 image_viewer_get_resized_size(w
, h
, a_w
, a_h
, &r_w
, &r_h
);
1209 rect
.width
= r_w
* PANGO_SCALE
;
1210 rect
.height
= r_h
* PANGO_SCALE
;
1212 scaled
= gdk_pixbuf_scale_simple(image
, r_w
, r_h
, GDK_INTERP_BILINEAR
);
1213 attr
= pango_attr_shape_new_with_data (&rect
, &rect
,
1214 scaled
, NULL
, NULL
);
1215 attr
->start_index
= startpos
;
1216 attr
->end_index
= startpos
+1;
1217 pango_attr_list_insert(attr_list
, attr
);
1218 g_hash_table_insert(print_data
->images
, GINT_TO_POINTER(startpos
), attr
);
1219 print_data
->img_cnt
++;
1222 if (gtk_text_iter_ends_tag(&iter
, NULL
)) {
1223 PangoAttrColor
*attr_color
;
1224 PangoAttrInt
*attr_int
;
1226 tags
= gtk_text_iter_get_toggled_tags(&iter
, FALSE
);
1227 for (tag_walk
= tags
; tag_walk
!= NULL
; tag_walk
= tag_walk
->next
) {
1230 tag
= GTK_TEXT_TAG(tag_walk
->data
);
1231 g_object_get(G_OBJECT(tag
),
1232 "background-set", &bg_set
,
1233 "foreground-set", &fg_set
,
1234 "underline-set",&under_set
,
1235 "strikethrough-set", &strike_set
,
1236 "weight-set", &weight_set
,
1241 for (attr_walk
= open_attrs
; attr_walk
!= NULL
;
1242 attr_walk
= attr_walk
->next
) {
1243 attr
= (PangoAttribute
*)attr_walk
->data
;
1244 if (attr
->klass
->type
== PANGO_ATTR_FOREGROUND
) {
1245 attr_color
= (PangoAttrColor
*) attr
;
1246 g_object_get(G_OBJECT(tag
), "foreground_gdk",
1249 printing_is_pango_gdk_color_equal(&(attr_color
->color
),
1251 attr
->end_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1252 pango_attr_list_insert(attr_list
, attr
);
1254 open_attrs
= g_slist_delete_link(open_attrs
, attr_walk
);
1258 gdk_color_free(color
);
1262 debug_print("Error generating attribute list.\n");
1267 for (attr_walk
= open_attrs
; attr_walk
!= NULL
;
1268 attr_walk
= attr_walk
->next
) {
1269 attr
= (PangoAttribute
*)attr_walk
->data
;
1270 if (attr
->klass
->type
== PANGO_ATTR_BACKGROUND
) {
1271 attr_color
= (PangoAttrColor
*) attr
;
1272 g_object_get(G_OBJECT(tag
), "background-gdk",
1275 printing_is_pango_gdk_color_equal(&(attr_color
->color
),
1277 attr
->end_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1278 pango_attr_list_insert(attr_list
, attr
);
1280 open_attrs
= g_slist_delete_link(open_attrs
, attr_walk
);
1284 gdk_color_free(color
);
1288 debug_print("Error generating attribute list.\n");
1293 for (attr_walk
= open_attrs
; attr_walk
!= NULL
;
1294 attr_walk
= attr_walk
->next
) {
1295 attr
= (PangoAttribute
*)attr_walk
->data
;
1296 if (attr
->klass
->type
== PANGO_ATTR_UNDERLINE
) {
1297 attr_int
= (PangoAttrInt
*)attr
;
1298 g_object_get(G_OBJECT(tag
), "underline",
1300 if (attr_int
->value
== underline
) {
1301 attr
->end_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1302 pango_attr_list_insert(attr_list
, attr
);
1304 open_attrs
= g_slist_delete_link(open_attrs
, attr_walk
);
1310 debug_print("Error generating attribute list.\n");
1315 for (attr_walk
= open_attrs
; attr_walk
!= NULL
;
1316 attr_walk
= attr_walk
->next
) {
1317 attr
= (PangoAttribute
*)attr_walk
->data
;
1318 if (attr
->klass
->type
== PANGO_ATTR_STRIKETHROUGH
) {
1319 attr_int
= (PangoAttrInt
*)attr
;
1320 g_object_get(G_OBJECT(tag
), "strikethrough",
1321 &strikethrough
, NULL
);
1322 if (attr_int
->value
== strikethrough
) {
1323 attr
->end_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1324 pango_attr_list_insert(attr_list
, attr
);
1326 open_attrs
= g_slist_delete_link(open_attrs
, attr_walk
);
1332 debug_print("Error generating attribute list.\n");
1337 for (attr_walk
= open_attrs
; attr_walk
!= NULL
;
1338 attr_walk
= attr_walk
->next
) {
1339 attr
= (PangoAttribute
*)attr_walk
->data
;
1340 if (attr
->klass
->type
== PANGO_ATTR_WEIGHT
) {
1341 attr_int
= (PangoAttrInt
*)attr
;
1342 g_object_get(G_OBJECT(tag
), "weight", &weight
, NULL
);
1343 if (attr_int
->value
== weight
) {
1344 attr
->end_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1345 pango_attr_list_insert(attr_list
, attr
);
1347 open_attrs
= g_slist_delete_link(open_attrs
, attr_walk
);
1353 debug_print("Error generating attribute list.\n");
1359 if (gtk_text_iter_begins_tag(&iter
, NULL
)) {
1360 tags
= gtk_text_iter_get_toggled_tags(&iter
, TRUE
);
1361 /* Sometimes, an iter has several weights. Use only the first in this case */
1362 gboolean weight_set_for_this_iter
;
1363 weight_set_for_this_iter
= FALSE
;
1364 for (tag_walk
= tags
; tag_walk
!= NULL
; tag_walk
= tag_walk
->next
) {
1365 tag
= GTK_TEXT_TAG(tag_walk
->data
);
1366 g_object_get(G_OBJECT(tag
),
1367 "background-set", &bg_set
,
1368 "foreground-set", &fg_set
,
1369 "underline-set", &under_set
,
1370 "strikethrough-set", &strike_set
,
1371 "weight-set", &weight_set
,
1374 g_object_get(G_OBJECT(tag
), "foreground-gdk", &color
, NULL
);
1375 attr
= pango_attr_foreground_new(color
->red
,color
->green
,color
->blue
);
1376 attr
->start_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1377 open_attrs
= g_slist_prepend(open_attrs
, attr
);
1380 g_object_get(G_OBJECT(tag
), "background-gdk", &color
, NULL
);
1381 attr
= pango_attr_background_new(color
->red
,color
->green
,color
->blue
);
1382 attr
->start_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1383 open_attrs
= g_slist_prepend(open_attrs
, attr
);
1386 g_object_get(G_OBJECT(tag
), "underline", &underline
, NULL
);
1387 attr
= pango_attr_underline_new(underline
);
1388 attr
->start_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1389 open_attrs
= g_slist_prepend(open_attrs
, attr
);
1392 g_object_get(G_OBJECT(tag
), "strikethrough", &strikethrough
, NULL
);
1393 attr
= pango_attr_strikethrough_new(strikethrough
);
1394 attr
->start_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1395 open_attrs
= g_slist_prepend(open_attrs
, attr
);
1397 if (weight_set
&& !weight_set_for_this_iter
) {
1398 weight_set_for_this_iter
= TRUE
;
1399 g_object_get(G_OBJECT(tag
), "weight", &weight
, NULL
);
1400 attr
= pango_attr_weight_new(weight
);
1401 attr
->start_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1402 open_attrs
= g_slist_prepend(open_attrs
, attr
);
1403 /* Hack to see if the first char is bold -- indicates header */
1404 if (attr
->start_index
== 0 && weight
== PANGO_WEIGHT_BOLD
) {
1405 *has_headers
= TRUE
;
1412 } while(!gtk_text_iter_is_end(&iter
) && gtk_text_iter_forward_to_tag_toggle(&iter
, NULL
));
1414 /* close all open attributes */
1415 for (attr_walk
= open_attrs
; attr_walk
!= NULL
; attr_walk
= attr_walk
->next
) {
1416 attr
= (PangoAttribute
*) attr_walk
->data
;
1417 attr
->end_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1418 pango_attr_list_insert(attr_list
, attr
);
1420 g_slist_free(open_attrs
);
1422 pango_layout_set_attributes(print_data
->layout
, attr_list
);
1423 pango_attr_list_unref(attr_list
);
1426 static gboolean
printing_is_pango_gdk_color_equal(PangoColor
*p
, GdkColor
*g
)
1428 return ((p
->red
== g
->red
) && (p
->green
== g
->green
) && (p
->blue
== g
->blue
));
1431 /* Pango has it's attribute in bytes, but GtkTextIter gets only an offset
1432 * in characters, so here we're returning an offset in bytes.
1434 static gint
printing_text_iter_get_offset_bytes(PrintData
*print_data
, const GtkTextIter
*iter
)
1440 if (print_data
->sel_start
< 0 || print_data
->sel_end
<= print_data
->sel_start
) {
1441 gtk_text_buffer_get_start_iter(gtk_text_iter_get_buffer(iter
), &start
);
1443 gtk_text_buffer_get_iter_at_offset(gtk_text_iter_get_buffer(iter
), &start
, print_data
->sel_start
);
1445 text
= gtk_text_iter_get_text(&start
, iter
);
1446 off_bytes
= strlen(text
);
1451 static void printing_preview_update_zoom_sensitivity(PreviewData
*preview_data
)
1453 if((preview_data
->print_data
->zoom
* PREVIEW_ZOOM_FAC
) > PREVIEW_ZOOM_MAX
)
1454 gtk_widget_set_sensitive(preview_data
->zoom_in
, FALSE
);
1456 gtk_widget_set_sensitive(preview_data
->zoom_in
, TRUE
);
1458 if ((preview_data
->print_data
->zoom
/ PREVIEW_ZOOM_FAC
) < PREVIEW_ZOOM_MIN
)
1459 gtk_widget_set_sensitive(preview_data
->zoom_out
, FALSE
);
1461 gtk_widget_set_sensitive(preview_data
->zoom_out
, TRUE
);