1 /* Claws Mail -- a GTK based, lightweight, and fast e-mail client
2 * Copyright (C) 2007-2019 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 static gboolean
cb_drawing_area(GtkWidget
*widget
, cairo_t
*cr
, gpointer data
);
97 static void cb_preview_got_page_size(GtkPrintOperationPreview
*,
99 GtkPageSetup
*, gpointer
);
100 static void cb_preview_go_first(GtkButton
*, gpointer
);
101 static void cb_preview_go_previous(GtkButton
*, gpointer
);
102 static void cb_preview_go_next(GtkButton
*, gpointer
);
103 static void cb_preview_go_last(GtkButton
*, gpointer
);
104 static void cb_preview_btn_close(GtkButton
*, gpointer
);
105 static void cb_preview_zoom_100(GtkButton
*, gpointer
);
106 static void cb_preview_zoom_fit(GtkButton
*, gpointer
);
107 static void cb_preview_zoom_in(GtkButton
*, gpointer
);
108 static void cb_preview_zoom_out(GtkButton
*, gpointer
);
109 static void cb_preview_request_page_setup(GtkPrintOperation
*,
111 gint
,GtkPageSetup
*,gpointer
);
113 static void printing_preview_update_zoom_sensitivity(PreviewData
*);
116 static GtkPrintSettings
*settings
= NULL
;
117 static GtkPageSetup
*page_setup
= NULL
;
119 /* other static functions */
120 static void printing_layout_set_text_attributes(PrintData
*, GtkPrintContext
*, gboolean
*);
121 static gboolean
printing_is_pango_gdk_rgba_equal(PangoColor
*, GdkRGBA
*);
122 PangoColor
* printing_pango_color_from_gdk_rgba(GdkRGBA
*);
123 static gint
printing_text_iter_get_offset_bytes(PrintData
*, const GtkTextIter
*);
125 #define PAGE_MARGIN_STORAGE_UNIT GTK_UNIT_MM
126 #define PREVIEW_SCALE 72
127 #define PREVIEW_SHADOW_OFFSET 3
128 #define PREVIEW_ZOOM_FAC 1.41
129 #define PREVIEW_ZOOM_MAX 10.
130 #define PREVIEW_ZOOM_MIN 0.2
132 static void free_pixbuf(gpointer key
, gpointer value
, gpointer data
)
134 PangoAttrShape
*attr
= (PangoAttrShape
*) value
;
135 g_object_unref(G_OBJECT(attr
->data
));
138 gpointer
printing_get_renderer_data(PrintData
*print_data
)
142 return print_data
->renderer_data
;
145 gdouble
printing_get_zoom(PrintData
*print_data
)
149 return print_data
->zoom
;
152 void printing_set_n_pages(PrintData
*print_data
, gint n_pages
)
156 print_data
->npages
= n_pages
;
159 GtkPrintSettings
*printing_get_settings(void)
161 if (settings
== NULL
) {
162 settings
= gtk_print_settings_new();
163 gtk_print_settings_set_use_color(settings
, prefs_common
.print_use_color
);
164 gtk_print_settings_set_collate(settings
, prefs_common
.print_use_collate
);
165 gtk_print_settings_set_reverse(settings
, prefs_common
.print_use_reverse
);
166 gtk_print_settings_set_duplex(settings
, prefs_common
.print_use_duplex
);
171 void printing_store_settings(GtkPrintSettings
*new_settings
)
173 if (settings
!= NULL
)
174 g_object_unref(settings
);
176 settings
= g_object_ref(new_settings
);
177 prefs_common
.print_use_color
= gtk_print_settings_get_use_color(settings
);
178 prefs_common
.print_use_collate
= gtk_print_settings_get_collate(settings
);
179 prefs_common
.print_use_reverse
= gtk_print_settings_get_reverse(settings
);
180 prefs_common
.print_use_duplex
= gtk_print_settings_get_duplex(settings
);
183 GtkPageSetup
*printing_get_page_setup(void)
185 if (page_setup
== NULL
) {
186 gboolean read_from_file
;
187 char *page_setup_filename
;
189 gboolean key_file_read
;
191 page_setup
= gtk_page_setup_new();
193 read_from_file
= FALSE
;
195 /* try reading the page setup from file */
196 page_setup_filename
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
197 PRINTING_PAGE_SETUP_STORAGE_FILE
, NULL
);
198 keyfile
= g_key_file_new();
199 key_file_read
= g_key_file_load_from_file(keyfile
, page_setup_filename
,
201 g_free(page_setup_filename
);
204 read_from_file
= gtk_page_setup_load_key_file(page_setup
, keyfile
,
206 g_key_file_free(keyfile
);
208 if (read_from_file
) {
209 debug_print("Printing: Read page setup from key file\n");
211 debug_print("Printing: Could not read page setup from key file\n");
214 /* if reading from file did not work, or has not been tried (GTK+ < 2.14), use prefs */
215 if (!read_from_file
) {
217 if (prefs_common
.print_paper_type
&&
218 *prefs_common
.print_paper_type
) {
219 GtkPaperSize
*paper
= gtk_paper_size_new(prefs_common
.print_paper_type
);
220 gtk_page_setup_set_paper_size(page_setup
, paper
);
221 gtk_paper_size_free(paper
);
224 gtk_page_setup_set_orientation(page_setup
,
225 prefs_common
.print_paper_orientation
);
227 if (prefs_common
.print_margin_top
!= -1)
228 gtk_page_setup_set_top_margin(page_setup
,
229 0.01*prefs_common
.print_margin_top
,
230 PAGE_MARGIN_STORAGE_UNIT
);
231 if (prefs_common
.print_margin_bottom
!= -1)
232 gtk_page_setup_set_bottom_margin(page_setup
,
233 0.01*prefs_common
.print_margin_bottom
,
234 PAGE_MARGIN_STORAGE_UNIT
);
235 if (prefs_common
.print_margin_left
!= -1)
236 gtk_page_setup_set_left_margin(page_setup
,
237 0.01*prefs_common
.print_margin_left
,
238 PAGE_MARGIN_STORAGE_UNIT
);
239 if (prefs_common
.print_margin_right
!= -1)
240 gtk_page_setup_set_right_margin(page_setup
,
241 0.01*prefs_common
.print_margin_right
,
242 PAGE_MARGIN_STORAGE_UNIT
);
248 void printing_print_full(GtkWindow
*parent
, PrintRenderer
*renderer
, gpointer renderer_data
,
249 gint sel_start
, gint sel_end
, GtkImage
*avatar
)
251 GtkPrintOperation
*op
;
252 GtkPrintOperationResult res
;
253 PrintData
*print_data
;
255 op
= gtk_print_operation_new();
257 print_data
= g_new0(PrintData
,1);
259 print_data
->renderer
= renderer
;
260 print_data
->renderer_data
= renderer_data
;
261 print_data
->sel_start
= sel_start
;
262 print_data
->sel_end
= sel_end
;
263 print_data
->avatar
= (avatar
!= NULL
? GTK_IMAGE(g_object_ref(avatar
)): NULL
);
265 print_data
->zoom
= 1.;
267 print_data
->images
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
269 print_data
->pango_context
= renderer
->get_pango_context(renderer_data
);
271 print_data
->to_print
= renderer
->get_data_to_print(renderer_data
, sel_start
, sel_end
);
273 printing_get_settings();
274 printing_get_page_setup();
276 /* Config for printing */
277 gtk_print_operation_set_print_settings(op
, settings
);
278 gtk_print_operation_set_default_page_setup(op
, page_setup
);
279 /* enable Page Size and Orientation in the print dialog */
280 gtk_print_operation_set_embed_page_setup(op
, TRUE
);
282 g_signal_connect(op
, "begin_print", G_CALLBACK(renderer
->cb_begin_print
), print_data
);
283 g_signal_connect(op
, "draw_page", G_CALLBACK(renderer
->cb_draw_page
), print_data
);
284 g_signal_connect(op
, "preview", G_CALLBACK(cb_preview
), print_data
);
286 /* Start printing process */
287 res
= gtk_print_operation_run(op
, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG
,
290 if (res
== GTK_PRINT_OPERATION_RESULT_ERROR
) {
291 GError
*error
= NULL
;
292 gtk_print_operation_get_error(op
, &error
);
293 debug_print("Error printing message: %s\n",
294 error
? error
->message
: "no details");
295 } else if (res
== GTK_PRINT_OPERATION_RESULT_APPLY
) {
296 /* store settings for next printing session */
297 printing_store_settings(gtk_print_operation_get_print_settings(op
));
300 g_hash_table_foreach(print_data
->images
, free_pixbuf
, NULL
);
301 g_hash_table_destroy(print_data
->images
);
302 if (print_data
->to_print
)
303 g_free(print_data
->to_print
);
304 g_list_free(print_data
->page_breaks
);
305 if (print_data
->layout
)
306 g_object_unref(print_data
->layout
);
307 if (print_data
->avatar
)
308 g_object_unref(print_data
->avatar
);
313 debug_print("printing_print finished\n");
316 static PangoContext
*printing_textview_get_pango_context(gpointer data
)
318 return gtk_widget_get_pango_context(GTK_WIDGET(data
));
321 static gpointer
printing_textview_get_data_to_print(gpointer data
, gint sel_start
, gint sel_end
)
323 GtkTextView
*text_view
= GTK_TEXT_VIEW(data
);
324 GtkTextBuffer
*buffer
= gtk_text_view_get_buffer(text_view
);
325 GtkTextIter start
, end
;
327 if (sel_start
< 0 || sel_end
<= sel_start
) {
328 gtk_text_buffer_get_start_iter(buffer
, &start
);
329 gtk_text_buffer_get_end_iter(buffer
, &end
);
331 gtk_text_buffer_get_iter_at_offset(buffer
, &start
, sel_start
);
332 gtk_text_buffer_get_iter_at_offset(buffer
, &end
, sel_end
);
335 return gtk_text_buffer_get_text(buffer
, &start
, &end
, FALSE
);
338 void printing_print(GtkTextView
*text_view
, GtkWindow
*parent
, gint sel_start
, gint sel_end
, GtkImage
*avatar
)
340 PrintRenderer
*textview_renderer
= g_new0(PrintRenderer
, 1);
342 textview_renderer
->get_pango_context
= printing_textview_get_pango_context
;
343 textview_renderer
->get_data_to_print
= printing_textview_get_data_to_print
;
344 textview_renderer
->cb_begin_print
= printing_textview_cb_begin_print
;
345 textview_renderer
->cb_draw_page
= printing_textview_cb_draw_page
;
347 printing_print_full(parent
, textview_renderer
, text_view
, sel_start
, sel_end
, avatar
);
349 g_free(textview_renderer
);
352 void printing_page_setup(GtkWindow
*parent
)
354 GtkPageSetup
*new_page_setup
;
359 printing_get_settings();
360 printing_get_page_setup();
362 new_page_setup
= gtk_print_run_page_setup_dialog(parent
,page_setup
,settings
);
365 g_object_unref(page_setup
);
367 page_setup
= new_page_setup
;
369 g_free(prefs_common
.print_paper_type
);
370 prefs_common
.print_paper_type
= g_strdup(gtk_paper_size_get_name(
371 gtk_page_setup_get_paper_size(page_setup
)));
372 prefs_common
.print_paper_orientation
= gtk_page_setup_get_orientation(page_setup
);
373 /* store 100th millimeters */
374 prefs_common
.print_margin_top
= (int) (100*gtk_page_setup_get_top_margin(page_setup
,
375 PAGE_MARGIN_STORAGE_UNIT
));
376 prefs_common
.print_margin_bottom
= (int) (100*gtk_page_setup_get_bottom_margin(page_setup
,
377 PAGE_MARGIN_STORAGE_UNIT
));
378 prefs_common
.print_margin_left
= (int) (100*gtk_page_setup_get_left_margin(page_setup
,
379 PAGE_MARGIN_STORAGE_UNIT
));
380 prefs_common
.print_margin_right
= (int) (100*gtk_page_setup_get_right_margin(page_setup
,
381 PAGE_MARGIN_STORAGE_UNIT
));
384 keyfile
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
385 PRINTING_PAGE_SETUP_STORAGE_FILE
, NULL
);
386 if (!gtk_page_setup_to_file(page_setup
, keyfile
, NULL
)) {
387 debug_print("Printing: Could not store page setup in file `%s'\n", keyfile
);
392 static gboolean
cb_preview(GtkPrintOperation
*operation
,
393 GtkPrintOperationPreview
*preview
,
394 GtkPrintContext
*context
,
398 PrintData
*print_data
;
399 cairo_region_t
*creg
;
401 GdkDrawingContext
*gdc
;
402 PreviewData
*preview_data
;
408 GtkToolItem
*separator
;
409 static GdkGeometry geometry
;
410 GtkWidget
*dialog
= NULL
;
411 GtkWidget
*statusbar
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 2);
413 debug_print("Creating internal print preview\n");
415 print_data
= (PrintData
*) data
;
417 preview_data
= g_new0(PreviewData
,1);
418 preview_data
->print_data
= print_data
;
419 preview_data
->op
= g_object_ref(operation
);
420 preview_data
->preview
= preview
;
423 dialog
= gtkut_window_new(GTK_WINDOW_TOPLEVEL
, "print_preview");
424 preview_data
->dialog
= dialog
;
425 if (!geometry
.min_height
) {
426 geometry
.min_width
= 600;
427 geometry
.min_height
= 400;
429 gtk_window_set_type_hint(GTK_WINDOW(dialog
), GDK_WINDOW_TYPE_HINT_DIALOG
);
430 gtk_window_set_geometry_hints(GTK_WINDOW(dialog
), NULL
, &geometry
,
432 gtk_window_set_default_size(GTK_WINDOW(dialog
),
433 prefs_common
.print_previewwin_width
,
434 prefs_common
.print_previewwin_height
);
435 gtk_window_set_title(GTK_WINDOW(dialog
), _("Print preview"));
438 vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 0);
439 gtk_container_add(GTK_CONTAINER(dialog
), vbox
);
442 toolbar
= gtk_toolbar_new();
443 gtk_orientable_set_orientation(GTK_ORIENTABLE(toolbar
), GTK_ORIENTATION_HORIZONTAL
);
445 switch (prefs_common
.toolbar_style
) {
447 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar
), GTK_TOOLBAR_ICONS
);
450 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar
), GTK_TOOLBAR_TEXT
);
452 case TOOLBAR_BOTH_HORIZ
:
453 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar
), GTK_TOOLBAR_BOTH_HORIZ
);
457 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar
), GTK_TOOLBAR_BOTH
);
459 gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolbar
), TRUE
);
461 gtk_box_pack_start(GTK_BOX(vbox
), toolbar
, FALSE
, FALSE
, 0);
463 #define CLAWS_SET_TOOL_ITEM_TIP(widget,tip) { \
464 gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), tip); \
467 #define TOOLBAR_ITEM(item,text,tooltip,cb,cbdata) { \
468 item = GTK_WIDGET(gtk_tool_button_new (NULL, NULL)); \
469 gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), 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
, "go-first",
479 _("First page"), cb_preview_go_first
, preview_data
);
480 TOOLBAR_ITEM(preview_data
->previous
, "go-previous",
481 _("Previous page"), cb_preview_go_previous
, preview_data
);
483 page
= gtk_label_new("");
484 preview_data
->page_nr_label
= page
;
486 TOOLBAR_ITEM(preview_data
->next
, "go-next",
487 _("Next page"), cb_preview_go_next
, preview_data
);
488 TOOLBAR_ITEM(preview_data
->last
, "go-last",
489 _("Last page"), cb_preview_go_last
, preview_data
);
491 separator
= gtk_separator_tool_item_new();
492 gtk_toolbar_insert(GTK_TOOLBAR(toolbar
), GTK_TOOL_ITEM(separator
), -1);
494 TOOLBAR_ITEM(preview_data
->zoom_100
, "zoom-original",
495 _("Zoom 100%"), cb_preview_zoom_100
, preview_data
);
496 TOOLBAR_ITEM(preview_data
->zoom_fit
, "zoom-fit-best",
497 _("Zoom fit"), cb_preview_zoom_fit
, preview_data
);
498 TOOLBAR_ITEM(preview_data
->zoom_in
, "zoom-in",
499 _("Zoom in"), cb_preview_zoom_in
, preview_data
);
500 TOOLBAR_ITEM(preview_data
->zoom_out
, "zoom-out",
501 _("Zoom out"), cb_preview_zoom_out
, preview_data
);
503 separator
= gtk_separator_tool_item_new();
504 gtk_toolbar_insert(GTK_TOOLBAR(toolbar
), GTK_TOOL_ITEM(separator
), -1);
506 /* tooltip has to be NULL else it triggers an expose_event */
507 TOOLBAR_ITEM(preview_data
->close
, "window-close", _("Close"),
508 cb_preview_btn_close
, preview_data
);
510 gtk_widget_show(statusbar
);
511 gtk_box_pack_start(GTK_BOX(vbox
), statusbar
, FALSE
, FALSE
, 0);
512 gtk_box_pack_start(GTK_BOX(statusbar
), page
, FALSE
, FALSE
, 0);
514 sw
= gtk_scrolled_window_new(NULL
, NULL
);
515 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
),
516 GTK_POLICY_AUTOMATIC
,
517 GTK_POLICY_AUTOMATIC
);
518 gtk_box_pack_start(GTK_BOX(vbox
), sw
, TRUE
, TRUE
, 0);
519 da
= gtk_drawing_area_new();
520 gtk_container_add(GTK_CONTAINER(sw
), da
);
521 gtk_widget_realize(da
);
522 preview_data
->scrolled_window
= sw
;
523 preview_data
->area
= da
;
526 creg
= cairo_region_create();
527 gdc
= gdk_window_begin_draw_frame(gtk_widget_get_window(da
), creg
);
528 cr
= gdk_drawing_context_get_cairo_context(gdc
);
529 gtk_print_context_set_cairo_context(context
, cr
, PREVIEW_SCALE
, PREVIEW_SCALE
);
530 gdk_window_end_draw_frame(gtk_widget_get_window(da
), gdc
);
531 cairo_region_destroy(creg
);
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 gtk_window_get_size(GTK_WINDOW(widget
),
587 &prefs_common
.print_previewwin_width
, &prefs_common
.print_previewwin_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 g_signal_connect(G_OBJECT (preview_data
->area
), "draw",
613 G_CALLBACK(cb_drawing_area
), preview_data
);
615 gtk_widget_queue_draw(preview_data
->area
);
618 static void cb_preview_got_page_size(GtkPrintOperationPreview
*preview
,
619 GtkPrintContext
*context
,
620 GtkPageSetup
*page_setup
,
623 PreviewData
*preview_data
;
624 GtkPaperSize
*paper_size
;
628 preview_data
= (PreviewData
*) data
;
629 debug_print("got_page_size\n");
630 paper_size
= gtk_page_setup_get_paper_size(page_setup
);
631 paper_width
= (gint
)(gtk_paper_size_get_width(paper_size
, GTK_UNIT_INCH
)
633 paper_height
= (gint
)(gtk_paper_size_get_height(paper_size
, GTK_UNIT_INCH
)
636 preview_data
->page_width
= paper_width
;
637 preview_data
->page_height
= paper_height
;
639 debug_print("w/h %d/%d\n", paper_width
, paper_height
);
640 gtk_widget_set_size_request(GTK_WIDGET(preview_data
->area
),
641 paper_width
, paper_height
);
644 static gboolean
cb_drawing_area(GtkWidget
*widget
, cairo_t
*cr
, gpointer data
)
646 PreviewData
*preview_data
= data
;
647 GdkDrawingContext
*gdc
;
648 cairo_region_t
*creg
;
651 width
= gtk_widget_get_allocated_width (widget
);
652 height
= gtk_widget_get_allocated_height (widget
);
654 debug_print("preview_expose (current %p)\n", preview_data
->current_page
);
656 creg
= cairo_region_create();
657 gdc
= gdk_window_begin_draw_frame(gtk_widget_get_window(preview_data
->area
), creg
);
658 cr
= gdk_drawing_context_get_cairo_context(gdc
);
661 cairo_set_source_rgb(cr
, 0.5, 0.5, 0.5);
662 cairo_rectangle(cr
, 0, 0, width
, height
);
666 cairo_set_source_rgb(cr
, 0., 0., 0.);
667 cairo_rectangle(cr
, PREVIEW_SHADOW_OFFSET
, PREVIEW_SHADOW_OFFSET
,
668 preview_data
->page_width
+PREVIEW_SHADOW_OFFSET
,
669 preview_data
->page_height
+PREVIEW_SHADOW_OFFSET
);
673 cairo_set_source_rgb(cr
, 1., 1., 1.);
674 cairo_rectangle(cr
, 0, 0,
675 preview_data
->page_width
,
676 preview_data
->page_height
);
679 gtk_print_context_set_cairo_context(preview_data
->context
, cr
, PREVIEW_SCALE
, PREVIEW_SCALE
);
680 gdk_window_end_draw_frame(gtk_widget_get_window(preview_data
->area
), gdc
);
681 cairo_region_destroy(creg
);
683 if (preview_data
->current_page
) {
684 preview_data
->rendering
= TRUE
;
685 gtk_widget_set_sensitive(preview_data
->close
, FALSE
);
686 int cur
= GPOINTER_TO_INT(preview_data
->current_page
->data
);
688 str
= g_strdup_printf(_("Page %d"), cur
+1);
689 gtk_label_set_text(GTK_LABEL(preview_data
->page_nr_label
), str
);
691 gtk_print_operation_preview_render_page(preview_data
->preview
,
693 (preview_data
->current_page
->data
));
695 gtk_widget_set_sensitive(preview_data
->first
,
696 preview_data
->current_page
->prev
!= NULL
);
697 gtk_widget_set_sensitive(preview_data
->previous
,
698 preview_data
->current_page
->prev
!= NULL
);
699 gtk_widget_set_sensitive(preview_data
->next
,
700 preview_data
->current_page
->next
!= NULL
);
701 gtk_widget_set_sensitive(preview_data
->last
,
702 preview_data
->current_page
->next
!= NULL
);
703 gtk_widget_set_sensitive(preview_data
->close
, TRUE
);
704 preview_data
->rendering
= FALSE
;
709 static void cb_preview_go_first(GtkButton
*button
, gpointer data
)
711 PreviewData
*preview_data
= (PreviewData
*) data
;
712 preview_data
->current_page
= preview_data
->pages_to_print
;
713 gtk_widget_queue_draw(preview_data
->area
);
716 static void cb_preview_go_previous(GtkButton
*button
, gpointer data
)
719 PreviewData
*preview_data
= (PreviewData
*) data
;
720 next
= g_list_previous(preview_data
->current_page
);
722 preview_data
->current_page
= next
;
723 gtk_widget_queue_draw(preview_data
->area
);
726 static void cb_preview_go_next(GtkButton
*button
, gpointer data
)
729 PreviewData
*preview_data
= (PreviewData
*) data
;
730 next
= g_list_next(preview_data
->current_page
);
732 preview_data
->current_page
= next
;
733 gtk_widget_queue_draw(preview_data
->area
);
736 static void cb_preview_go_last(GtkButton
*button
, gpointer data
)
738 PreviewData
*preview_data
= (PreviewData
*) data
;
739 preview_data
->current_page
= g_list_last(preview_data
->current_page
);
740 gtk_widget_queue_draw(preview_data
->area
);
743 static void cb_preview_btn_close(GtkButton
*button
, gpointer data
)
745 PreviewData
*preview_data
= (PreviewData
*)data
;
746 if (preview_data
->rendering
)
748 gtk_widget_destroy(preview_data
->dialog
);
751 static void cb_preview_zoom_100(GtkButton
*button
, gpointer data
)
753 PreviewData
*preview_data
= (PreviewData
*) data
;
754 if (preview_data
->print_data
->zoom
!= 1.) {
755 preview_data
->print_data
->zoom
= 1.;
756 gtk_widget_queue_draw(preview_data
->area
);
757 printing_preview_update_zoom_sensitivity(preview_data
);
761 static void cb_preview_zoom_fit(GtkButton
*button
, gpointer data
)
763 PreviewData
*preview_data
= (PreviewData
*) data
;
764 GtkAllocation allocation
;
768 gtk_widget_get_allocation(preview_data
->scrolled_window
, &allocation
);
769 zoom_w
= ((gdouble
)allocation
.width
) /
770 ((gdouble
)preview_data
->page_width
/preview_data
->print_data
->zoom
+
771 PREVIEW_SHADOW_OFFSET
);
772 zoom_h
= ((gdouble
)allocation
.height
) /
773 ((gdouble
)preview_data
->page_height
/preview_data
->print_data
->zoom
+
774 PREVIEW_SHADOW_OFFSET
);
776 preview_data
->print_data
->zoom
= MIN(zoom_w
,zoom_h
) - 0.01;
778 if (preview_data
->print_data
->zoom
> PREVIEW_ZOOM_MAX
)
779 preview_data
->print_data
->zoom
= PREVIEW_ZOOM_MAX
;
780 else if (preview_data
->print_data
->zoom
< PREVIEW_ZOOM_MIN
)
781 preview_data
->print_data
->zoom
= PREVIEW_ZOOM_MIN
;
783 printing_preview_update_zoom_sensitivity(preview_data
);
784 gtk_widget_queue_draw(preview_data
->area
);
787 static void cb_preview_zoom_in(GtkButton
*button
, gpointer data
)
789 PreviewData
*preview_data
= (PreviewData
*) data
;
791 new_zoom
= preview_data
->print_data
->zoom
* PREVIEW_ZOOM_FAC
;
792 if (new_zoom
<= PREVIEW_ZOOM_MAX
) {
793 preview_data
->print_data
->zoom
= new_zoom
;
794 printing_preview_update_zoom_sensitivity(preview_data
);
795 gtk_widget_queue_draw(preview_data
->area
);
799 static void cb_preview_zoom_out(GtkButton
*button
, gpointer data
)
801 PreviewData
*preview_data
= (PreviewData
*) data
;
803 new_zoom
= preview_data
->print_data
->zoom
/ PREVIEW_ZOOM_FAC
;
804 if (new_zoom
>= PREVIEW_ZOOM_MIN
) {
805 preview_data
->print_data
->zoom
= new_zoom
;
806 printing_preview_update_zoom_sensitivity(preview_data
);
807 gtk_widget_queue_draw(preview_data
->area
);
811 static void cb_preview_request_page_setup(GtkPrintOperation
*op
,
812 GtkPrintContext
*context
,
814 GtkPageSetup
*setup
,gpointer data
)
816 GtkPaperSize
*paper_size
;
817 GtkPaperSize
*old_size
;
821 gdouble bottom_margin
;
823 gdouble right_margin
;
825 PreviewData
*preview_data
= (PreviewData
*) data
;
827 old_size
= gtk_page_setup_get_paper_size(setup
);
828 width
= gtk_paper_size_get_width(old_size
,GTK_UNIT_INCH
);
829 height
= gtk_paper_size_get_height(old_size
,GTK_UNIT_INCH
);
831 top_margin
= gtk_page_setup_get_top_margin(setup
,GTK_UNIT_INCH
);
832 bottom_margin
= gtk_page_setup_get_bottom_margin(setup
,GTK_UNIT_INCH
);
833 left_margin
= gtk_page_setup_get_left_margin(setup
,GTK_UNIT_INCH
);
834 right_margin
= gtk_page_setup_get_right_margin(setup
,GTK_UNIT_INCH
);
836 paper_size
= gtk_paper_size_new_custom("preview paper", "preview_paper",
837 width
*preview_data
->print_data
->zoom
,
838 height
*preview_data
->print_data
->zoom
,
840 gtk_page_setup_set_paper_size(setup
, paper_size
);
841 gtk_paper_size_free(paper_size
);
843 gtk_page_setup_set_top_margin(setup
,top_margin
*preview_data
->print_data
->zoom
,
845 gtk_page_setup_set_bottom_margin(setup
,bottom_margin
*preview_data
->print_data
->zoom
,
847 gtk_page_setup_set_left_margin(setup
,left_margin
*preview_data
->print_data
->zoom
,
849 gtk_page_setup_set_right_margin(setup
,right_margin
*preview_data
->print_data
->zoom
,
853 static void printing_textview_cb_begin_print(GtkPrintOperation
*op
, GtkPrintContext
*context
,
856 double width
, height
;
860 PrintData
*print_data
;
861 PangoFontDescription
*desc
;
863 PangoLayoutIter
*iter
;
865 gint num_header_lines
;
867 gboolean header_done
;
868 gboolean has_headers
= FALSE
;
870 double line_height
=0.;
872 print_data
= (PrintData
*) user_data
;
874 debug_print("Preparing print job...\n");
876 width
= gtk_print_context_get_width(context
);
877 height
= gtk_print_context_get_height(context
);
879 if (print_data
->layout
== NULL
)
880 print_data
->layout
= gtk_print_context_create_pango_layout(context
);
882 if (prefs_common
.use_different_print_font
)
883 desc
= pango_font_description_from_string(prefs_common
.printfont
);
885 desc
= pango_font_description_copy(
886 pango_context_get_font_description(print_data
->pango_context
));
888 pango_layout_set_font_description(print_data
->layout
, desc
);
889 pango_font_description_free(desc
);
891 pango_layout_set_width(print_data
->layout
, width
* PANGO_SCALE
);
892 pango_layout_set_text(print_data
->layout
, (char *)print_data
->to_print
, -1);
894 printing_layout_set_text_attributes(print_data
, context
, &has_headers
);
896 num_lines
= pango_layout_get_line_count(print_data
->layout
);
902 iter
= pango_layout_get_iter(print_data
->layout
);
904 /* find the last character of the header */
907 text
= pango_layout_get_text(print_data
->layout
);
910 if (text
&& *text
&& *text
!= '\n') {
912 if (text
[0] == '\n' && (text
[1] != '\0') && (text
[1] == '\n'))
917 } while(*text
&& !header_done
);
919 /* find line number for header end */
920 pango_layout_index_to_line_x(print_data
->layout
, header_end_pos
, 1,
921 &num_header_lines
, &dummy
);
922 /* line count is zero-based */
925 print_data
->ypos_line
= -1.0;
929 PangoRectangle logical_rect
;
930 PangoAttrShape
*attr
= NULL
;
933 pango_layout_iter_get_line_extents(iter
, NULL
, &logical_rect
);
935 if ((attr
= g_hash_table_lookup(print_data
->images
,
936 GINT_TO_POINTER(pango_layout_iter_get_index(iter
)))) != NULL
) {
937 line_height
= (double)gdk_pixbuf_get_height(GDK_PIXBUF(attr
->data
));
939 line_height
= ((double)logical_rect
.height
) / PANGO_SCALE
;
942 if ((page_height
+ line_height
) > height
) {
943 page_breaks
= g_list_prepend(page_breaks
, GINT_TO_POINTER(ii
));
947 if (has_headers
&& ii
== num_header_lines
) {
949 pango_layout_iter_get_line_yrange(iter
,&y0
,&y1
);
950 print_data
->ypos_line
= (double)y0
+ 1./3.*((double)(y1
- y0
))/2.;
953 page_height
+= line_height
;
955 } while(ii
< num_lines
&& pango_layout_iter_next_line(iter
));
956 pango_layout_iter_free(iter
);
958 page_breaks
= g_list_reverse(page_breaks
);
959 print_data
->npages
= g_list_length(page_breaks
) + 1;
960 print_data
->page_breaks
= page_breaks
;
962 gtk_print_operation_set_n_pages(op
, print_data
->npages
);
964 debug_print("Starting print job...\n");
967 static cairo_surface_t
*pixbuf_to_surface(GdkPixbuf
*pixbuf
)
969 cairo_surface_t
*surface
;
970 cairo_format_t format
;
971 static const cairo_user_data_key_t key
;
972 guchar
*pixels
= g_malloc(
974 gdk_pixbuf_get_width(pixbuf
)*
975 gdk_pixbuf_get_height(pixbuf
));
976 guchar
*src_pixels
= gdk_pixbuf_get_pixels (pixbuf
);
977 gint width
= gdk_pixbuf_get_width(pixbuf
);
978 gint height
= gdk_pixbuf_get_height(pixbuf
);
979 gint nchans
= gdk_pixbuf_get_n_channels (pixbuf
);
980 gint stride
= gdk_pixbuf_get_rowstride (pixbuf
);
984 format
= CAIRO_FORMAT_RGB24
;
986 format
= CAIRO_FORMAT_ARGB32
;
987 surface
= cairo_image_surface_create_for_data (pixels
,
988 format
, width
, height
, 4*width
);
989 cairo_surface_set_user_data (surface
, &key
,
990 pixels
, (cairo_destroy_func_t
)g_free
);
992 for (j
= height
; j
; j
--) {
993 guchar
*p
= src_pixels
;
997 guchar
*end
= p
+ 3 * width
;
1000 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1013 guchar
*end
= p
+ 4 * width
;
1016 #define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END
1019 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1020 MULT(q
[0], p
[2], p
[3], t1
);
1021 MULT(q
[1], p
[1], p
[3], t2
);
1022 MULT(q
[2], p
[0], p
[3], t3
);
1026 MULT(q
[1], p
[0], p
[3], t1
);
1027 MULT(q
[2], p
[1], p
[3], t2
);
1028 MULT(q
[3], p
[2], p
[3], t3
);
1038 src_pixels
+= stride
;
1039 pixels
+= 4 * width
;
1045 static void printing_textview_cb_draw_page(GtkPrintOperation
*op
, GtkPrintContext
*context
,
1046 int page_nr
, gpointer user_data
)
1049 PrintData
*print_data
;
1052 PangoLayoutIter
*iter
;
1054 gboolean notlast
= TRUE
;
1056 print_data
= (PrintData
*) user_data
;
1061 pagebreak
= g_list_nth(print_data
->page_breaks
, page_nr
- 1);
1062 start
= GPOINTER_TO_INT(pagebreak
->data
);
1065 pagebreak
= g_list_nth(print_data
->page_breaks
, page_nr
);
1066 if (pagebreak
== NULL
)
1067 end
= pango_layout_get_line_count(print_data
->layout
);
1069 end
= GPOINTER_TO_INT(pagebreak
->data
);
1071 cr
= gtk_print_context_get_cairo_context(context
);
1072 cairo_scale(cr
, print_data
->zoom
, print_data
->zoom
);
1073 cairo_set_source_rgb(cr
, 0., 0., 0.);
1077 iter
= pango_layout_get_iter(print_data
->layout
);
1079 PangoRectangle logical_rect
;
1080 PangoLayoutLine
*line
;
1081 PangoAttrShape
*attr
= NULL
;
1085 line
= pango_layout_iter_get_line(iter
);
1087 pango_layout_iter_get_line_extents(iter
, NULL
, &logical_rect
);
1088 baseline
= pango_layout_iter_get_baseline(iter
);
1091 start_pos
= ((double)logical_rect
.y
) / PANGO_SCALE
;
1093 /* Draw header separator line */
1094 if (ii
== 0 && print_data
->ypos_line
>= 0) {
1095 cairo_surface_t
*surface
;
1096 surface
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32
,
1097 gtk_print_context_get_width(context
)/print_data
->zoom
,
1098 gtk_print_context_get_height(context
)/print_data
->zoom
);
1099 cairo_set_line_width(cr
, .5);
1100 cairo_set_source_surface(cr
, surface
,
1101 ((double)logical_rect
.x
) / PANGO_SCALE
,
1102 ((double)baseline
) / PANGO_SCALE
- start_pos
);
1103 cairo_move_to(cr
, ((double)logical_rect
.x
) / PANGO_SCALE
,
1104 (double)print_data
->ypos_line
/ PANGO_SCALE
);
1105 cairo_rel_line_to(cr
, gtk_print_context_get_width(context
)/print_data
->zoom
, 0);
1106 cairo_set_source_rgb(cr
, 0., 0., 0.);
1108 cairo_surface_destroy(surface
);
1112 ((double)logical_rect
.x
) / PANGO_SCALE
,
1113 ((double)baseline
) / PANGO_SCALE
- start_pos
);
1115 if ((attr
= g_hash_table_lookup(print_data
->images
,
1116 GINT_TO_POINTER(pango_layout_iter_get_index(iter
)))) != NULL
) {
1117 cairo_surface_t
*surface
;
1119 surface
= pixbuf_to_surface(GDK_PIXBUF(attr
->data
));
1120 cairo_set_source_surface (cr
, surface
,
1121 ((double)logical_rect
.x
) / PANGO_SCALE
,
1122 ((double)baseline
) / PANGO_SCALE
- start_pos
);
1124 cairo_surface_destroy (surface
);
1126 pango_cairo_show_layout_line(cr
, line
);
1130 } while(ii
< end
&& (notlast
= pango_layout_iter_next_line(iter
)));
1132 if (print_data
->avatar
&& page_nr
== 0) {
1133 cairo_surface_t
*surface
;
1134 GdkPixbuf
*pixbuf
= gtk_image_get_pixbuf(print_data
->avatar
);
1135 gdouble startx
, starty
;
1137 if (pixbuf
!= NULL
) {
1138 startx
= gtk_print_context_get_width(context
)/print_data
->zoom
;
1140 startx
-= ((double)gdk_pixbuf_get_width(pixbuf
));
1144 surface
= pixbuf_to_surface(pixbuf
);
1145 cairo_set_source_surface (cr
, surface
, startx
, starty
);
1147 cairo_surface_destroy (surface
);
1151 pango_layout_iter_free(iter
);
1152 debug_print("Sent page %d to printer\n", page_nr
+1);
1155 static void printing_layout_set_text_attributes(PrintData
*print_data
,
1156 GtkPrintContext
*context
,
1157 gboolean
*has_headers
)
1160 PangoAttrList
*attr_list
;
1161 PangoAttribute
*attr
;
1162 GSList
*open_attrs
, *attr_walk
;
1163 GtkTextView
*text_view
= GTK_TEXT_VIEW(print_data
->renderer_data
);
1164 GtkTextBuffer
*buffer
= gtk_text_view_get_buffer(text_view
);
1166 *has_headers
= FALSE
;
1168 attr_list
= pango_attr_list_new();
1169 if (print_data
->sel_start
< 0 || print_data
->sel_end
<= print_data
->sel_start
) {
1170 gtk_text_buffer_get_start_iter(buffer
, &iter
);
1172 gtk_text_buffer_get_iter_at_offset(buffer
, &iter
, print_data
->sel_start
);
1177 gboolean fg_set
, bg_set
, under_set
, strike_set
, weight_set
;
1178 GSList
*tags
, *tag_walk
;
1180 GdkRGBA
*color
= NULL
;
1181 PangoUnderline underline
;
1182 gboolean strikethrough
;
1186 if (prefs_common
.print_imgs
&& (image
= gtk_text_iter_get_pixbuf(&iter
)) != NULL
) {
1187 PangoRectangle rect
= {0, 0, 0, 0};
1188 gint startpos
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1189 gint h
= gdk_pixbuf_get_height(image
);
1190 gint w
= gdk_pixbuf_get_width(image
);
1191 gint a_h
= gtk_print_context_get_height(context
);
1192 gint a_w
= gtk_print_context_get_width(context
);
1194 GdkPixbuf
*scaled
= NULL
;
1195 image_viewer_get_resized_size(w
, h
, a_w
, a_h
, &r_w
, &r_h
);
1198 rect
.width
= r_w
* PANGO_SCALE
;
1199 rect
.height
= r_h
* PANGO_SCALE
;
1201 scaled
= gdk_pixbuf_scale_simple(image
, r_w
, r_h
, GDK_INTERP_BILINEAR
);
1202 attr
= pango_attr_shape_new_with_data (&rect
, &rect
,
1203 scaled
, NULL
, NULL
);
1204 attr
->start_index
= startpos
;
1205 attr
->end_index
= startpos
+1;
1206 pango_attr_list_insert(attr_list
, attr
);
1207 g_hash_table_insert(print_data
->images
, GINT_TO_POINTER(startpos
), attr
);
1208 print_data
->img_cnt
++;
1211 if (gtk_text_iter_ends_tag(&iter
, NULL
)) {
1212 PangoAttrColor
*attr_color
;
1213 PangoAttrInt
*attr_int
;
1215 tags
= gtk_text_iter_get_toggled_tags(&iter
, FALSE
);
1216 for (tag_walk
= tags
; tag_walk
!= NULL
; tag_walk
= tag_walk
->next
) {
1219 tag
= GTK_TEXT_TAG(tag_walk
->data
);
1220 g_object_get(G_OBJECT(tag
),
1221 "background-set", &bg_set
,
1222 "foreground-set", &fg_set
,
1223 "underline-set",&under_set
,
1224 "strikethrough-set", &strike_set
,
1225 "weight-set", &weight_set
,
1230 for (attr_walk
= open_attrs
; attr_walk
!= NULL
;
1231 attr_walk
= attr_walk
->next
) {
1232 attr
= (PangoAttribute
*)attr_walk
->data
;
1233 if (attr
->klass
->type
== PANGO_ATTR_FOREGROUND
) {
1234 attr_color
= (PangoAttrColor
*) attr
;
1235 g_object_get(G_OBJECT(tag
), "foreground-rgba",
1238 printing_is_pango_gdk_rgba_equal(&(attr_color
->color
),
1240 attr
->end_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1241 pango_attr_list_insert(attr_list
, attr
);
1243 open_attrs
= g_slist_delete_link(open_attrs
, attr_walk
);
1247 gdk_rgba_free(color
);
1251 debug_print("Error generating attribute list.\n");
1256 for (attr_walk
= open_attrs
; attr_walk
!= NULL
;
1257 attr_walk
= attr_walk
->next
) {
1258 attr
= (PangoAttribute
*)attr_walk
->data
;
1259 if (attr
->klass
->type
== PANGO_ATTR_BACKGROUND
) {
1260 attr_color
= (PangoAttrColor
*) attr
;
1261 g_object_get(G_OBJECT(tag
), "background-rgba",
1264 printing_is_pango_gdk_rgba_equal(&(attr_color
->color
),
1266 attr
->end_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1267 pango_attr_list_insert(attr_list
, attr
);
1269 open_attrs
= g_slist_delete_link(open_attrs
, attr_walk
);
1273 gdk_rgba_free(color
);
1277 debug_print("Error generating attribute list.\n");
1282 for (attr_walk
= open_attrs
; attr_walk
!= NULL
;
1283 attr_walk
= attr_walk
->next
) {
1284 attr
= (PangoAttribute
*)attr_walk
->data
;
1285 if (attr
->klass
->type
== PANGO_ATTR_UNDERLINE
) {
1286 attr_int
= (PangoAttrInt
*)attr
;
1287 g_object_get(G_OBJECT(tag
), "underline",
1289 if (attr_int
->value
== underline
) {
1290 attr
->end_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1291 pango_attr_list_insert(attr_list
, attr
);
1293 open_attrs
= g_slist_delete_link(open_attrs
, attr_walk
);
1299 debug_print("Error generating attribute list.\n");
1304 for (attr_walk
= open_attrs
; attr_walk
!= NULL
;
1305 attr_walk
= attr_walk
->next
) {
1306 attr
= (PangoAttribute
*)attr_walk
->data
;
1307 if (attr
->klass
->type
== PANGO_ATTR_STRIKETHROUGH
) {
1308 attr_int
= (PangoAttrInt
*)attr
;
1309 g_object_get(G_OBJECT(tag
), "strikethrough",
1310 &strikethrough
, NULL
);
1311 if (attr_int
->value
== strikethrough
) {
1312 attr
->end_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1313 pango_attr_list_insert(attr_list
, attr
);
1315 open_attrs
= g_slist_delete_link(open_attrs
, attr_walk
);
1321 debug_print("Error generating attribute list.\n");
1326 for (attr_walk
= open_attrs
; attr_walk
!= NULL
;
1327 attr_walk
= attr_walk
->next
) {
1328 attr
= (PangoAttribute
*)attr_walk
->data
;
1329 if (attr
->klass
->type
== PANGO_ATTR_WEIGHT
) {
1330 attr_int
= (PangoAttrInt
*)attr
;
1331 g_object_get(G_OBJECT(tag
), "weight", &weight
, NULL
);
1332 if (attr_int
->value
== weight
) {
1333 attr
->end_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1334 pango_attr_list_insert(attr_list
, attr
);
1336 open_attrs
= g_slist_delete_link(open_attrs
, attr_walk
);
1342 debug_print("Error generating attribute list.\n");
1348 if (gtk_text_iter_starts_tag(&iter
, NULL
)) {
1349 tags
= gtk_text_iter_get_toggled_tags(&iter
, TRUE
);
1350 /* Sometimes, an iter has several weights. Use only the first in this case */
1351 gboolean weight_set_for_this_iter
;
1352 weight_set_for_this_iter
= FALSE
;
1353 for (tag_walk
= tags
; tag_walk
!= NULL
; tag_walk
= tag_walk
->next
) {
1354 tag
= GTK_TEXT_TAG(tag_walk
->data
);
1355 g_object_get(G_OBJECT(tag
),
1356 "background-set", &bg_set
,
1357 "foreground-set", &fg_set
,
1358 "underline-set", &under_set
,
1359 "strikethrough-set", &strike_set
,
1360 "weight-set", &weight_set
,
1363 g_object_get(G_OBJECT(tag
), "foreground-rgba", &color
, NULL
);
1364 PangoColor
*pc
= printing_pango_color_from_gdk_rgba(color
);
1365 attr
= pango_attr_foreground_new(pc
->red
, pc
->green
, pc
->blue
);
1366 attr
->start_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1367 open_attrs
= g_slist_prepend(open_attrs
, attr
);
1371 g_object_get(G_OBJECT(tag
), "background-rgba", &color
, NULL
);
1372 PangoColor
*pc
= printing_pango_color_from_gdk_rgba(color
);
1373 attr
= pango_attr_background_new(pc
->red
, pc
->green
, pc
->blue
);
1374 attr
->start_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1375 open_attrs
= g_slist_prepend(open_attrs
, attr
);
1379 g_object_get(G_OBJECT(tag
), "underline", &underline
, NULL
);
1380 attr
= pango_attr_underline_new(underline
);
1381 attr
->start_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1382 open_attrs
= g_slist_prepend(open_attrs
, attr
);
1385 g_object_get(G_OBJECT(tag
), "strikethrough", &strikethrough
, NULL
);
1386 attr
= pango_attr_strikethrough_new(strikethrough
);
1387 attr
->start_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1388 open_attrs
= g_slist_prepend(open_attrs
, attr
);
1390 if (weight_set
&& !weight_set_for_this_iter
) {
1391 weight_set_for_this_iter
= TRUE
;
1392 g_object_get(G_OBJECT(tag
), "weight", &weight
, NULL
);
1393 attr
= pango_attr_weight_new(weight
);
1394 attr
->start_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1395 open_attrs
= g_slist_prepend(open_attrs
, attr
);
1396 /* Hack to see if the first char is bold -- indicates header */
1397 if (attr
->start_index
== 0 && weight
== PANGO_WEIGHT_BOLD
) {
1398 *has_headers
= TRUE
;
1405 } while(!gtk_text_iter_is_end(&iter
) && gtk_text_iter_forward_to_tag_toggle(&iter
, NULL
));
1407 /* close all open attributes */
1408 for (attr_walk
= open_attrs
; attr_walk
!= NULL
; attr_walk
= attr_walk
->next
) {
1409 attr
= (PangoAttribute
*) attr_walk
->data
;
1410 attr
->end_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1411 pango_attr_list_insert(attr_list
, attr
);
1413 g_slist_free(open_attrs
);
1415 pango_layout_set_attributes(print_data
->layout
, attr_list
);
1416 pango_attr_list_unref(attr_list
);
1419 PangoColor
* printing_pango_color_from_gdk_rgba(GdkRGBA
* g
)
1423 c
= g_new(PangoColor
, 1);
1424 c
->red
= (guint16
) (g
->red
* 65535);
1425 c
->green
= (guint16
) (g
->green
* 65535);
1426 c
->blue
= (guint16
) (g
->blue
* 65535);
1430 static gboolean
printing_is_pango_gdk_rgba_equal(PangoColor
*p
, GdkRGBA
*g
)
1434 c
.red
= (guint16
) (g
->red
* 65535);
1435 c
.green
= (guint16
) (g
->green
* 65535);
1436 c
.blue
= (guint16
) (g
->blue
* 65535);
1437 return ((c
.red
== p
->red
) && (c
.green
== p
->green
) && (c
.blue
== p
->blue
));
1440 /* Pango has it's attribute in bytes, but GtkTextIter gets only an offset
1441 * in characters, so here we're returning an offset in bytes.
1443 static gint
printing_text_iter_get_offset_bytes(PrintData
*print_data
, const GtkTextIter
*iter
)
1449 if (print_data
->sel_start
< 0 || print_data
->sel_end
<= print_data
->sel_start
) {
1450 gtk_text_buffer_get_start_iter(gtk_text_iter_get_buffer(iter
), &start
);
1452 gtk_text_buffer_get_iter_at_offset(gtk_text_iter_get_buffer(iter
), &start
, print_data
->sel_start
);
1454 text
= gtk_text_iter_get_text(&start
, iter
);
1455 off_bytes
= strlen(text
);
1460 static void printing_preview_update_zoom_sensitivity(PreviewData
*preview_data
)
1462 if((preview_data
->print_data
->zoom
* PREVIEW_ZOOM_FAC
) > PREVIEW_ZOOM_MAX
)
1463 gtk_widget_set_sensitive(preview_data
->zoom_in
, FALSE
);
1465 gtk_widget_set_sensitive(preview_data
->zoom_in
, TRUE
);
1467 if ((preview_data
->print_data
->zoom
/ PREVIEW_ZOOM_FAC
) < PREVIEW_ZOOM_MIN
)
1468 gtk_widget_set_sensitive(preview_data
->zoom_out
, FALSE
);
1470 gtk_widget_set_sensitive(preview_data
->zoom_out
, TRUE
);