1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * This program 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  * This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include <string.h>
21 
22 #include <libgimp/gimp.h>
23 #include <libgimp/gimpui.h>
24 
25 #include "print.h"
26 #include "print-settings.h"
27 #include "print-page-layout.h"
28 #include "print-page-setup.h"
29 #include "print-draw-page.h"
30 
31 #include "libgimp/stdplugins-intl.h"
32 
33 
34 #define PLUG_IN_BINARY       "print"
35 #define PLUG_IN_ROLE         "gimp-print"
36 #define PRINT_PROC_NAME      "file-print-gtk"
37 
38 #ifndef EMBED_PAGE_SETUP
39 #define PAGE_SETUP_PROC_NAME "file-print-gtk-page-setup"
40 #define PRINT_TEMP_PROC_NAME "file-print-gtk-page-setup-notify-temp"
41 #endif
42 
43 G_DEFINE_QUARK (gimp-plugin-print-error-quark, gimp_plugin_print_error)
44 
45 static void        query (void);
46 static void        run   (const gchar       *name,
47                           gint               nparams,
48                           const GimpParam   *param,
49                           gint              *nreturn_vals,
50                           GimpParam        **return_vals);
51 
52 static GimpPDBStatusType  print_image       (gint32             image_ID,
53                                              gboolean           interactive,
54                                              GError           **error);
55 #ifndef EMBED_PAGE_SETUP
56 static GimpPDBStatusType  page_setup        (gint32             image_ID);
57 #endif
58 
59 static void        print_show_error         (const gchar       *message);
60 static void        print_operation_set_name (GtkPrintOperation *operation,
61                                              gint               image_ID);
62 
63 static void        begin_print              (GtkPrintOperation *operation,
64                                              GtkPrintContext   *context,
65                                              PrintData         *data);
66 static void        end_print                (GtkPrintOperation *operation,
67                                              GtkPrintContext   *context,
68                                              gint32            *layer_ID);
69 static void        draw_page                (GtkPrintOperation *print,
70                                              GtkPrintContext   *context,
71                                              gint               page_nr,
72                                              PrintData         *data);
73 
74 static GtkWidget * create_custom_widget     (GtkPrintOperation *operation,
75                                              PrintData         *data);
76 
77 #ifndef EMBED_PAGE_SETUP
78 static gchar     * print_temp_proc_name     (gint32             image_ID);
79 static gchar     * print_temp_proc_install  (gint32             image_ID);
80 
81 /*  Keep a reference to the current GtkPrintOperation
82  *  for access by the temporary procedure.
83  */
84 static GtkPrintOperation *print_operation = NULL;
85 #endif
86 
87 
88 const GimpPlugInInfo PLUG_IN_INFO =
89 {
90   NULL,  /* init_proc  */
91   NULL,  /* quit_proc  */
92   query, /* query_proc */
93   run,   /* run_proc   */
94 };
95 
MAIN()96 MAIN ()
97 
98 static void
99 query (void)
100 {
101   static const GimpParamDef print_args[] =
102   {
103     { GIMP_PDB_INT32,    "run-mode", "The run mode { RUN-INTERACTIVE (0) }" },
104     { GIMP_PDB_IMAGE,    "image",    "Image to print"                       }
105   };
106 
107   gimp_install_procedure (PRINT_PROC_NAME,
108                           N_("Print the image"),
109                           "Print the image using the GTK+ Print API.",
110                           "Bill Skaggs, Sven Neumann, Stefan Röllin",
111                           "Bill Skaggs <weskaggs@primate.ucdavis.edu>",
112                           "2006 - 2008",
113                           N_("_Print..."),
114                           "*",
115                           GIMP_PLUGIN,
116                           G_N_ELEMENTS (print_args), 0,
117                           print_args, NULL);
118 
119   gimp_plugin_menu_register (PRINT_PROC_NAME, "<Image>/File/Send");
120   gimp_plugin_icon_register (PRINT_PROC_NAME, GIMP_ICON_TYPE_ICON_NAME,
121                              (const guint8 *) GIMP_ICON_DOCUMENT_PRINT);
122 
123 #ifndef EMBED_PAGE_SETUP
124   gimp_install_procedure (PAGE_SETUP_PROC_NAME,
125                           N_("Adjust page size and orientation for printing"),
126                           "Adjust page size and orientation for printing the "
127                           "image using the GTK+ Print API.",
128                           "Bill Skaggs, Sven Neumann, Stefan Röllin",
129                           "Sven Neumann <sven@gimp.org>",
130                           "2008",
131                           N_("Page Set_up..."),
132                           "*",
133                           GIMP_PLUGIN,
134                           G_N_ELEMENTS (print_args), 0,
135                           print_args, NULL);
136 
137   gimp_plugin_menu_register (PAGE_SETUP_PROC_NAME, "<Image>/File/Send");
138   gimp_plugin_icon_register (PAGE_SETUP_PROC_NAME, GIMP_ICON_TYPE_ICON_NAME,
139                              (const guint8 *) GIMP_ICON_DOCUMENT_PAGE_SETUP);
140 #endif
141 }
142 
143 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)144 run (const gchar      *name,
145      gint              nparams,
146      const GimpParam  *param,
147      gint             *nreturn_vals,
148      GimpParam       **return_vals)
149 {
150   static GimpParam   values[2];
151   GimpRunMode        run_mode;
152   GimpPDBStatusType  status;
153   gint32             image_ID;
154   GError            *error = NULL;
155 
156   INIT_I18N ();
157   gegl_init (NULL, NULL);
158 
159   run_mode = param[0].data.d_int32;
160 
161   *nreturn_vals = 1;
162   *return_vals  = values;
163 
164   values[0].type          = GIMP_PDB_STATUS;
165   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
166 
167   image_ID = param[1].data.d_int32;
168 
169   if (strcmp (name, PRINT_PROC_NAME) == 0)
170     {
171       status = print_image (image_ID, run_mode == GIMP_RUN_INTERACTIVE, &error);
172 
173       if (error && run_mode == GIMP_RUN_INTERACTIVE)
174         {
175           print_show_error (error->message);
176         }
177     }
178 #ifndef EMBED_PAGE_SETUP
179   else if (strcmp (name, PAGE_SETUP_PROC_NAME) == 0)
180     {
181       if (run_mode == GIMP_RUN_INTERACTIVE)
182         {
183           status = page_setup (image_ID);
184         }
185       else
186         {
187           status = GIMP_PDB_CALLING_ERROR;
188         }
189     }
190 #endif
191   else
192     {
193       status = GIMP_PDB_CALLING_ERROR;
194     }
195 
196   if (status != GIMP_PDB_SUCCESS && error)
197     {
198       *nreturn_vals = 2;
199       values[1].type          = GIMP_PDB_STRING;
200       values[1].data.d_string = error->message;
201     }
202 
203   values[0].data.d_status = status;
204 }
205 
206 static GimpPDBStatusType
print_image(gint32 image_ID,gboolean interactive,GError ** error)207 print_image (gint32     image_ID,
208              gboolean   interactive,
209              GError   **error)
210 {
211   GtkPrintOperation       *operation;
212   GtkPrintOperationResult  result;
213   gint32                   layer;
214   PrintData                data;
215 #ifndef EMBED_PAGE_SETUP
216   gchar                   *temp_proc;
217 #endif
218 
219   /*  create a print layer from the projection  */
220   layer = gimp_layer_new_from_visible (image_ID, image_ID, PRINT_PROC_NAME);
221 
222   operation = gtk_print_operation_new ();
223 
224   gtk_print_operation_set_n_pages (operation, 1);
225   print_operation_set_name (operation, image_ID);
226 
227   print_page_setup_load (operation, image_ID);
228 
229   /* fill in the PrintData struct */
230   data.image_id        = image_ID;
231   data.drawable_id     = layer;
232   data.unit            = gimp_get_default_unit ();
233   data.image_unit      = gimp_image_get_unit (image_ID);
234   data.offset_x        = 0;
235   data.offset_y        = 0;
236   data.center          = CENTER_BOTH;
237   data.use_full_page   = FALSE;
238   data.draw_crop_marks = FALSE;
239   data.operation       = operation;
240 
241   gimp_image_get_resolution (image_ID, &data.xres, &data.yres);
242 
243   print_settings_load (&data);
244 
245   gtk_print_operation_set_unit (operation, GTK_UNIT_PIXEL);
246 
247   g_signal_connect (operation, "begin-print",
248                     G_CALLBACK (begin_print),
249                     &data);
250   g_signal_connect (operation, "draw-page",
251                     G_CALLBACK (draw_page),
252                     &data);
253   g_signal_connect (operation, "end-print",
254                     G_CALLBACK (end_print),
255                     &layer);
256 
257 #ifndef EMBED_PAGE_SETUP
258   print_operation = operation;
259   temp_proc = print_temp_proc_install (image_ID);
260   gimp_extension_enable ();
261 #endif
262 
263   if (interactive)
264     {
265       gimp_ui_init (PLUG_IN_BINARY, FALSE);
266 
267       g_signal_connect_swapped (operation, "end-print",
268                                 G_CALLBACK (print_settings_save),
269                                 &data);
270 
271       g_signal_connect (operation, "create-custom-widget",
272                         G_CALLBACK (create_custom_widget),
273                         &data);
274 
275       gtk_print_operation_set_custom_tab_label (operation, _("Image Settings"));
276 
277 #ifdef EMBED_PAGE_SETUP
278       gtk_print_operation_set_embed_page_setup (operation, TRUE);
279 #endif
280 
281       result = gtk_print_operation_run (operation,
282                                         GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
283                                         NULL, error);
284 
285       if (result == GTK_PRINT_OPERATION_RESULT_APPLY ||
286           result == GTK_PRINT_OPERATION_RESULT_IN_PROGRESS)
287         {
288           print_page_setup_save (operation, image_ID);
289         }
290     }
291   else
292     {
293       result = gtk_print_operation_run (operation,
294                                         GTK_PRINT_OPERATION_ACTION_PRINT,
295                                         NULL, error);
296     }
297 
298 #ifndef EMBED_PAGE_SETUP
299   gimp_uninstall_temp_proc (temp_proc);
300   g_free (temp_proc);
301   print_operation = NULL;
302 #endif
303 
304   g_object_unref (operation);
305 
306   if (gimp_item_is_valid (layer))
307     gimp_item_delete (layer);
308 
309   switch (result)
310     {
311     case GTK_PRINT_OPERATION_RESULT_APPLY:
312     case GTK_PRINT_OPERATION_RESULT_IN_PROGRESS:
313       return GIMP_PDB_SUCCESS;
314 
315     case GTK_PRINT_OPERATION_RESULT_CANCEL:
316       return GIMP_PDB_CANCEL;
317 
318     case GTK_PRINT_OPERATION_RESULT_ERROR:
319       return GIMP_PDB_EXECUTION_ERROR;
320     }
321 
322   return GIMP_PDB_EXECUTION_ERROR;
323 }
324 
325 #ifndef EMBED_PAGE_SETUP
326 static GimpPDBStatusType
page_setup(gint32 image_ID)327 page_setup (gint32 image_ID)
328 {
329   GtkPrintOperation  *operation;
330   GimpParam          *return_vals;
331   gchar              *name;
332   gint                n_return_vals;
333 
334   gimp_ui_init (PLUG_IN_BINARY, FALSE);
335 
336   operation = gtk_print_operation_new ();
337 
338   print_page_setup_load (operation, image_ID);
339   print_page_setup_dialog (operation);
340   print_page_setup_save (operation, image_ID);
341 
342   g_object_unref (operation);
343 
344   /* now notify a running print procedure about this change */
345   name = print_temp_proc_name (image_ID);
346 
347   /* we don't want the core to show an error message if the
348    * temporary procedure does not exist
349    */
350   gimp_plugin_set_pdb_error_handler (GIMP_PDB_ERROR_HANDLER_PLUGIN);
351 
352   return_vals = gimp_run_procedure (name,
353                                     &n_return_vals,
354                                     GIMP_PDB_IMAGE, image_ID,
355                                     GIMP_PDB_END);
356   gimp_destroy_params (return_vals, n_return_vals);
357 
358   g_free (name);
359 
360   return GIMP_PDB_SUCCESS;
361 }
362 #endif
363 
364 static void
print_show_error(const gchar * message)365 print_show_error (const gchar *message)
366 {
367   GtkWidget *dialog;
368 
369   dialog = gtk_message_dialog_new (NULL, 0,
370                                    GTK_MESSAGE_ERROR,
371                                    GTK_BUTTONS_OK,
372                                    "%s",
373                                    _("An error occurred while trying to print:"));
374 
375   gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
376                                             "%s", message);
377 
378   gtk_dialog_run (GTK_DIALOG (dialog));
379   gtk_widget_destroy (dialog);
380 }
381 
382 static void
print_operation_set_name(GtkPrintOperation * operation,gint image_ID)383 print_operation_set_name (GtkPrintOperation *operation,
384                           gint               image_ID)
385 {
386   gchar *name = gimp_image_get_name (image_ID);
387 
388   gtk_print_operation_set_job_name (operation, name);
389 
390   g_free (name);
391 }
392 
393 static void
begin_print(GtkPrintOperation * operation,GtkPrintContext * context,PrintData * data)394 begin_print (GtkPrintOperation *operation,
395              GtkPrintContext   *context,
396              PrintData         *data)
397 {
398   gtk_print_operation_set_use_full_page (operation, data->use_full_page);
399 
400   gimp_progress_init (_("Printing"));
401 }
402 
403 static void
end_print(GtkPrintOperation * operation,GtkPrintContext * context,gint32 * layer_ID)404 end_print (GtkPrintOperation *operation,
405            GtkPrintContext   *context,
406            gint32            *layer_ID)
407 {
408   /* we don't need the print layer any longer, delete it */
409   if (gimp_item_is_valid (*layer_ID))
410     {
411       gimp_item_delete (*layer_ID);
412       *layer_ID = -1;
413     }
414 
415   gimp_progress_end ();
416 
417   /* generate events to solve the problems described in bug #466928 */
418   g_timeout_add_seconds (1, (GSourceFunc) gtk_true, NULL);
419 }
420 
421 static void
draw_page(GtkPrintOperation * operation,GtkPrintContext * context,gint page_nr,PrintData * data)422 draw_page (GtkPrintOperation *operation,
423            GtkPrintContext   *context,
424            gint               page_nr,
425            PrintData         *data)
426 {
427   GError *error = NULL;
428 
429   if (print_draw_page (context, data, &error))
430     {
431       gimp_progress_update (1.0);
432     }
433   else
434     {
435       print_show_error (error->message);
436       g_error_free (error);
437     }
438 }
439 
440 
441 /*
442  * This callback creates a "custom" widget that gets inserted into the
443  * print operation dialog.
444  */
445 static GtkWidget *
create_custom_widget(GtkPrintOperation * operation,PrintData * data)446 create_custom_widget (GtkPrintOperation *operation,
447                       PrintData         *data)
448 {
449   return print_page_layout_gui (data, PRINT_PROC_NAME);
450 }
451 
452 #ifndef EMBED_PAGE_SETUP
453 static void
print_temp_proc_run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)454 print_temp_proc_run (const gchar      *name,
455                      gint              nparams,
456                      const GimpParam  *param,
457                      gint             *nreturn_vals,
458                      GimpParam       **return_vals)
459 {
460   static GimpParam  values[1];
461 
462   values[0].type          = GIMP_PDB_STATUS;
463   values[0].data.d_status = GIMP_PDB_SUCCESS;
464 
465   *nreturn_vals = 1;
466   *return_vals  = values;
467 
468   if (print_operation && nparams == 1)
469     print_page_setup_load (print_operation, param[0].data.d_int32);
470 }
471 
472 static gchar *
print_temp_proc_name(gint32 image_ID)473 print_temp_proc_name (gint32 image_ID)
474 {
475   return g_strdup_printf (PRINT_TEMP_PROC_NAME "-%d", image_ID);
476 }
477 
478 static gchar *
print_temp_proc_install(gint32 image_ID)479 print_temp_proc_install (gint32  image_ID)
480 {
481   static const GimpParamDef args[] =
482   {
483     { GIMP_PDB_IMAGE, "image", "Image to print" }
484   };
485 
486   gchar *name = print_temp_proc_name (image_ID);
487 
488   gimp_install_temp_proc (name,
489                           "DON'T USE THIS ONE",
490                           "Temporary procedure to notify the Print plug-in "
491                           "about changes to the Page Setup.",
492                          "Sven Neumann",
493                          "Sven Neumann",
494                          "2008",
495                           NULL,
496                           "",
497                           GIMP_TEMPORARY,
498                           G_N_ELEMENTS (args), 0, args, NULL,
499                           print_temp_proc_run);
500 
501   return name;
502 }
503 #endif
504