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 static gboolean
cb_preview_expose(GtkWidget
*, GdkEventExpose
*, gpointer
);
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_color_equal(PangoColor
*, GdkColor
*);
122 static gint
printing_text_iter_get_offset_bytes(PrintData
*, const GtkTextIter
*);
124 #define PAGE_MARGIN_STORAGE_UNIT GTK_UNIT_MM
125 #define PREVIEW_SCALE 72
126 #define PREVIEW_SHADOW_OFFSET 3
127 #define PREVIEW_ZOOM_FAC 1.41
128 #define PREVIEW_ZOOM_MAX 10.
129 #define PREVIEW_ZOOM_MIN 0.2
131 static void free_pixbuf(gpointer key
, gpointer value
, gpointer data
)
133 PangoAttrShape
*attr
= (PangoAttrShape
*) value
;
134 g_object_unref(G_OBJECT(attr
->data
));
137 gpointer
printing_get_renderer_data(PrintData
*print_data
)
141 return print_data
->renderer_data
;
144 gdouble
printing_get_zoom(PrintData
*print_data
)
148 return print_data
->zoom
;
151 void printing_set_n_pages(PrintData
*print_data
, gint n_pages
)
155 print_data
->npages
= n_pages
;
158 GtkPrintSettings
*printing_get_settings(void)
160 if (settings
== NULL
) {
161 settings
= gtk_print_settings_new();
162 gtk_print_settings_set_use_color(settings
, prefs_common
.print_use_color
);
163 gtk_print_settings_set_collate(settings
, prefs_common
.print_use_collate
);
164 gtk_print_settings_set_reverse(settings
, prefs_common
.print_use_reverse
);
165 gtk_print_settings_set_duplex(settings
, prefs_common
.print_use_duplex
);
170 void printing_store_settings(GtkPrintSettings
*new_settings
)
172 if (settings
!= NULL
)
173 g_object_unref(settings
);
175 settings
= g_object_ref(new_settings
);
176 prefs_common
.print_use_color
= gtk_print_settings_get_use_color(settings
);
177 prefs_common
.print_use_collate
= gtk_print_settings_get_collate(settings
);
178 prefs_common
.print_use_reverse
= gtk_print_settings_get_reverse(settings
);
179 prefs_common
.print_use_duplex
= gtk_print_settings_get_duplex(settings
);
182 GtkPageSetup
*printing_get_page_setup(void)
184 if (page_setup
== NULL
) {
185 gboolean read_from_file
;
186 char *page_setup_filename
;
188 gboolean key_file_read
;
190 page_setup
= gtk_page_setup_new();
192 read_from_file
= FALSE
;
194 /* try reading the page setup from file */
195 page_setup_filename
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
196 PRINTING_PAGE_SETUP_STORAGE_FILE
, NULL
);
197 keyfile
= g_key_file_new();
198 key_file_read
= g_key_file_load_from_file(keyfile
, page_setup_filename
,
200 g_free(page_setup_filename
);
203 read_from_file
= gtk_page_setup_load_key_file(page_setup
, keyfile
,
205 g_key_file_free(keyfile
);
207 if (read_from_file
) {
208 debug_print("Printing: Read page setup from key file\n");
210 debug_print("Printing: Could not read page setup from key file\n");
213 /* if reading from file did not work, or has not been tried (GTK+ < 2.14), use prefs */
214 if (!read_from_file
) {
216 if (prefs_common
.print_paper_type
&&
217 *prefs_common
.print_paper_type
) {
218 GtkPaperSize
*paper
= gtk_paper_size_new(prefs_common
.print_paper_type
);
219 gtk_page_setup_set_paper_size(page_setup
, paper
);
220 gtk_paper_size_free(paper
);
223 gtk_page_setup_set_orientation(page_setup
,
224 prefs_common
.print_paper_orientation
);
226 if (prefs_common
.print_margin_top
!= -1)
227 gtk_page_setup_set_top_margin(page_setup
,
228 0.01*prefs_common
.print_margin_top
,
229 PAGE_MARGIN_STORAGE_UNIT
);
230 if (prefs_common
.print_margin_bottom
!= -1)
231 gtk_page_setup_set_bottom_margin(page_setup
,
232 0.01*prefs_common
.print_margin_bottom
,
233 PAGE_MARGIN_STORAGE_UNIT
);
234 if (prefs_common
.print_margin_left
!= -1)
235 gtk_page_setup_set_left_margin(page_setup
,
236 0.01*prefs_common
.print_margin_left
,
237 PAGE_MARGIN_STORAGE_UNIT
);
238 if (prefs_common
.print_margin_right
!= -1)
239 gtk_page_setup_set_right_margin(page_setup
,
240 0.01*prefs_common
.print_margin_right
,
241 PAGE_MARGIN_STORAGE_UNIT
);
247 void printing_print_full(GtkWindow
*parent
, PrintRenderer
*renderer
, gpointer renderer_data
,
248 gint sel_start
, gint sel_end
, GtkImage
*avatar
)
250 GtkPrintOperation
*op
;
251 GtkPrintOperationResult res
;
252 PrintData
*print_data
;
254 op
= gtk_print_operation_new();
256 print_data
= g_new0(PrintData
,1);
258 print_data
->renderer
= renderer
;
259 print_data
->renderer_data
= renderer_data
;
260 print_data
->sel_start
= sel_start
;
261 print_data
->sel_end
= sel_end
;
262 print_data
->avatar
= (avatar
!= NULL
? GTK_IMAGE(g_object_ref(avatar
)): NULL
);
264 print_data
->zoom
= 1.;
266 print_data
->images
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
268 print_data
->pango_context
= renderer
->get_pango_context(renderer_data
);
270 print_data
->to_print
= renderer
->get_data_to_print(renderer_data
, sel_start
, sel_end
);
272 printing_get_settings();
273 printing_get_page_setup();
275 /* Config for printing */
276 gtk_print_operation_set_print_settings(op
, settings
);
277 gtk_print_operation_set_default_page_setup(op
, page_setup
);
278 /* enable Page Size and Orientation in the print dialog */
279 gtk_print_operation_set_embed_page_setup(op
, TRUE
);
281 g_signal_connect(op
, "begin_print", G_CALLBACK(renderer
->cb_begin_print
), print_data
);
282 g_signal_connect(op
, "draw_page", G_CALLBACK(renderer
->cb_draw_page
), print_data
);
283 g_signal_connect(op
, "preview", G_CALLBACK(cb_preview
), print_data
);
285 /* Start printing process */
286 res
= gtk_print_operation_run(op
, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG
,
289 if (res
== GTK_PRINT_OPERATION_RESULT_ERROR
) {
290 GError
*error
= NULL
;
291 gtk_print_operation_get_error(op
, &error
);
292 debug_print("Error printing message: %s\n",
293 error
? error
->message
: "no details");
294 } else if (res
== GTK_PRINT_OPERATION_RESULT_APPLY
) {
295 /* store settings for next printing session */
296 printing_store_settings(gtk_print_operation_get_print_settings(op
));
299 g_hash_table_foreach(print_data
->images
, free_pixbuf
, NULL
);
300 g_hash_table_destroy(print_data
->images
);
301 if (print_data
->to_print
)
302 g_free(print_data
->to_print
);
303 g_list_free(print_data
->page_breaks
);
304 if (print_data
->layout
)
305 g_object_unref(print_data
->layout
);
306 if (print_data
->avatar
)
307 g_object_unref(print_data
->avatar
);
312 debug_print("printing_print finished\n");
315 static PangoContext
*printing_textview_get_pango_context(gpointer data
)
317 return gtk_widget_get_pango_context(GTK_WIDGET(data
));
320 static gpointer
printing_textview_get_data_to_print(gpointer data
, gint sel_start
, gint sel_end
)
322 GtkTextView
*text_view
= GTK_TEXT_VIEW(data
);
323 GtkTextBuffer
*buffer
= gtk_text_view_get_buffer(text_view
);
324 GtkTextIter start
, end
;
326 if (sel_start
< 0 || sel_end
<= sel_start
) {
327 gtk_text_buffer_get_start_iter(buffer
, &start
);
328 gtk_text_buffer_get_end_iter(buffer
, &end
);
330 gtk_text_buffer_get_iter_at_offset(buffer
, &start
, sel_start
);
331 gtk_text_buffer_get_iter_at_offset(buffer
, &end
, sel_end
);
334 return gtk_text_buffer_get_text(buffer
, &start
, &end
, FALSE
);
337 void printing_print(GtkTextView
*text_view
, GtkWindow
*parent
, gint sel_start
, gint sel_end
, GtkImage
*avatar
)
339 PrintRenderer
*textview_renderer
= g_new0(PrintRenderer
, 1);
341 textview_renderer
->get_pango_context
= printing_textview_get_pango_context
;
342 textview_renderer
->get_data_to_print
= printing_textview_get_data_to_print
;
343 textview_renderer
->cb_begin_print
= printing_textview_cb_begin_print
;
344 textview_renderer
->cb_draw_page
= printing_textview_cb_draw_page
;
346 printing_print_full(parent
, textview_renderer
, text_view
, sel_start
, sel_end
, avatar
);
348 g_free(textview_renderer
);
351 void printing_page_setup(GtkWindow
*parent
)
353 GtkPageSetup
*new_page_setup
;
358 printing_get_settings();
359 printing_get_page_setup();
361 new_page_setup
= gtk_print_run_page_setup_dialog(parent
,page_setup
,settings
);
364 g_object_unref(page_setup
);
366 page_setup
= new_page_setup
;
368 g_free(prefs_common
.print_paper_type
);
369 prefs_common
.print_paper_type
= g_strdup(gtk_paper_size_get_name(
370 gtk_page_setup_get_paper_size(page_setup
)));
371 prefs_common
.print_paper_orientation
= gtk_page_setup_get_orientation(page_setup
);
372 /* store 100th millimeters */
373 prefs_common
.print_margin_top
= (int) (100*gtk_page_setup_get_top_margin(page_setup
,
374 PAGE_MARGIN_STORAGE_UNIT
));
375 prefs_common
.print_margin_bottom
= (int) (100*gtk_page_setup_get_bottom_margin(page_setup
,
376 PAGE_MARGIN_STORAGE_UNIT
));
377 prefs_common
.print_margin_left
= (int) (100*gtk_page_setup_get_left_margin(page_setup
,
378 PAGE_MARGIN_STORAGE_UNIT
));
379 prefs_common
.print_margin_right
= (int) (100*gtk_page_setup_get_right_margin(page_setup
,
380 PAGE_MARGIN_STORAGE_UNIT
));
383 keyfile
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
384 PRINTING_PAGE_SETUP_STORAGE_FILE
, NULL
);
385 if (!gtk_page_setup_to_file(page_setup
, keyfile
, NULL
)) {
386 debug_print("Printing: Could not store page setup in file `%s'\n", keyfile
);
391 static gboolean
cb_preview(GtkPrintOperation
*operation
,
392 GtkPrintOperationPreview
*preview
,
393 GtkPrintContext
*context
,
397 PrintData
*print_data
;
399 PreviewData
*preview_data
;
405 GtkToolItem
*separator
;
406 static GdkGeometry geometry
;
407 GtkWidget
*dialog
= NULL
;
408 GtkWidget
*statusbar
= gtk_hbox_new(2, FALSE
);
410 debug_print("Creating internal print preview\n");
412 print_data
= (PrintData
*) data
;
414 preview_data
= g_new0(PreviewData
,1);
415 preview_data
->print_data
= print_data
;
416 preview_data
->op
= g_object_ref(operation
);
417 preview_data
->preview
= preview
;
420 dialog
= gtkut_window_new(GTK_WINDOW_TOPLEVEL
, "print_preview");
421 preview_data
->dialog
= dialog
;
422 if (!geometry
.min_height
) {
423 geometry
.min_width
= 600;
424 geometry
.min_height
= 400;
426 gtk_window_set_type_hint(GTK_WINDOW(dialog
), GDK_WINDOW_TYPE_HINT_DIALOG
);
427 gtk_window_set_geometry_hints(GTK_WINDOW(dialog
), NULL
, &geometry
,
429 gtk_widget_set_size_request(dialog
, prefs_common
.print_previewwin_width
,
430 prefs_common
.print_previewwin_height
);
431 gtk_window_set_title(GTK_WINDOW(dialog
), _("Print preview"));
434 vbox
= gtk_vbox_new(FALSE
, 0);
435 gtk_container_add(GTK_CONTAINER(dialog
), vbox
);
438 toolbar
= gtk_toolbar_new();
439 gtk_orientable_set_orientation(GTK_ORIENTABLE(toolbar
), GTK_ORIENTATION_HORIZONTAL
);
441 switch (prefs_common
.toolbar_style
) {
443 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar
), GTK_TOOLBAR_ICONS
);
446 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar
), GTK_TOOLBAR_TEXT
);
448 case TOOLBAR_BOTH_HORIZ
:
449 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar
), GTK_TOOLBAR_BOTH_HORIZ
);
453 gtk_toolbar_set_style(GTK_TOOLBAR(toolbar
), GTK_TOOLBAR_BOTH
);
455 gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolbar
), TRUE
);
457 gtk_box_pack_start(GTK_BOX(vbox
), toolbar
, FALSE
, FALSE
, 0);
459 #define CLAWS_SET_TOOL_ITEM_TIP(widget,tip) { \
460 gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), tip); \
463 #define TOOLBAR_ITEM(item,text,tooltip,cb,cbdata) { \
464 item = GTK_WIDGET(gtk_tool_button_new_from_stock(text)); \
465 gtk_tool_item_set_homogeneous(GTK_TOOL_ITEM(item), FALSE); \
466 gtk_tool_item_set_is_important(GTK_TOOL_ITEM(item), TRUE); \
467 gtk_toolbar_insert(GTK_TOOLBAR(toolbar), GTK_TOOL_ITEM(item), -1); \
468 g_signal_connect (G_OBJECT(item), "clicked", G_CALLBACK(cb), cbdata); \
469 CLAWS_SET_TOOL_ITEM_TIP(GTK_TOOL_ITEM(item), \
473 TOOLBAR_ITEM(preview_data
->first
, GTK_STOCK_GOTO_FIRST
,
474 _("First page"), cb_preview_go_first
, preview_data
);
475 TOOLBAR_ITEM(preview_data
->previous
, GTK_STOCK_GO_BACK
,
476 _("Previous page"), cb_preview_go_previous
, preview_data
);
478 page
= gtk_label_new("");
479 preview_data
->page_nr_label
= page
;
481 TOOLBAR_ITEM(preview_data
->next
, GTK_STOCK_GO_FORWARD
,
482 _("Next page"), cb_preview_go_next
, preview_data
);
483 TOOLBAR_ITEM(preview_data
->last
, GTK_STOCK_GOTO_LAST
,
484 _("Last page"), cb_preview_go_last
, preview_data
);
486 separator
= gtk_separator_tool_item_new();
487 gtk_toolbar_insert(GTK_TOOLBAR(toolbar
), GTK_TOOL_ITEM(separator
), -1);
489 TOOLBAR_ITEM(preview_data
->zoom_100
, GTK_STOCK_ZOOM_100
,
490 _("Zoom 100%"), cb_preview_zoom_100
, preview_data
);
491 TOOLBAR_ITEM(preview_data
->zoom_fit
, GTK_STOCK_ZOOM_FIT
,
492 _("Zoom fit"), cb_preview_zoom_fit
, preview_data
);
493 TOOLBAR_ITEM(preview_data
->zoom_in
, GTK_STOCK_ZOOM_IN
,
494 _("Zoom in"), cb_preview_zoom_in
, preview_data
);
495 TOOLBAR_ITEM(preview_data
->zoom_out
, GTK_STOCK_ZOOM_OUT
,
496 _("Zoom out"), cb_preview_zoom_out
, preview_data
);
498 separator
= gtk_separator_tool_item_new();
499 gtk_toolbar_insert(GTK_TOOLBAR(toolbar
), GTK_TOOL_ITEM(separator
), -1);
501 /* tooltip has to be NULL else it triggers an expose_event */
502 TOOLBAR_ITEM(preview_data
->close
, GTK_STOCK_CLOSE
, NULL
,
503 cb_preview_btn_close
, preview_data
);
505 gtk_widget_show(statusbar
);
506 gtk_box_pack_start(GTK_BOX(vbox
), statusbar
, FALSE
, FALSE
, 0);
507 gtk_box_pack_start(GTK_BOX(statusbar
), page
, FALSE
, FALSE
, 0);
509 sw
= gtk_scrolled_window_new(NULL
, NULL
);
510 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
),
511 GTK_POLICY_AUTOMATIC
,
512 GTK_POLICY_AUTOMATIC
);
513 gtk_box_pack_start(GTK_BOX(vbox
), sw
, TRUE
, TRUE
, 0);
514 da
= gtk_drawing_area_new();
515 gtk_widget_set_double_buffered(da
, FALSE
);
516 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw
),
518 gtk_widget_realize(da
);
519 preview_data
->scrolled_window
= sw
;
520 preview_data
->area
= da
;
523 cr
= gdk_cairo_create(gtk_widget_get_window(da
));
524 gtk_print_context_set_cairo_context(context
, cr
, PREVIEW_SCALE
, PREVIEW_SCALE
);
528 g_signal_connect(dialog
, "key_press_event",
529 G_CALLBACK(cb_preview_close
), preview_data
);
530 g_signal_connect(dialog
, "size_allocate",
531 G_CALLBACK(cb_preview_size_allocate
), NULL
);
532 g_signal_connect(dialog
, "destroy",G_CALLBACK(cb_preview_destroy
),
534 g_signal_connect(preview
, "ready", G_CALLBACK(cb_preview_ready
),
536 g_signal_connect(preview
, "got-page-size",
537 G_CALLBACK(cb_preview_got_page_size
), preview_data
);
539 g_signal_connect(operation
, "request-page-setup",
540 G_CALLBACK(cb_preview_request_page_setup
), preview_data
);
542 gtk_widget_show_all(dialog
);
546 static void cb_preview_destroy(GtkWindow
*window
, gpointer data
)
548 PreviewData
*preview_data
;
549 preview_data
= (PreviewData
*) data
;
551 if (preview_data
->rendering
)
553 debug_print("Preview window destroyed\n");
555 gtk_print_operation_preview_end_preview(preview_data
->preview
);
556 g_object_unref(preview_data
->op
);
557 g_list_free(preview_data
->pages_to_print
);
559 g_free(preview_data
);
562 static gboolean
cb_preview_close(GtkWidget
*widget
, GdkEventAny
*event
,
565 PreviewData
*preview_data
= (PreviewData
*)data
;
566 if (event
->type
== GDK_KEY_PRESS
)
567 if (((GdkEventKey
*)event
)->keyval
!= GDK_KEY_Escape
)
569 if (preview_data
->rendering
)
571 gtk_widget_destroy(widget
);
575 static void cb_preview_size_allocate(GtkWidget
*widget
,
576 GtkAllocation
*allocation
)
578 cm_return_if_fail(allocation
!= NULL
);
580 prefs_common
.print_previewwin_width
= allocation
->width
;
581 prefs_common
.print_previewwin_height
= allocation
->height
;
584 static void cb_preview_ready(GtkPrintOperationPreview
*preview
,
585 GtkPrintContext
*context
,
588 PreviewData
*preview_data
;
590 preview_data
= (PreviewData
*) data
;
591 debug_print("preview_ready %d\n", preview_data
->print_data
->npages
);
593 for (iPage
= 0; iPage
< (preview_data
->print_data
->npages
); iPage
++) {
594 if (gtk_print_operation_preview_is_selected(preview_data
->preview
, iPage
)) {
595 preview_data
->pages_to_print
=
596 g_list_prepend(preview_data
->pages_to_print
,
597 GINT_TO_POINTER(iPage
));
598 debug_print("want to print page %d\n",iPage
+1);
602 preview_data
->pages_to_print
= g_list_reverse(preview_data
->pages_to_print
);
603 preview_data
->current_page
= preview_data
->pages_to_print
;
604 preview_data
->context
= context
;
606 g_signal_connect(preview_data
->area
, "expose_event",
607 G_CALLBACK(cb_preview_expose
),
610 gtk_widget_queue_draw(preview_data
->area
);
613 static void cb_preview_got_page_size(GtkPrintOperationPreview
*preview
,
614 GtkPrintContext
*context
,
615 GtkPageSetup
*page_setup
,
618 PreviewData
*preview_data
;
619 GtkPaperSize
*paper_size
;
623 preview_data
= (PreviewData
*) data
;
624 debug_print("got_page_size\n");
625 paper_size
= gtk_page_setup_get_paper_size(page_setup
);
626 paper_width
= (gint
)(gtk_paper_size_get_width(paper_size
, GTK_UNIT_INCH
)
628 paper_height
= (gint
)(gtk_paper_size_get_height(paper_size
, GTK_UNIT_INCH
)
631 preview_data
->page_width
= paper_width
;
632 preview_data
->page_height
= paper_height
;
634 debug_print("w/h %d/%d\n", paper_width
, paper_height
);
635 gtk_widget_set_size_request(GTK_WIDGET(preview_data
->area
),
636 paper_width
, paper_height
);
639 static gboolean
cb_preview_expose(GtkWidget
*widget
, GdkEventExpose
*event
,
642 PreviewData
*preview_data
= data
;
645 debug_print("preview_expose (current %p)\n", preview_data
->current_page
);
647 cr
= gdk_cairo_create(gtk_widget_get_window(preview_data
->area
));
650 cairo_set_source_rgb(cr
, 0.5, 0.5, 0.5);
651 cairo_rectangle(cr
, event
->area
.x
, event
->area
.y
, event
->area
.width
, event
->area
.height
);
655 cairo_set_source_rgb(cr
, 0., 0., 0.);
656 cairo_rectangle(cr
, PREVIEW_SHADOW_OFFSET
, PREVIEW_SHADOW_OFFSET
,
657 preview_data
->page_width
+PREVIEW_SHADOW_OFFSET
,
658 preview_data
->page_height
+PREVIEW_SHADOW_OFFSET
);
662 cairo_set_source_rgb(cr
, 1., 1., 1.);
663 cairo_rectangle(cr
, 0, 0,
664 preview_data
->page_width
,
665 preview_data
->page_height
);
668 gtk_print_context_set_cairo_context(preview_data
->context
, cr
, PREVIEW_SCALE
, PREVIEW_SCALE
);
671 if (preview_data
->current_page
) {
672 preview_data
->rendering
= TRUE
;
673 gtk_widget_set_sensitive(preview_data
->close
, FALSE
);
674 int cur
= GPOINTER_TO_INT(preview_data
->current_page
->data
);
676 str
= g_strdup_printf(_("Page %d"), cur
+1);
677 gtk_label_set_text(GTK_LABEL(preview_data
->page_nr_label
), str
);
679 gtk_print_operation_preview_render_page(preview_data
->preview
,
681 (preview_data
->current_page
->data
));
683 gtk_widget_set_sensitive(preview_data
->first
,
684 preview_data
->current_page
->prev
!= NULL
);
685 gtk_widget_set_sensitive(preview_data
->previous
,
686 preview_data
->current_page
->prev
!= NULL
);
687 gtk_widget_set_sensitive(preview_data
->next
,
688 preview_data
->current_page
->next
!= NULL
);
689 gtk_widget_set_sensitive(preview_data
->last
,
690 preview_data
->current_page
->next
!= NULL
);
691 gtk_widget_set_sensitive(preview_data
->close
, TRUE
);
692 preview_data
->rendering
= FALSE
;
697 static void cb_preview_go_first(GtkButton
*button
, gpointer data
)
699 PreviewData
*preview_data
= (PreviewData
*) data
;
700 preview_data
->current_page
= preview_data
->pages_to_print
;
701 gtk_widget_queue_draw(preview_data
->area
);
704 static void cb_preview_go_previous(GtkButton
*button
, gpointer data
)
707 PreviewData
*preview_data
= (PreviewData
*) data
;
708 next
= g_list_previous(preview_data
->current_page
);
710 preview_data
->current_page
= next
;
711 gtk_widget_queue_draw(preview_data
->area
);
714 static void cb_preview_go_next(GtkButton
*button
, gpointer data
)
717 PreviewData
*preview_data
= (PreviewData
*) data
;
718 next
= g_list_next(preview_data
->current_page
);
720 preview_data
->current_page
= next
;
721 gtk_widget_queue_draw(preview_data
->area
);
724 static void cb_preview_go_last(GtkButton
*button
, gpointer data
)
726 PreviewData
*preview_data
= (PreviewData
*) data
;
727 preview_data
->current_page
= g_list_last(preview_data
->current_page
);
728 gtk_widget_queue_draw(preview_data
->area
);
731 static void cb_preview_btn_close(GtkButton
*button
, gpointer data
)
733 PreviewData
*preview_data
= (PreviewData
*)data
;
734 if (preview_data
->rendering
)
736 gtk_widget_destroy(preview_data
->dialog
);
739 static void cb_preview_zoom_100(GtkButton
*button
, gpointer data
)
741 PreviewData
*preview_data
= (PreviewData
*) data
;
742 if (preview_data
->print_data
->zoom
!= 1.) {
743 preview_data
->print_data
->zoom
= 1.;
744 gtk_widget_queue_draw(preview_data
->area
);
745 printing_preview_update_zoom_sensitivity(preview_data
);
749 static void cb_preview_zoom_fit(GtkButton
*button
, gpointer data
)
751 PreviewData
*preview_data
= (PreviewData
*) data
;
752 GtkAllocation allocation
;
756 gtk_widget_get_allocation(preview_data
->scrolled_window
, &allocation
);
757 zoom_w
= ((gdouble
)allocation
.width
) /
758 ((gdouble
)preview_data
->page_width
/preview_data
->print_data
->zoom
+
759 PREVIEW_SHADOW_OFFSET
);
760 zoom_h
= ((gdouble
)allocation
.height
) /
761 ((gdouble
)preview_data
->page_height
/preview_data
->print_data
->zoom
+
762 PREVIEW_SHADOW_OFFSET
);
764 preview_data
->print_data
->zoom
= MIN(zoom_w
,zoom_h
) - 0.01;
766 if (preview_data
->print_data
->zoom
> PREVIEW_ZOOM_MAX
)
767 preview_data
->print_data
->zoom
= PREVIEW_ZOOM_MAX
;
768 else if (preview_data
->print_data
->zoom
< PREVIEW_ZOOM_MIN
)
769 preview_data
->print_data
->zoom
= PREVIEW_ZOOM_MIN
;
771 printing_preview_update_zoom_sensitivity(preview_data
);
772 gtk_widget_queue_draw(preview_data
->area
);
775 static void cb_preview_zoom_in(GtkButton
*button
, gpointer data
)
777 PreviewData
*preview_data
= (PreviewData
*) data
;
779 new_zoom
= preview_data
->print_data
->zoom
* PREVIEW_ZOOM_FAC
;
780 if (new_zoom
<= PREVIEW_ZOOM_MAX
) {
781 preview_data
->print_data
->zoom
= new_zoom
;
782 printing_preview_update_zoom_sensitivity(preview_data
);
783 gtk_widget_queue_draw(preview_data
->area
);
787 static void cb_preview_zoom_out(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_MIN
) {
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_request_page_setup(GtkPrintOperation
*op
,
800 GtkPrintContext
*context
,
802 GtkPageSetup
*setup
,gpointer data
)
804 GtkPaperSize
*paper_size
;
805 GtkPaperSize
*old_size
;
809 gdouble bottom_margin
;
811 gdouble right_margin
;
813 PreviewData
*preview_data
= (PreviewData
*) data
;
815 old_size
= gtk_page_setup_get_paper_size(setup
);
816 width
= gtk_paper_size_get_width(old_size
,GTK_UNIT_INCH
);
817 height
= gtk_paper_size_get_height(old_size
,GTK_UNIT_INCH
);
819 top_margin
= gtk_page_setup_get_top_margin(setup
,GTK_UNIT_INCH
);
820 bottom_margin
= gtk_page_setup_get_bottom_margin(setup
,GTK_UNIT_INCH
);
821 left_margin
= gtk_page_setup_get_left_margin(setup
,GTK_UNIT_INCH
);
822 right_margin
= gtk_page_setup_get_right_margin(setup
,GTK_UNIT_INCH
);
824 paper_size
= gtk_paper_size_new_custom("preview paper", "preview_paper",
825 width
*preview_data
->print_data
->zoom
,
826 height
*preview_data
->print_data
->zoom
,
828 gtk_page_setup_set_paper_size(setup
, paper_size
);
829 gtk_paper_size_free(paper_size
);
831 gtk_page_setup_set_top_margin(setup
,top_margin
*preview_data
->print_data
->zoom
,
833 gtk_page_setup_set_bottom_margin(setup
,bottom_margin
*preview_data
->print_data
->zoom
,
835 gtk_page_setup_set_left_margin(setup
,left_margin
*preview_data
->print_data
->zoom
,
837 gtk_page_setup_set_right_margin(setup
,right_margin
*preview_data
->print_data
->zoom
,
841 static void printing_textview_cb_begin_print(GtkPrintOperation
*op
, GtkPrintContext
*context
,
844 double width
, height
;
848 PrintData
*print_data
;
849 PangoFontDescription
*desc
;
851 PangoLayoutIter
*iter
;
853 gint num_header_lines
;
855 gboolean header_done
;
856 gboolean has_headers
= FALSE
;
858 double line_height
=0.;
860 print_data
= (PrintData
*) user_data
;
862 debug_print("Preparing print job...\n");
864 width
= gtk_print_context_get_width(context
);
865 height
= gtk_print_context_get_height(context
);
867 if (print_data
->layout
== NULL
)
868 print_data
->layout
= gtk_print_context_create_pango_layout(context
);
870 if (prefs_common
.use_different_print_font
)
871 desc
= pango_font_description_from_string(prefs_common
.printfont
);
873 desc
= pango_font_description_copy(
874 pango_context_get_font_description(print_data
->pango_context
));
876 pango_layout_set_font_description(print_data
->layout
, desc
);
877 pango_font_description_free(desc
);
879 pango_layout_set_width(print_data
->layout
, width
* PANGO_SCALE
);
880 pango_layout_set_text(print_data
->layout
, (char *)print_data
->to_print
, -1);
882 printing_layout_set_text_attributes(print_data
, context
, &has_headers
);
884 num_lines
= pango_layout_get_line_count(print_data
->layout
);
890 iter
= pango_layout_get_iter(print_data
->layout
);
892 /* find the last character of the header */
895 text
= pango_layout_get_text(print_data
->layout
);
898 if (text
&& *text
&& *text
!= '\n') {
900 if (text
[0] == '\n' && (text
[1] != '\0') && (text
[1] == '\n'))
905 } while(*text
&& !header_done
);
907 /* find line number for header end */
908 pango_layout_index_to_line_x(print_data
->layout
, header_end_pos
, 1,
909 &num_header_lines
, &dummy
);
910 /* line count is zero-based */
913 print_data
->ypos_line
= -1.0;
917 PangoRectangle logical_rect
;
918 PangoAttrShape
*attr
= NULL
;
921 pango_layout_iter_get_line_extents(iter
, NULL
, &logical_rect
);
923 if ((attr
= g_hash_table_lookup(print_data
->images
,
924 GINT_TO_POINTER(pango_layout_iter_get_index(iter
)))) != NULL
) {
925 line_height
= (double)gdk_pixbuf_get_height(GDK_PIXBUF(attr
->data
));
927 line_height
= ((double)logical_rect
.height
) / PANGO_SCALE
;
930 if ((page_height
+ line_height
) > height
) {
931 page_breaks
= g_list_prepend(page_breaks
, GINT_TO_POINTER(ii
));
935 if (has_headers
&& ii
== num_header_lines
) {
937 pango_layout_iter_get_line_yrange(iter
,&y0
,&y1
);
938 print_data
->ypos_line
= (double)y0
+ 1./3.*((double)(y1
- y0
))/2.;
941 page_height
+= line_height
;
943 } while(ii
< num_lines
&& pango_layout_iter_next_line(iter
));
944 pango_layout_iter_free(iter
);
946 page_breaks
= g_list_reverse(page_breaks
);
947 print_data
->npages
= g_list_length(page_breaks
) + 1;
948 print_data
->page_breaks
= page_breaks
;
950 gtk_print_operation_set_n_pages(op
, print_data
->npages
);
952 debug_print("Starting print job...\n");
955 static cairo_surface_t
*pixbuf_to_surface(GdkPixbuf
*pixbuf
)
957 cairo_surface_t
*surface
;
958 cairo_format_t format
;
959 static const cairo_user_data_key_t key
;
960 guchar
*pixels
= g_malloc(
962 gdk_pixbuf_get_width(pixbuf
)*
963 gdk_pixbuf_get_height(pixbuf
));
964 guchar
*src_pixels
= gdk_pixbuf_get_pixels (pixbuf
);
965 gint width
= gdk_pixbuf_get_width(pixbuf
);
966 gint height
= gdk_pixbuf_get_height(pixbuf
);
967 gint nchans
= gdk_pixbuf_get_n_channels (pixbuf
);
968 gint stride
= gdk_pixbuf_get_rowstride (pixbuf
);
972 format
= CAIRO_FORMAT_RGB24
;
974 format
= CAIRO_FORMAT_ARGB32
;
975 surface
= cairo_image_surface_create_for_data (pixels
,
976 format
, width
, height
, 4*width
);
977 cairo_surface_set_user_data (surface
, &key
,
978 pixels
, (cairo_destroy_func_t
)g_free
);
980 for (j
= height
; j
; j
--) {
981 guchar
*p
= src_pixels
;
985 guchar
*end
= p
+ 3 * width
;
988 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1001 guchar
*end
= p
+ 4 * width
;
1004 #define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END
1007 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1008 MULT(q
[0], p
[2], p
[3], t1
);
1009 MULT(q
[1], p
[1], p
[3], t2
);
1010 MULT(q
[2], p
[0], p
[3], t3
);
1014 MULT(q
[1], p
[0], p
[3], t1
);
1015 MULT(q
[2], p
[1], p
[3], t2
);
1016 MULT(q
[3], p
[2], p
[3], t3
);
1026 src_pixels
+= stride
;
1027 pixels
+= 4 * width
;
1033 static void printing_textview_cb_draw_page(GtkPrintOperation
*op
, GtkPrintContext
*context
,
1034 int page_nr
, gpointer user_data
)
1037 PrintData
*print_data
;
1040 PangoLayoutIter
*iter
;
1042 gboolean notlast
= TRUE
;
1044 print_data
= (PrintData
*) user_data
;
1049 pagebreak
= g_list_nth(print_data
->page_breaks
, page_nr
- 1);
1050 start
= GPOINTER_TO_INT(pagebreak
->data
);
1053 pagebreak
= g_list_nth(print_data
->page_breaks
, page_nr
);
1054 if (pagebreak
== NULL
)
1055 end
= pango_layout_get_line_count(print_data
->layout
);
1057 end
= GPOINTER_TO_INT(pagebreak
->data
);
1059 cr
= gtk_print_context_get_cairo_context(context
);
1060 cairo_scale(cr
, print_data
->zoom
, print_data
->zoom
);
1061 cairo_set_source_rgb(cr
, 0., 0., 0.);
1065 iter
= pango_layout_get_iter(print_data
->layout
);
1067 PangoRectangle logical_rect
;
1068 PangoLayoutLine
*line
;
1069 PangoAttrShape
*attr
= NULL
;
1073 line
= pango_layout_iter_get_line(iter
);
1075 pango_layout_iter_get_line_extents(iter
, NULL
, &logical_rect
);
1076 baseline
= pango_layout_iter_get_baseline(iter
);
1079 start_pos
= ((double)logical_rect
.y
) / PANGO_SCALE
;
1081 /* Draw header separator line */
1082 if (ii
== 0 && print_data
->ypos_line
>= 0) {
1083 cairo_surface_t
*surface
;
1084 surface
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32
,
1085 gtk_print_context_get_width(context
)/print_data
->zoom
,
1086 gtk_print_context_get_height(context
)/print_data
->zoom
);
1087 cairo_set_line_width(cr
, .5);
1088 cairo_set_source_surface(cr
, surface
,
1089 ((double)logical_rect
.x
) / PANGO_SCALE
,
1090 ((double)baseline
) / PANGO_SCALE
- start_pos
);
1091 cairo_move_to(cr
, ((double)logical_rect
.x
) / PANGO_SCALE
,
1092 (double)print_data
->ypos_line
/ PANGO_SCALE
);
1093 cairo_rel_line_to(cr
, gtk_print_context_get_width(context
)/print_data
->zoom
, 0);
1094 cairo_set_source_rgb(cr
, 0., 0., 0.);
1096 cairo_surface_destroy(surface
);
1100 ((double)logical_rect
.x
) / PANGO_SCALE
,
1101 ((double)baseline
) / PANGO_SCALE
- start_pos
);
1103 if ((attr
= g_hash_table_lookup(print_data
->images
,
1104 GINT_TO_POINTER(pango_layout_iter_get_index(iter
)))) != NULL
) {
1105 cairo_surface_t
*surface
;
1107 surface
= pixbuf_to_surface(GDK_PIXBUF(attr
->data
));
1108 cairo_set_source_surface (cr
, surface
,
1109 ((double)logical_rect
.x
) / PANGO_SCALE
,
1110 ((double)baseline
) / PANGO_SCALE
- start_pos
);
1112 cairo_surface_destroy (surface
);
1114 pango_cairo_show_layout_line(cr
, line
);
1118 } while(ii
< end
&& (notlast
= pango_layout_iter_next_line(iter
)));
1120 if (print_data
->avatar
&& page_nr
== 0) {
1121 cairo_surface_t
*surface
;
1122 GdkPixbuf
*pixbuf
= gtk_image_get_pixbuf(print_data
->avatar
);
1123 gdouble startx
, starty
;
1125 if (pixbuf
!= NULL
) {
1126 startx
= gtk_print_context_get_width(context
)/print_data
->zoom
;
1128 startx
-= ((double)gdk_pixbuf_get_width(pixbuf
));
1132 surface
= pixbuf_to_surface(pixbuf
);
1133 cairo_set_source_surface (cr
, surface
, startx
, starty
);
1135 cairo_surface_destroy (surface
);
1139 pango_layout_iter_free(iter
);
1140 debug_print("Sent page %d to printer\n", page_nr
+1);
1143 static void printing_layout_set_text_attributes(PrintData
*print_data
,
1144 GtkPrintContext
*context
,
1145 gboolean
*has_headers
)
1148 PangoAttrList
*attr_list
;
1149 PangoAttribute
*attr
;
1150 GSList
*open_attrs
, *attr_walk
;
1151 GtkTextView
*text_view
= GTK_TEXT_VIEW(print_data
->renderer_data
);
1152 GtkTextBuffer
*buffer
= gtk_text_view_get_buffer(text_view
);
1154 *has_headers
= FALSE
;
1156 attr_list
= pango_attr_list_new();
1157 if (print_data
->sel_start
< 0 || print_data
->sel_end
<= print_data
->sel_start
) {
1158 gtk_text_buffer_get_start_iter(buffer
, &iter
);
1160 gtk_text_buffer_get_iter_at_offset(buffer
, &iter
, print_data
->sel_start
);
1165 gboolean fg_set
, bg_set
, under_set
, strike_set
, weight_set
;
1166 GSList
*tags
, *tag_walk
;
1168 GdkColor
*color
= NULL
;
1169 PangoUnderline underline
;
1170 gboolean strikethrough
;
1174 if (prefs_common
.print_imgs
&& (image
= gtk_text_iter_get_pixbuf(&iter
)) != NULL
) {
1175 PangoRectangle rect
= {0, 0, 0, 0};
1176 gint startpos
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1177 gint h
= gdk_pixbuf_get_height(image
);
1178 gint w
= gdk_pixbuf_get_width(image
);
1179 gint a_h
= gtk_print_context_get_height(context
);
1180 gint a_w
= gtk_print_context_get_width(context
);
1182 GdkPixbuf
*scaled
= NULL
;
1183 image_viewer_get_resized_size(w
, h
, a_w
, a_h
, &r_w
, &r_h
);
1186 rect
.width
= r_w
* PANGO_SCALE
;
1187 rect
.height
= r_h
* PANGO_SCALE
;
1189 scaled
= gdk_pixbuf_scale_simple(image
, r_w
, r_h
, GDK_INTERP_BILINEAR
);
1190 attr
= pango_attr_shape_new_with_data (&rect
, &rect
,
1191 scaled
, NULL
, NULL
);
1192 attr
->start_index
= startpos
;
1193 attr
->end_index
= startpos
+1;
1194 pango_attr_list_insert(attr_list
, attr
);
1195 g_hash_table_insert(print_data
->images
, GINT_TO_POINTER(startpos
), attr
);
1196 print_data
->img_cnt
++;
1199 if (gtk_text_iter_ends_tag(&iter
, NULL
)) {
1200 PangoAttrColor
*attr_color
;
1201 PangoAttrInt
*attr_int
;
1203 tags
= gtk_text_iter_get_toggled_tags(&iter
, FALSE
);
1204 for (tag_walk
= tags
; tag_walk
!= NULL
; tag_walk
= tag_walk
->next
) {
1207 tag
= GTK_TEXT_TAG(tag_walk
->data
);
1208 g_object_get(G_OBJECT(tag
),
1209 "background-set", &bg_set
,
1210 "foreground-set", &fg_set
,
1211 "underline-set",&under_set
,
1212 "strikethrough-set", &strike_set
,
1213 "weight-set", &weight_set
,
1218 for (attr_walk
= open_attrs
; attr_walk
!= NULL
;
1219 attr_walk
= attr_walk
->next
) {
1220 attr
= (PangoAttribute
*)attr_walk
->data
;
1221 if (attr
->klass
->type
== PANGO_ATTR_FOREGROUND
) {
1222 attr_color
= (PangoAttrColor
*) attr
;
1223 g_object_get(G_OBJECT(tag
), "foreground_gdk",
1226 printing_is_pango_gdk_color_equal(&(attr_color
->color
),
1228 attr
->end_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1229 pango_attr_list_insert(attr_list
, attr
);
1231 open_attrs
= g_slist_delete_link(open_attrs
, attr_walk
);
1235 gdk_color_free(color
);
1239 debug_print("Error generating attribute list.\n");
1244 for (attr_walk
= open_attrs
; attr_walk
!= NULL
;
1245 attr_walk
= attr_walk
->next
) {
1246 attr
= (PangoAttribute
*)attr_walk
->data
;
1247 if (attr
->klass
->type
== PANGO_ATTR_BACKGROUND
) {
1248 attr_color
= (PangoAttrColor
*) attr
;
1249 g_object_get(G_OBJECT(tag
), "background-gdk",
1252 printing_is_pango_gdk_color_equal(&(attr_color
->color
),
1254 attr
->end_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1255 pango_attr_list_insert(attr_list
, attr
);
1257 open_attrs
= g_slist_delete_link(open_attrs
, attr_walk
);
1261 gdk_color_free(color
);
1265 debug_print("Error generating attribute list.\n");
1270 for (attr_walk
= open_attrs
; attr_walk
!= NULL
;
1271 attr_walk
= attr_walk
->next
) {
1272 attr
= (PangoAttribute
*)attr_walk
->data
;
1273 if (attr
->klass
->type
== PANGO_ATTR_UNDERLINE
) {
1274 attr_int
= (PangoAttrInt
*)attr
;
1275 g_object_get(G_OBJECT(tag
), "underline",
1277 if (attr_int
->value
== underline
) {
1278 attr
->end_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1279 pango_attr_list_insert(attr_list
, attr
);
1281 open_attrs
= g_slist_delete_link(open_attrs
, attr_walk
);
1287 debug_print("Error generating attribute list.\n");
1292 for (attr_walk
= open_attrs
; attr_walk
!= NULL
;
1293 attr_walk
= attr_walk
->next
) {
1294 attr
= (PangoAttribute
*)attr_walk
->data
;
1295 if (attr
->klass
->type
== PANGO_ATTR_STRIKETHROUGH
) {
1296 attr_int
= (PangoAttrInt
*)attr
;
1297 g_object_get(G_OBJECT(tag
), "strikethrough",
1298 &strikethrough
, NULL
);
1299 if (attr_int
->value
== strikethrough
) {
1300 attr
->end_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1301 pango_attr_list_insert(attr_list
, attr
);
1303 open_attrs
= g_slist_delete_link(open_attrs
, attr_walk
);
1309 debug_print("Error generating attribute list.\n");
1314 for (attr_walk
= open_attrs
; attr_walk
!= NULL
;
1315 attr_walk
= attr_walk
->next
) {
1316 attr
= (PangoAttribute
*)attr_walk
->data
;
1317 if (attr
->klass
->type
== PANGO_ATTR_WEIGHT
) {
1318 attr_int
= (PangoAttrInt
*)attr
;
1319 g_object_get(G_OBJECT(tag
), "weight", &weight
, NULL
);
1320 if (attr_int
->value
== weight
) {
1321 attr
->end_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1322 pango_attr_list_insert(attr_list
, attr
);
1324 open_attrs
= g_slist_delete_link(open_attrs
, attr_walk
);
1330 debug_print("Error generating attribute list.\n");
1336 if (gtk_text_iter_begins_tag(&iter
, NULL
)) {
1337 tags
= gtk_text_iter_get_toggled_tags(&iter
, TRUE
);
1338 /* Sometimes, an iter has several weights. Use only the first in this case */
1339 gboolean weight_set_for_this_iter
;
1340 weight_set_for_this_iter
= FALSE
;
1341 for (tag_walk
= tags
; tag_walk
!= NULL
; tag_walk
= tag_walk
->next
) {
1342 tag
= GTK_TEXT_TAG(tag_walk
->data
);
1343 g_object_get(G_OBJECT(tag
),
1344 "background-set", &bg_set
,
1345 "foreground-set", &fg_set
,
1346 "underline-set", &under_set
,
1347 "strikethrough-set", &strike_set
,
1348 "weight-set", &weight_set
,
1351 g_object_get(G_OBJECT(tag
), "foreground-gdk", &color
, NULL
);
1352 attr
= pango_attr_foreground_new(color
->red
,color
->green
,color
->blue
);
1353 attr
->start_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1354 open_attrs
= g_slist_prepend(open_attrs
, attr
);
1357 g_object_get(G_OBJECT(tag
), "background-gdk", &color
, NULL
);
1358 attr
= pango_attr_background_new(color
->red
,color
->green
,color
->blue
);
1359 attr
->start_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1360 open_attrs
= g_slist_prepend(open_attrs
, attr
);
1363 g_object_get(G_OBJECT(tag
), "underline", &underline
, NULL
);
1364 attr
= pango_attr_underline_new(underline
);
1365 attr
->start_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1366 open_attrs
= g_slist_prepend(open_attrs
, attr
);
1369 g_object_get(G_OBJECT(tag
), "strikethrough", &strikethrough
, NULL
);
1370 attr
= pango_attr_strikethrough_new(strikethrough
);
1371 attr
->start_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1372 open_attrs
= g_slist_prepend(open_attrs
, attr
);
1374 if (weight_set
&& !weight_set_for_this_iter
) {
1375 weight_set_for_this_iter
= TRUE
;
1376 g_object_get(G_OBJECT(tag
), "weight", &weight
, NULL
);
1377 attr
= pango_attr_weight_new(weight
);
1378 attr
->start_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1379 open_attrs
= g_slist_prepend(open_attrs
, attr
);
1380 /* Hack to see if the first char is bold -- indicates header */
1381 if (attr
->start_index
== 0 && weight
== PANGO_WEIGHT_BOLD
) {
1382 *has_headers
= TRUE
;
1389 } while(!gtk_text_iter_is_end(&iter
) && gtk_text_iter_forward_to_tag_toggle(&iter
, NULL
));
1391 /* close all open attributes */
1392 for (attr_walk
= open_attrs
; attr_walk
!= NULL
; attr_walk
= attr_walk
->next
) {
1393 attr
= (PangoAttribute
*) attr_walk
->data
;
1394 attr
->end_index
= printing_text_iter_get_offset_bytes(print_data
, &iter
);
1395 pango_attr_list_insert(attr_list
, attr
);
1397 g_slist_free(open_attrs
);
1399 pango_layout_set_attributes(print_data
->layout
, attr_list
);
1400 pango_attr_list_unref(attr_list
);
1403 static gboolean
printing_is_pango_gdk_color_equal(PangoColor
*p
, GdkColor
*g
)
1405 return ((p
->red
== g
->red
) && (p
->green
== g
->green
) && (p
->blue
== g
->blue
));
1408 /* Pango has it's attribute in bytes, but GtkTextIter gets only an offset
1409 * in characters, so here we're returning an offset in bytes.
1411 static gint
printing_text_iter_get_offset_bytes(PrintData
*print_data
, const GtkTextIter
*iter
)
1417 if (print_data
->sel_start
< 0 || print_data
->sel_end
<= print_data
->sel_start
) {
1418 gtk_text_buffer_get_start_iter(gtk_text_iter_get_buffer(iter
), &start
);
1420 gtk_text_buffer_get_iter_at_offset(gtk_text_iter_get_buffer(iter
), &start
, print_data
->sel_start
);
1422 text
= gtk_text_iter_get_text(&start
, iter
);
1423 off_bytes
= strlen(text
);
1428 static void printing_preview_update_zoom_sensitivity(PreviewData
*preview_data
)
1430 if((preview_data
->print_data
->zoom
* PREVIEW_ZOOM_FAC
) > PREVIEW_ZOOM_MAX
)
1431 gtk_widget_set_sensitive(preview_data
->zoom_in
, FALSE
);
1433 gtk_widget_set_sensitive(preview_data
->zoom_in
, TRUE
);
1435 if ((preview_data
->print_data
->zoom
/ PREVIEW_ZOOM_FAC
) < PREVIEW_ZOOM_MIN
)
1436 gtk_widget_set_sensitive(preview_data
->zoom_out
, FALSE
);
1438 gtk_widget_set_sensitive(preview_data
->zoom_out
, TRUE
);