1 | /* Printing/Printing |
2 | * |
3 | * GtkPrintOperation offers a simple API to support printing |
4 | * in a cross-platform way. |
5 | */ |
6 | |
7 | #include <math.h> |
8 | #include <gtk/gtk.h> |
9 | |
10 | /* In points */ |
11 | #define (10*72/25.4) |
12 | #define (3*72/25.4) |
13 | |
14 | typedef struct |
15 | { |
16 | char *resourcename; |
17 | double font_size; |
18 | |
19 | int lines_per_page; |
20 | char **lines; |
21 | int num_lines; |
22 | int num_pages; |
23 | } PrintData; |
24 | |
25 | static void |
26 | begin_print (GtkPrintOperation *operation, |
27 | GtkPrintContext *context, |
28 | gpointer user_data) |
29 | { |
30 | PrintData *data = (PrintData *)user_data; |
31 | GBytes *bytes; |
32 | int i; |
33 | double height; |
34 | |
35 | height = gtk_print_context_get_height (context) - HEADER_HEIGHT - HEADER_GAP; |
36 | |
37 | data->lines_per_page = floor (x: height / data->font_size); |
38 | |
39 | bytes = g_resources_lookup_data (path: data->resourcename, lookup_flags: 0, NULL); |
40 | |
41 | data->lines = g_strsplit (string: g_bytes_get_data (bytes, NULL), delimiter: "\n" , max_tokens: 0); |
42 | g_bytes_unref (bytes); |
43 | |
44 | i = 0; |
45 | while (data->lines[i] != NULL) |
46 | i++; |
47 | |
48 | data->num_lines = i; |
49 | data->num_pages = (data->num_lines - 1) / data->lines_per_page + 1; |
50 | |
51 | gtk_print_operation_set_n_pages (op: operation, n_pages: data->num_pages); |
52 | } |
53 | |
54 | static void |
55 | draw_page (GtkPrintOperation *operation, |
56 | GtkPrintContext *context, |
57 | int page_nr, |
58 | gpointer user_data) |
59 | { |
60 | PrintData *data = (PrintData *)user_data; |
61 | cairo_t *cr; |
62 | PangoLayout *layout; |
63 | int text_width, text_height; |
64 | double width; |
65 | int line, i; |
66 | PangoFontDescription *desc; |
67 | char *page_str; |
68 | |
69 | cr = gtk_print_context_get_cairo_context (context); |
70 | width = gtk_print_context_get_width (context); |
71 | |
72 | cairo_rectangle (cr, x: 0, y: 0, width, HEADER_HEIGHT); |
73 | |
74 | cairo_set_source_rgb (cr, red: 0.8, green: 0.8, blue: 0.8); |
75 | cairo_fill_preserve (cr); |
76 | |
77 | cairo_set_source_rgb (cr, red: 0, green: 0, blue: 0); |
78 | cairo_set_line_width (cr, width: 1); |
79 | cairo_stroke (cr); |
80 | |
81 | layout = gtk_print_context_create_pango_layout (context); |
82 | |
83 | desc = pango_font_description_from_string (str: "sans 14" ); |
84 | pango_layout_set_font_description (layout, desc); |
85 | pango_font_description_free (desc); |
86 | |
87 | pango_layout_set_text (layout, text: data->resourcename, length: -1); |
88 | pango_layout_get_pixel_size (layout, width: &text_width, height: &text_height); |
89 | |
90 | if (text_width > width) |
91 | { |
92 | pango_layout_set_width (layout, width); |
93 | pango_layout_set_ellipsize (layout, ellipsize: PANGO_ELLIPSIZE_START); |
94 | pango_layout_get_pixel_size (layout, width: &text_width, height: &text_height); |
95 | } |
96 | |
97 | cairo_move_to (cr, x: (width - text_width) / 2, y: (HEADER_HEIGHT - text_height) / 2); |
98 | pango_cairo_show_layout (cr, layout); |
99 | |
100 | page_str = g_strdup_printf (format: "%d/%d" , page_nr + 1, data->num_pages); |
101 | pango_layout_set_text (layout, text: page_str, length: -1); |
102 | g_free (mem: page_str); |
103 | |
104 | pango_layout_set_width (layout, width: -1); |
105 | pango_layout_get_pixel_size (layout, width: &text_width, height: &text_height); |
106 | cairo_move_to (cr, x: width - text_width - 4, y: (HEADER_HEIGHT - text_height) / 2); |
107 | pango_cairo_show_layout (cr, layout); |
108 | |
109 | g_object_unref (object: layout); |
110 | |
111 | layout = gtk_print_context_create_pango_layout (context); |
112 | |
113 | desc = pango_font_description_from_string (str: "monospace" ); |
114 | pango_font_description_set_size (desc, size: data->font_size * PANGO_SCALE); |
115 | pango_layout_set_font_description (layout, desc); |
116 | pango_font_description_free (desc); |
117 | |
118 | cairo_move_to (cr, x: 0, HEADER_HEIGHT + HEADER_GAP); |
119 | line = page_nr * data->lines_per_page; |
120 | for (i = 0; i < data->lines_per_page && line < data->num_lines; i++) |
121 | { |
122 | pango_layout_set_text (layout, text: data->lines[line], length: -1); |
123 | pango_cairo_show_layout (cr, layout); |
124 | cairo_rel_move_to (cr, dx: 0, dy: data->font_size); |
125 | line++; |
126 | } |
127 | |
128 | g_object_unref (object: layout); |
129 | } |
130 | |
131 | static void |
132 | end_print (GtkPrintOperation *operation, |
133 | GtkPrintContext *context, |
134 | gpointer user_data) |
135 | { |
136 | PrintData *data = (PrintData *)user_data; |
137 | |
138 | g_free (mem: data->resourcename); |
139 | g_strfreev (str_array: data->lines); |
140 | g_free (mem: data); |
141 | } |
142 | |
143 | |
144 | GtkWidget * |
145 | do_printing (GtkWidget *do_widget) |
146 | { |
147 | GtkPrintOperation *operation; |
148 | GtkPrintSettings *settings; |
149 | PrintData *data; |
150 | GError *error = NULL; |
151 | |
152 | operation = gtk_print_operation_new (); |
153 | data = g_new0 (PrintData, 1); |
154 | data->resourcename = g_strdup (str: "/sources/printing.c" ); |
155 | data->font_size = 12.0; |
156 | |
157 | g_signal_connect (G_OBJECT (operation), "begin-print" , |
158 | G_CALLBACK (begin_print), data); |
159 | g_signal_connect (G_OBJECT (operation), "draw-page" , |
160 | G_CALLBACK (draw_page), data); |
161 | g_signal_connect (G_OBJECT (operation), "end-print" , |
162 | G_CALLBACK (end_print), data); |
163 | |
164 | gtk_print_operation_set_use_full_page (op: operation, FALSE); |
165 | gtk_print_operation_set_unit (op: operation, unit: GTK_UNIT_POINTS); |
166 | gtk_print_operation_set_embed_page_setup (op: operation, TRUE); |
167 | |
168 | settings = gtk_print_settings_new (); |
169 | |
170 | gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_OUTPUT_BASENAME, value: "gtk-demo" ); |
171 | gtk_print_operation_set_print_settings (op: operation, print_settings: settings); |
172 | |
173 | gtk_print_operation_run (op: operation, action: GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, GTK_WINDOW (do_widget), error: &error); |
174 | |
175 | g_object_unref (object: operation); |
176 | g_object_unref (object: settings); |
177 | |
178 | if (error) |
179 | { |
180 | GtkWidget *dialog; |
181 | |
182 | dialog = gtk_message_dialog_new (GTK_WINDOW (do_widget), |
183 | flags: GTK_DIALOG_DESTROY_WITH_PARENT, |
184 | type: GTK_MESSAGE_ERROR, |
185 | buttons: GTK_BUTTONS_CLOSE, |
186 | message_format: "%s" , error->message); |
187 | g_error_free (error); |
188 | |
189 | g_signal_connect (dialog, "response" , |
190 | G_CALLBACK (gtk_window_destroy), NULL); |
191 | |
192 | gtk_widget_show (widget: dialog); |
193 | } |
194 | |
195 | |
196 | return NULL; |
197 | } |
198 | |