1 /*
2 * This file is part of YAD.
3 *
4 * YAD is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * YAD is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with YAD. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Copyright (C) 2008-2019, Victor Ananjevsky <ananasik@gmail.com>
18 */
19
20 #include <sys/types.h>
21 #include <unistd.h>
22
23 #include <gtk/gtkunixprint.h>
24
25 #include "yad.h"
26
27 #define HEADER_HEIGHT (10*72/25.4)
28 #define HEADER_GAP (3*72/25.4)
29 #define HEADER_FONT "Sans 11"
30
31 #define FONTNAME "Monospace"
32 #define FONTSIZE 11.0
33
34 static gchar **text;
35 static gint nlines, npages;
36
37 static PangoFontDescription *fdesc = NULL;
38
39 static void
draw_header(GtkPrintContext * cnt,gint pn,gint pc)40 draw_header (GtkPrintContext * cnt, gint pn, gint pc)
41 {
42 cairo_t *cr;
43 PangoFontDescription *desc;
44 PangoLayout *layout;
45 gint pw, tw, th;
46 gchar *page;
47
48 cr = gtk_print_context_get_cairo_context (cnt);
49 pw = gtk_print_context_get_width (cnt);
50
51 layout = gtk_print_context_create_pango_layout (cnt);
52
53 desc = pango_font_description_from_string (HEADER_FONT);
54 pango_layout_set_font_description (layout, desc);
55 pango_font_description_free (desc);
56
57 pango_layout_set_text (layout, options.common_data.uri, -1);
58 pango_layout_get_pixel_size (layout, &tw, &th);
59 if (tw > pw)
60 {
61 pango_layout_set_width (layout, pw);
62 pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_START);
63 pango_layout_get_pixel_size (layout, &tw, &th);
64 }
65
66 cairo_move_to (cr, (pw - tw) / 2, (HEADER_HEIGHT - th) / 2);
67 pango_cairo_show_layout (cr, layout);
68
69 page = g_strdup_printf ("%d/%d", pn, pc);
70 pango_layout_set_text (layout, page, -1);
71 g_free (page);
72
73 pango_layout_set_width (layout, -1);
74 pango_layout_get_pixel_size (layout, &tw, &th);
75 cairo_move_to (cr, pw - tw - 4, (HEADER_HEIGHT - th) / 2);
76 pango_cairo_show_layout (cr, layout);
77
78 g_object_unref (layout);
79
80 cairo_move_to (cr, 0.0, HEADER_HEIGHT);
81 cairo_line_to (cr, pw, HEADER_HEIGHT);
82
83 cairo_set_source_rgb (cr, 0, 0, 0);
84 cairo_set_line_width (cr, 1);
85 cairo_stroke (cr);
86 }
87
88 static void
begin_print_text(GtkPrintOperation * op,GtkPrintContext * cnt,gpointer data)89 begin_print_text (GtkPrintOperation * op, GtkPrintContext * cnt, gpointer data)
90 {
91 gchar *buf;
92 gint i = 0;
93 gdouble ph;
94
95 /* load file */
96 g_file_get_contents (options.common_data.uri, &buf, NULL, NULL);
97 text = g_strsplit (buf, "\n", 0);
98 g_free (buf);
99
100 while (text[i] != NULL)
101 i++;
102
103 ph = gtk_print_context_get_height (cnt);
104 if (options.print_data.headers)
105 ph -= HEADER_HEIGHT + HEADER_GAP;
106
107 nlines = ph / FONTSIZE;
108 npages = i / nlines + 1;
109 gtk_print_operation_set_n_pages (op, npages);
110
111 /* set font */
112 if (options.common_data.font)
113 fdesc = pango_font_description_from_string (options.common_data.font);
114 else
115 {
116 fdesc = pango_font_description_from_string (FONTNAME);
117 pango_font_description_set_size (fdesc, FONTSIZE * PANGO_SCALE);
118 }
119 }
120
121 static void
draw_page_text(GtkPrintOperation * op,GtkPrintContext * cnt,gint page,gpointer data)122 draw_page_text (GtkPrintOperation * op, GtkPrintContext * cnt, gint page, gpointer data)
123 {
124 cairo_t *cr;
125 PangoLayout *layout;
126 gint i, line;
127
128 cr = gtk_print_context_get_cairo_context (cnt);
129
130 /* create header */
131 if (options.print_data.headers)
132 draw_header (cnt, page + 1, npages);
133
134 /* add text */
135 layout = gtk_print_context_create_pango_layout (cnt);
136 pango_layout_set_font_description (layout, fdesc);
137
138 cairo_move_to (cr, 0, HEADER_HEIGHT + HEADER_GAP);
139
140 line = page * nlines;
141 for (i = 0; i < nlines; i++)
142 {
143 if (text[line + i] == NULL)
144 break;
145 pango_layout_set_text (layout, text[line + i], -1);
146 pango_cairo_show_layout (cr, layout);
147 cairo_rel_move_to (cr, 0, FONTSIZE);
148 }
149
150 g_object_unref (layout);
151 }
152
153 static void
draw_page_image(GtkPrintOperation * op,GtkPrintContext * cnt,gint page,gpointer data)154 draw_page_image (GtkPrintOperation * op, GtkPrintContext * cnt, gint page, gpointer data)
155 {
156 cairo_t *cr;
157 GdkPixbuf *pb, *spb;
158 guint iw, ih;
159 gdouble pw, ph;
160 gdouble factor;
161
162 cr = gtk_print_context_get_cairo_context (cnt);
163
164 pw = gtk_print_context_get_width (cnt);
165 ph = gtk_print_context_get_height (cnt);
166 if (options.print_data.headers)
167 ph -= HEADER_HEIGHT + HEADER_GAP;
168
169 /* create header */
170 if (options.print_data.headers)
171 draw_header (cnt, 1, 1);
172
173 /* scale image to page size */
174 pb = gdk_pixbuf_new_from_file (options.common_data.uri, NULL);
175 iw = gdk_pixbuf_get_width (pb);
176 ih = gdk_pixbuf_get_height (pb);
177
178 if (pw < iw || ph < ih)
179 {
180 factor = MIN (pw / iw, ph / ih);
181 factor = (factor > 1.0) ? 1.0 : factor;
182 spb = gdk_pixbuf_scale_simple (pb, iw * factor, ih * factor, GDK_INTERP_HYPER);
183 }
184 else
185 spb = g_object_ref (pb);
186 g_object_unref (pb);
187
188 /* add image to surface */
189 gdk_cairo_set_source_pixbuf (cr, spb, 0.0, HEADER_HEIGHT + HEADER_GAP);
190 cairo_paint (cr);
191 g_object_unref (spb);
192 }
193
194 static void
raw_print_done(GtkPrintJob * job,gint * ret,GError * err)195 raw_print_done (GtkPrintJob * job, gint * ret, GError * err)
196 {
197 if (err)
198 {
199 g_printerr (_("Printing failed: %s\n"), err->message);
200 *ret = 1;
201 }
202 yad_exit (options.data.def_resp);
203 }
204
205 static void
size_allocate_cb(GtkWidget * w,GtkAllocation * al,gpointer data)206 size_allocate_cb (GtkWidget * w, GtkAllocation * al, gpointer data)
207 {
208 gtk_widget_set_size_request (w, al->width, -1);
209 }
210
211 gint
yad_print_run(void)212 yad_print_run (void)
213 {
214 GtkWidget *dlg;
215 GtkWidget *box, *img, *lbl;
216 gchar *uri, *fn, *job_name = NULL;
217 GtkPrintCapabilities pcap;
218 GtkPrintOperationAction act = GTK_PRINT_OPERATION_ACTION_PRINT;
219 GtkPrintSettings *print_settings = NULL;
220 GtkPageSetup *page_setup = NULL;
221 gint resp, ret = 0;
222 GError *err = NULL;
223
224 /* check if file is exists */
225 if (options.common_data.uri && options.common_data.uri[0])
226 {
227 if (!g_file_test (options.common_data.uri, G_FILE_TEST_EXISTS))
228 {
229 g_printerr (_("File %s not found.\n"), options.common_data.uri);
230 return 1;
231 }
232 }
233 else
234 {
235 g_printerr (_("Filename is not specified.\n"));
236 return 1;
237 }
238
239 /* load previously saved print settings */
240 fn = g_build_filename (g_get_user_config_dir (), "yad", "print.conf", NULL);
241 if (g_file_test (fn, G_FILE_TEST_EXISTS))
242 {
243 print_settings = gtk_print_settings_new_from_file (fn, NULL);
244 page_setup = gtk_page_setup_new_from_file (fn, NULL);
245 }
246 g_free (fn);
247
248 if (!print_settings)
249 print_settings = gtk_print_settings_new ();
250 if (!page_setup)
251 page_setup = gtk_page_setup_new ();
252
253 /* create print dialog */
254 dlg = gtk_print_unix_dialog_new (options.data.dialog_title, NULL);
255 gtk_window_set_type_hint (GTK_WINDOW (dlg), GDK_WINDOW_TYPE_HINT_NORMAL);
256 gtk_print_unix_dialog_set_embed_page_setup (GTK_PRINT_UNIX_DIALOG (dlg), TRUE);
257 pcap = GTK_PRINT_CAPABILITY_PAGE_SET | GTK_PRINT_CAPABILITY_COPIES |
258 GTK_PRINT_CAPABILITY_COLLATE | GTK_PRINT_CAPABILITY_REVERSE |
259 GTK_PRINT_CAPABILITY_NUMBER_UP | GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT;
260 if (options.common_data.preview && options.print_data.type != YAD_PRINT_RAW)
261 pcap |= GTK_PRINT_CAPABILITY_PREVIEW;
262 gtk_print_unix_dialog_set_manual_capabilities (GTK_PRINT_UNIX_DIALOG (dlg), pcap);
263
264 uri = g_build_filename (g_get_current_dir (), "yad.pdf", NULL);
265 gtk_print_settings_set (print_settings, "output-uri", g_filename_to_uri (uri, NULL, NULL));
266 g_free (uri);
267
268 gtk_print_unix_dialog_set_settings (GTK_PRINT_UNIX_DIALOG (dlg), print_settings);
269 gtk_print_unix_dialog_set_page_setup (GTK_PRINT_UNIX_DIALOG (dlg), page_setup);
270
271 /* set window behavior */
272 gtk_widget_set_name (dlg, "yad-dialog-window");
273 if (options.data.sticky)
274 gtk_window_stick (GTK_WINDOW (dlg));
275 gtk_window_set_resizable (GTK_WINDOW (dlg), !options.data.fixed);
276 gtk_window_set_keep_above (GTK_WINDOW (dlg), options.data.ontop);
277 gtk_window_set_decorated (GTK_WINDOW (dlg), !options.data.undecorated);
278 gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dlg), options.data.skip_taskbar);
279 gtk_window_set_skip_pager_hint (GTK_WINDOW (dlg), options.data.skip_taskbar);
280
281 /* set window size and position */
282 gtk_window_set_default_size (GTK_WINDOW (dlg), options.data.width, options.data.height);
283 if (options.data.center)
284 gtk_window_set_position (GTK_WINDOW (dlg), GTK_WIN_POS_CENTER);
285 else if (options.data.mouse)
286 gtk_window_set_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
287
288 /* create yad's top box */
289 if (options.data.dialog_text || options.data.dialog_image)
290 {
291 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
292
293 if (options.data.dialog_image)
294 {
295 GdkPixbuf *pb = NULL;
296
297 pb = get_pixbuf (options.data.dialog_image, YAD_BIG_ICON, FALSE);
298 img = gtk_image_new_from_pixbuf (pb);
299 if (pb)
300 g_object_unref (pb);
301
302 gtk_widget_set_name (img, "yad-dialog-image");
303 gtk_box_pack_start (GTK_BOX (box), img, FALSE, FALSE, 2);
304 }
305 if (options.data.dialog_text)
306 {
307 gchar *buf = g_strcompress (options.data.dialog_text);
308
309 lbl = gtk_label_new (NULL);
310 if (!options.data.no_markup)
311 gtk_label_set_markup (GTK_LABEL (lbl), buf);
312 else
313 gtk_label_set_text (GTK_LABEL (lbl), buf);
314 gtk_widget_set_name (lbl, "yad-dialog-label");
315 gtk_label_set_selectable (GTK_LABEL (lbl), options.data.selectable_labels);
316 gtk_label_set_xalign (GTK_LABEL (lbl), options.data.text_align);
317
318 if (options.data.geometry || options.data.width != -1)
319 gtk_label_set_line_wrap (GTK_LABEL (lbl), TRUE);
320 gtk_box_pack_start (GTK_BOX (box), lbl, TRUE, TRUE, 2);
321 g_signal_connect (G_OBJECT (lbl), "size-allocate", G_CALLBACK (size_allocate_cb), NULL);
322 g_free (buf);
323 }
324
325 /* add tob box to dialog */
326 gtk_widget_show_all (box);
327 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), box, TRUE, TRUE, 5);
328 gtk_box_reorder_child (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), box, 0);
329 }
330
331 do
332 {
333 resp = gtk_dialog_run (GTK_DIALOG (dlg));
334 switch (resp)
335 {
336 case GTK_RESPONSE_APPLY: /* ask for preview */
337 act = GTK_PRINT_OPERATION_ACTION_PREVIEW;
338 case GTK_RESPONSE_OK: /* run print */
339 print_settings = gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (dlg));
340 page_setup = gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (dlg));
341 job_name = g_strdup_printf ("yad-%s-%d", g_path_get_basename (options.common_data.uri), getpid ());
342 if (options.print_data.type != YAD_PRINT_RAW)
343 {
344 /* print text or image */
345 GtkPrintOperation *op = gtk_print_operation_new ();
346 gtk_print_operation_set_unit (op, GTK_UNIT_POINTS);
347 gtk_print_operation_set_print_settings (op, print_settings);
348 gtk_print_operation_set_default_page_setup (op, page_setup);
349 gtk_print_operation_set_job_name (op, job_name);
350
351 switch (options.print_data.type)
352 {
353 case YAD_PRINT_TEXT:
354 g_signal_connect (G_OBJECT (op), "begin-print", G_CALLBACK (begin_print_text), NULL);
355 g_signal_connect (G_OBJECT (op), "draw-page", G_CALLBACK (draw_page_text), NULL);
356 break;
357 case YAD_PRINT_IMAGE:
358 gtk_print_operation_set_n_pages (op, 1);
359 g_signal_connect (G_OBJECT (op), "draw-page", G_CALLBACK (draw_page_image), NULL);
360 break;
361 default:;
362 }
363
364 if (gtk_print_operation_run (op, act, NULL, &err) == GTK_PRINT_OPERATION_RESULT_ERROR)
365 {
366 g_printerr (_("Printing failed: %s\n"), err->message);
367 ret = 1;
368 }
369 }
370 else
371 {
372 /* print raw ps or pdf data */
373 GtkPrinter *prnt;
374 GtkPrintJob *job;
375
376 prnt = gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (dlg));
377
378 if (g_str_has_suffix (options.common_data.uri, ".ps"))
379 {
380 if (!gtk_printer_accepts_ps (prnt))
381 {
382 g_printerr (_("Printer doesn't support ps format.\n"));
383 ret = 1;
384 }
385 }
386 else if (g_str_has_suffix (options.common_data.uri, ".pdf"))
387 {
388 if (!gtk_printer_accepts_pdf (prnt))
389 {
390 g_printerr (_("Printer doesn't support pdf format.\n"));
391 ret = 1;
392 }
393 }
394 else
395 {
396 g_printerr (_("This file type is not supported for raw printing.\n"));
397 ret = 1;
398 }
399 if (ret == 1)
400 break;
401
402 job = gtk_print_job_new (job_name, prnt, print_settings, page_setup);
403 if (gtk_print_job_set_source_file (job, options.common_data.uri, &err))
404 {
405 gtk_print_job_send (job, (GtkPrintJobCompleteFunc) raw_print_done, &ret, NULL);
406 gtk_main ();
407 }
408 else
409 {
410 g_printerr (_("Load source file failed: %s\n"), err->message);
411 ret = 1;
412 }
413 }
414 break;
415 default:
416 ret = 1;
417 break;
418 }
419 }
420 while (resp == GTK_RESPONSE_APPLY);
421
422 gtk_widget_destroy (dlg);
423
424 /* save print settings */
425 fn = g_build_filename (g_get_user_config_dir (), "yad", NULL);
426 g_mkdir_with_parents (fn, 0700);
427 g_free (fn);
428
429 fn = g_build_filename (g_get_user_config_dir (), "yad", "print.conf", NULL);
430 gtk_print_settings_to_file (print_settings, fn, NULL);
431 gtk_page_setup_to_file (page_setup, fn, NULL);
432 g_free (fn);
433
434 return ret;
435 }
436