1 /* GtkPrintUnixDialog
2  * Copyright (C) 2006 John (J5) Palmieri  <johnp@redhat.com>
3  * Copyright (C) 2006 Alexander Larsson <alexl@redhat.com>
4  * Copyright © 2006, 2007 Christian Persch
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "config.h"
21 
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <stdio.h>
26 #include <math.h>
27 
28 #include "gtkprintunixdialog.h"
29 
30 #include "gtkcustompaperunixdialog.h"
31 #include "gtkprintbackendprivate.h"
32 #include "gtkprinterprivate.h"
33 #include "gtkprinteroptionwidget.h"
34 #include "gtkprintutils.h"
35 
36 #include "gtkspinbutton.h"
37 #include "gtkimage.h"
38 #include "gtknotebook.h"
39 #include "gtkscrolledwindow.h"
40 #include "gtktogglebutton.h"
41 #include "gtkdrawingarea.h"
42 #include "gtkbox.h"
43 #include "gtkgrid.h"
44 #include "gtkframe.h"
45 #include "gtklabel.h"
46 #include "gtkbuildable.h"
47 #include "gtkmessagedialog.h"
48 #include "gtkbutton.h"
49 #include "gtkintl.h"
50 #include "gtkprivate.h"
51 #include "gtktypebuiltins.h"
52 #include "gtkdialogprivate.h"
53 #include "gtkstylecontextprivate.h"
54 #include "gtkwidgetprivate.h"
55 
56 
57 /**
58  * GtkPrintUnixDialog:
59  *
60  * `GtkPrintUnixDialog` implements a print dialog for platforms
61  * which don’t provide a native print dialog, like Unix.
62  *
63  * ![An example GtkPrintUnixDialog](printdialog.png)
64  *
65  * It can be used very much like any other GTK dialog, at the cost of
66  * the portability offered by the high-level printing API with
67  * [class@Gtk.PrintOperation].
68  *
69  * In order to print something with `GtkPrintUnixDialog`, you need to
70  * use [method@Gtk.PrintUnixDialog.get_selected_printer] to obtain a
71  * [class@Gtk.Printer] object and use it to construct a [class@Gtk.PrintJob]
72  * using [ctor@Gtk.PrintJob.new].
73  *
74  * `GtkPrintUnixDialog` uses the following response values:
75  *
76  * - %GTK_RESPONSE_OK: for the “Print” button
77  * - %GTK_RESPONSE_APPLY: for the “Preview” button
78  * - %GTK_RESPONSE_CANCEL: for the “Cancel” button
79  *
80  * # GtkPrintUnixDialog as GtkBuildable
81  *
82  * The `GtkPrintUnixDialog` implementation of the `GtkBuildable` interface
83  * exposes its @notebook internal children with the name “notebook”.
84  *
85  * An example of a `GtkPrintUnixDialog` UI definition fragment:
86  *
87  * ```xml
88  * <object class="GtkPrintUnixDialog" id="dialog1">
89  *   <child internal-child="notebook">
90  *     <object class="GtkNotebook" id="notebook">
91  *       <child>
92  *         <object type="GtkNotebookPage">
93  *           <property name="tab_expand">False</property>
94  *           <property name="tab_fill">False</property>
95  *           <property name="tab">
96  *             <object class="GtkLabel" id="tablabel">
97  *               <property name="label">Tab label</property>
98  *             </object>
99  *           </property>
100  *           <property name="child">
101  *             <object class="GtkLabel" id="tabcontent">
102  *               <property name="label">Content on notebook tab</property>
103  *             </object>
104  *           </property>
105  *         </object>
106  *       </child>
107  *     </object>
108  *   </child>
109  * </object>
110  * ```
111  *
112  * # CSS nodes
113  *
114  * `GtkPrintUnixDialog` has a single CSS node with name window. The style classes
115  * dialog and print are added.
116  */
117 
118 
119 #define EXAMPLE_PAGE_AREA_SIZE 110
120 #define RULER_DISTANCE 7.5
121 #define RULER_RADIUS 2
122 
123 
124 static void     gtk_print_unix_dialog_constructed  (GObject            *object);
125 static void     gtk_print_unix_dialog_dispose      (GObject            *object);
126 static void     gtk_print_unix_dialog_finalize     (GObject            *object);
127 static void     gtk_print_unix_dialog_set_property (GObject            *object,
128                                                     guint               prop_id,
129                                                     const GValue       *value,
130                                                     GParamSpec         *pspec);
131 static void     gtk_print_unix_dialog_get_property (GObject            *object,
132                                                     guint               prop_id,
133                                                     GValue             *value,
134                                                     GParamSpec         *pspec);
135 static void     unschedule_idle_mark_conflicts     (GtkPrintUnixDialog *dialog);
136 static void     selected_printer_changed           (GtkPrintUnixDialog *dialog);
137 static void     clear_per_printer_ui               (GtkPrintUnixDialog *dialog);
138 static void     printer_added_cb                   (GListModel         *model,
139                                                     guint               position,
140                                                     guint               removed,
141                                                     guint               added,
142                                                     GtkPrintUnixDialog *dialog);
143 static void     printer_status_cb                  (GtkPrintBackend    *backend,
144                                                     GtkPrinter         *printer,
145                                                     GtkPrintUnixDialog *dialog);
146 static void     update_collate_icon                (GtkToggleButton    *toggle_button,
147                                                     GtkPrintUnixDialog *dialog);
148 static void     error_dialogs                      (GtkPrintUnixDialog *print_dialog,
149 						    int                 print_dialog_response_id,
150 						    gpointer            data);
151 static gboolean page_range_entry_focus_changed     (GtkWidget          *entry,
152                                                     GParamSpec         *pspec,
153                                                     GtkPrintUnixDialog *dialog);
154 static void     update_page_range_entry_sensitivity(GtkWidget          *button,
155 						    GtkPrintUnixDialog *dialog);
156 static void     update_print_at_entry_sensitivity  (GtkWidget          *button,
157 						    GtkPrintUnixDialog *dialog);
158 static void     update_print_at_option             (GtkPrintUnixDialog *dialog);
159 static void     update_dialog_from_capabilities    (GtkPrintUnixDialog *dialog);
160 static void     draw_collate                       (GtkDrawingArea     *da,
161 						    cairo_t            *cr,
162                                                     int                 width,
163                                                     int                 height,
164                                                     gpointer            data);
165 static gboolean is_printer_active                  (gpointer            item,
166                                                     gpointer            data);
167 static  int     default_printer_list_sort_func     (gconstpointer        a,
168                                                     gconstpointer        b,
169 						    gpointer             user_data);
170 static void     update_number_up_layout            (GtkPrintUnixDialog  *dialog);
171 static void     draw_page                          (GtkDrawingArea      *da,
172 						    cairo_t             *cr,
173                                                     int                  width,
174                                                     int                  height,
175                                                     gpointer             data);
176 
177 
178 static gboolean dialog_get_collate                 (GtkPrintUnixDialog *dialog);
179 static gboolean dialog_get_reverse                 (GtkPrintUnixDialog *dialog);
180 static int      dialog_get_n_copies                (GtkPrintUnixDialog *dialog);
181 
182 static gboolean set_active_printer                 (GtkPrintUnixDialog *dialog,
183                                                     const char         *printer_name);
184 static void redraw_page_layout_preview             (GtkPrintUnixDialog *dialog);
185 static GListModel *load_print_backends             (GtkPrintUnixDialog *dialog);
186 
187 /* GtkBuildable */
188 static void gtk_print_unix_dialog_buildable_init                    (GtkBuildableIface *iface);
189 static GObject *gtk_print_unix_dialog_buildable_get_internal_child  (GtkBuildable *buildable,
190                                                                      GtkBuilder   *builder,
191                                                                      const char   *childname);
192 
193 static const char common_paper_sizes[][16] = {
194   "na_letter",
195   "na_legal",
196   "iso_a4",
197   "iso_a5",
198   "roc_16k",
199   "iso_b5",
200   "jis_b5",
201   "na_number-10",
202   "iso_dl",
203   "jpn_chou3",
204   "na_ledger",
205   "iso_a3",
206 };
207 
208 /* Keep in line with liststore defined in gtkprintunixdialog.ui */
209 enum {
210   PAGE_SETUP_LIST_COL_PAGE_SETUP,
211   PAGE_SETUP_LIST_COL_IS_SEPARATOR,
212   PAGE_SETUP_LIST_N_COLS
213 };
214 
215 /* Keep in line with liststore defined in gtkprintunixdialog.ui */
216 enum {
217   PRINTER_LIST_COL_ICON,
218   PRINTER_LIST_COL_NAME,
219   PRINTER_LIST_COL_STATE,
220   PRINTER_LIST_COL_JOBS,
221   PRINTER_LIST_COL_LOCATION,
222   PRINTER_LIST_COL_PRINTER_OBJ,
223   PRINTER_LIST_N_COLS
224 };
225 
226 enum {
227   PROP_0,
228   PROP_PAGE_SETUP,
229   PROP_CURRENT_PAGE,
230   PROP_PRINT_SETTINGS,
231   PROP_SELECTED_PRINTER,
232   PROP_MANUAL_CAPABILITIES,
233   PROP_SUPPORT_SELECTION,
234   PROP_HAS_SELECTION,
235   PROP_EMBED_PAGE_SETUP
236 };
237 
238 typedef struct _GtkPrintUnixDialogClass    GtkPrintUnixDialogClass;
239 
240 struct _GtkPrintUnixDialog
241 {
242   GtkDialog parent_instance;
243 
244   GtkWidget *notebook;
245 
246   GtkWidget *printer_list;
247 
248   GtkPrintCapabilities manual_capabilities;
249   GtkPrintCapabilities printer_capabilities;
250 
251   GtkPageSetup *page_setup;
252   gboolean page_setup_set;
253   gboolean embed_page_setup;
254   GListStore *page_setup_list;
255   GListStore *custom_paper_list;
256   GListStore *manage_papers_list;
257 
258   gboolean support_selection;
259   gboolean has_selection;
260 
261   GtkWidget *all_pages_radio;
262   GtkWidget *current_page_radio;
263   GtkWidget *selection_radio;
264   GtkWidget *range_table;
265   GtkWidget *page_range_radio;
266   GtkWidget *page_range_entry;
267 
268   GtkWidget *copies_spin;
269   GtkWidget *collate_check;
270   GtkWidget *reverse_check;
271   GtkWidget *collate_image;
272   GtkWidget *page_layout_preview;
273   GtkWidget *scale_spin;
274   GtkWidget *page_set_combo;
275   GtkWidget *print_now_radio;
276   GtkWidget *print_at_radio;
277   GtkWidget *print_at_entry;
278   GtkWidget *print_hold_radio;
279   GtkWidget *paper_size_combo;
280   GtkWidget *orientation_combo;
281   gboolean internal_page_setup_change;
282   gboolean updating_print_at;
283   GtkPrinterOptionWidget *pages_per_sheet;
284   GtkPrinterOptionWidget *duplex;
285   GtkPrinterOptionWidget *paper_type;
286   GtkPrinterOptionWidget *paper_source;
287   GtkPrinterOptionWidget *output_tray;
288   GtkPrinterOptionWidget *job_prio;
289   GtkPrinterOptionWidget *billing_info;
290   GtkPrinterOptionWidget *cover_before;
291   GtkPrinterOptionWidget *cover_after;
292   GtkPrinterOptionWidget *number_up_layout;
293 
294   GtkWidget *conflicts_widget;
295 
296   GtkWidget *job_page;
297   GtkWidget *finishing_table;
298   GtkWidget *finishing_page;
299   GtkWidget *image_quality_table;
300   GtkWidget *image_quality_page;
301   GtkWidget *color_table;
302   GtkWidget *color_page;
303 
304   GtkWidget *advanced_vbox;
305   GtkWidget *advanced_page;
306 
307   GtkWidget *extension_point;
308 
309   /* These are set initially on selected printer (either default printer,
310    * printer taken from set settings, or user-selected), but when any
311    * setting is changed by the user it is cleared.
312    */
313   GtkPrintSettings *initial_settings;
314 
315   GtkPrinterOption *number_up_layout_n_option;
316   GtkPrinterOption *number_up_layout_2_option;
317 
318   /* This is the initial printer set by set_settings. We look for it in
319    * the added printers. We clear this whenever the user manually changes
320    * to another printer, when the user changes a setting or when we find
321    * this printer.
322    */
323   char *waiting_for_printer;
324   gboolean internal_printer_change;
325 
326   GList *print_backends;
327 
328   GtkPrinter *current_printer;
329   GtkPrinter *request_details_printer;
330   gulong request_details_tag;
331   GtkPrinterOptionSet *options;
332   gulong options_changed_handler;
333   gulong mark_conflicts_id;
334 
335   char *format_for_printer;
336 
337   int current_page;
338   GtkCssNode *collate_paper_node;
339   GtkCssNode *page_layout_paper_node;
340 };
341 
342 struct _GtkPrintUnixDialogClass
343 {
344   GtkDialogClass parent_class;
345 };
346 
347 G_DEFINE_TYPE_WITH_CODE (GtkPrintUnixDialog, gtk_print_unix_dialog, GTK_TYPE_DIALOG,
348                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
349                                                 gtk_print_unix_dialog_buildable_init))
350 
351 static GtkBuildableIface *parent_buildable_iface;
352 
353 static gboolean
is_default_printer(GtkPrintUnixDialog * dialog,GtkPrinter * printer)354 is_default_printer (GtkPrintUnixDialog *dialog,
355                     GtkPrinter         *printer)
356 {
357   if (dialog->format_for_printer)
358     return strcmp (dialog->format_for_printer,
359                    gtk_printer_get_name (printer)) == 0;
360  else
361    return gtk_printer_is_default (printer);
362 }
363 
364 static void
gtk_print_unix_dialog_class_init(GtkPrintUnixDialogClass * class)365 gtk_print_unix_dialog_class_init (GtkPrintUnixDialogClass *class)
366 {
367   GObjectClass *object_class;
368   GtkWidgetClass *widget_class;
369 
370   object_class = (GObjectClass *) class;
371   widget_class = (GtkWidgetClass *) class;
372 
373   object_class->constructed = gtk_print_unix_dialog_constructed;
374   object_class->finalize = gtk_print_unix_dialog_finalize;
375   object_class->dispose = gtk_print_unix_dialog_dispose;
376   object_class->set_property = gtk_print_unix_dialog_set_property;
377   object_class->get_property = gtk_print_unix_dialog_get_property;
378 
379   /**
380    * GtkPrintUnixDialog:page-setup: (attributes org.gtk.Property.get=gtk_print_unix_dialog_get_page_setup org.gtk.Property.set=gtk_print_unix_dialog_set_page_setup)
381    *
382    * The `GtkPageSetup` object to use.
383    */
384   g_object_class_install_property (object_class,
385                                    PROP_PAGE_SETUP,
386                                    g_param_spec_object ("page-setup",
387                                                         P_("Page Setup"),
388                                                         P_("The GtkPageSetup to use"),
389                                                         GTK_TYPE_PAGE_SETUP,
390                                                         GTK_PARAM_READWRITE));
391 
392   /**
393    * GtkPrintUnixDialog:current-page: (attributes org.gtk.Property.get=gtk_print_unix_dialog_get_current_page org.gtk.Property.set=gtk_print_unix_dialog_set_current_page)
394    *
395    * The current page in the document.
396    */
397   g_object_class_install_property (object_class,
398                                    PROP_CURRENT_PAGE,
399                                    g_param_spec_int ("current-page",
400                                                      P_("Current Page"),
401                                                      P_("The current page in the document"),
402                                                      -1,
403                                                      G_MAXINT,
404                                                      -1,
405                                                      GTK_PARAM_READWRITE));
406 
407   /**
408    * GtkPrintUnixDialog:print-settings: (attributes org.gtk.Property.get=gtk_print_unix_dialog_get_settings org.gtk.Property.set=gtk_print_unix_dialog_set_settings)
409    *
410    * The `GtkPrintSettings` object used for this dialog.
411    */
412   g_object_class_install_property (object_class,
413                                    PROP_PRINT_SETTINGS,
414                                    g_param_spec_object ("print-settings",
415                                                         P_("Print Settings"),
416                                                         P_("The GtkPrintSettings used for initializing the dialog"),
417                                                         GTK_TYPE_PRINT_SETTINGS,
418                                                         GTK_PARAM_READWRITE));
419 
420   /**
421    * GtkPrintUnixDialog:selected-printer: (attributes org.gtk.Property.get=gtk_print_unix_dialog_get_selected_printer)
422    *
423    * The `GtkPrinter` which is selected.
424    */
425   g_object_class_install_property (object_class,
426                                    PROP_SELECTED_PRINTER,
427                                    g_param_spec_object ("selected-printer",
428                                                         P_("Selected Printer"),
429                                                         P_("The GtkPrinter which is selected"),
430                                                         GTK_TYPE_PRINTER,
431                                                         GTK_PARAM_READABLE));
432 
433   /**
434    * GtkPrintUnixDialog:manual-capabilities: (attributes org.gtk.Property.get=gtk_print_unix_dialog_get_manual_capabilities org.gtk.Property.set=gtk_print_unix_dialog_set_manual_capabilities)
435    *
436    * Capabilities the application can handle.
437    */
438   g_object_class_install_property (object_class,
439                                    PROP_MANUAL_CAPABILITIES,
440                                    g_param_spec_flags ("manual-capabilities",
441                                                        P_("Manual Capabilities"),
442                                                        P_("Capabilities the application can handle"),
443                                                        GTK_TYPE_PRINT_CAPABILITIES,
444                                                        0,
445                                                        GTK_PARAM_READWRITE));
446 
447   /**
448    * GtkPrintUnixDialog:support-selection: (attributes org.gtk.Property.get=gtk_print_unix_dialog_get_support_selection org.gtk.Property.set=gtk_print_unix_dialog_set_support_selection)
449    *
450    * Whether the dialog supports selection.
451    */
452   g_object_class_install_property (object_class,
453                                    PROP_SUPPORT_SELECTION,
454                                    g_param_spec_boolean ("support-selection",
455                                                          P_("Support Selection"),
456                                                          P_("Whether the dialog supports selection"),
457                                                          FALSE,
458                                                          GTK_PARAM_READWRITE));
459 
460   /**
461    * GtkPrintUnixDialog:has-selection: (attributes org.gtk.Property.get=gtk_print_unix_dialog_get_has_selection org.gtk.Property.set=gtk_print_unix_dialog_set_has_selection)
462    *
463    * Whether the application has a selection.
464    */
465   g_object_class_install_property (object_class,
466                                    PROP_HAS_SELECTION,
467                                    g_param_spec_boolean ("has-selection",
468                                                          P_("Has Selection"),
469                                                          P_("Whether the application has a selection"),
470                                                          FALSE,
471                                                          GTK_PARAM_READWRITE));
472 
473    /**
474     * GtkPrintUnixDialog:embed-page-setup: (attributes org.gtk.Property.get=gtk_print_unix_dialog_get_embed_page_setup org.gtk.Property.set=gtk_print_unix_dialog_set_embed_page_setup)
475     *
476     * %TRUE if the page setup controls are embedded.
477     */
478    g_object_class_install_property (object_class,
479                                    PROP_EMBED_PAGE_SETUP,
480                                    g_param_spec_boolean ("embed-page-setup",
481                                                          P_("Embed Page Setup"),
482                                                          P_("TRUE if page setup combos are embedded in GtkPrintUnixDialog"),
483                                                          FALSE,
484                                                          GTK_PARAM_READWRITE));
485 
486   /* Bind class to template
487    */
488   gtk_widget_class_set_template_from_resource (widget_class,
489 					       "/org/gtk/libgtk/ui/gtkprintunixdialog.ui");
490 
491   /* GtkTreeView / GtkTreeModel */
492   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, printer_list);
493 
494   /* General Widgetry */
495   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, notebook);
496   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, all_pages_radio);
497   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, all_pages_radio);
498   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, current_page_radio);
499   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, selection_radio);
500   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, range_table);
501   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, page_range_radio);
502   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, page_range_entry);
503   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, copies_spin);
504   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, collate_check);
505   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, reverse_check);
506   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, collate_image);
507   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, page_layout_preview);
508   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, scale_spin);
509   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, page_set_combo);
510   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, print_now_radio);
511   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, print_at_radio);
512   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, print_at_entry);
513   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, print_hold_radio);
514   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, paper_size_combo);
515   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, orientation_combo);
516   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, conflicts_widget);
517   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, job_page);
518   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, finishing_table);
519   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, finishing_page);
520   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, image_quality_table);
521   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, image_quality_page);
522   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, color_table);
523   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, color_page);
524   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, advanced_vbox);
525   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, advanced_page);
526   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, extension_point);
527 
528   /* GtkPrinterOptionWidgets... */
529   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, pages_per_sheet);
530   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, duplex);
531   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, paper_type);
532   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, paper_source);
533   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, output_tray);
534   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, job_prio);
535   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, billing_info);
536   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, cover_before);
537   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, cover_after);
538   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, number_up_layout);
539 
540   /* Callbacks handled in the UI */
541   gtk_widget_class_bind_template_callback (widget_class, redraw_page_layout_preview);
542   gtk_widget_class_bind_template_callback (widget_class, error_dialogs);
543   gtk_widget_class_bind_template_callback (widget_class, page_range_entry_focus_changed);
544   gtk_widget_class_bind_template_callback (widget_class, update_page_range_entry_sensitivity);
545   gtk_widget_class_bind_template_callback (widget_class, update_print_at_entry_sensitivity);
546   gtk_widget_class_bind_template_callback (widget_class, update_print_at_option);
547   gtk_widget_class_bind_template_callback (widget_class, update_dialog_from_capabilities);
548   gtk_widget_class_bind_template_callback (widget_class, update_collate_icon);
549   gtk_widget_class_bind_template_callback (widget_class, redraw_page_layout_preview);
550   gtk_widget_class_bind_template_callback (widget_class, update_number_up_layout);
551   gtk_widget_class_bind_template_callback (widget_class, redraw_page_layout_preview);
552 }
553 
554 /* Returns a toplevel GtkWindow, or NULL if none */
555 static GtkWindow *
get_toplevel(GtkWidget * widget)556 get_toplevel (GtkWidget *widget)
557 {
558   GtkWidget *toplevel = NULL;
559 
560   toplevel = GTK_WIDGET (gtk_widget_get_root (widget));
561   if (GTK_IS_WINDOW (toplevel))
562     return GTK_WINDOW (toplevel);
563   else
564     return NULL;
565 }
566 
567 static void
set_busy_cursor(GtkPrintUnixDialog * dialog,gboolean busy)568 set_busy_cursor (GtkPrintUnixDialog *dialog,
569                  gboolean            busy)
570 {
571   GtkWidget *widget;
572   GtkWindow *toplevel;
573 
574   toplevel = get_toplevel (GTK_WIDGET (dialog));
575   widget = GTK_WIDGET (toplevel);
576 
577   if (!toplevel || !gtk_widget_get_realized (widget))
578     return;
579 
580   if (busy)
581     gtk_widget_set_cursor_from_name (widget, "progress");
582   else
583     gtk_widget_set_cursor (widget, NULL);
584 }
585 
586 typedef struct {
587   GMainLoop *loop;
588   int response;
589 } ConfirmationData;
590 
591 static void
on_confirmation_dialog_response(GtkWidget * dialog,int response,gpointer user_data)592 on_confirmation_dialog_response (GtkWidget *dialog,
593                                  int        response,
594                                  gpointer   user_data)
595 {
596   ConfirmationData *data = user_data;
597 
598   data->response = response;
599 
600   g_main_loop_quit (data->loop);
601 
602   gtk_window_destroy (GTK_WINDOW (dialog));
603 }
604 
605 /* This function handles error messages before printing.
606  */
607 static void
error_dialogs(GtkPrintUnixDialog * dialog,int dialog_response_id,gpointer data)608 error_dialogs (GtkPrintUnixDialog *dialog,
609                int                 dialog_response_id,
610                gpointer            data)
611 {
612   if (dialog != NULL && dialog_response_id == GTK_RESPONSE_OK)
613     {
614       GtkPrinter *printer = gtk_print_unix_dialog_get_selected_printer (dialog);
615 
616       if (printer != NULL)
617         {
618           if (dialog->request_details_tag || !gtk_printer_is_accepting_jobs (printer))
619             {
620               g_signal_stop_emission_by_name (dialog, "response");
621               return;
622             }
623 
624           /* Shows overwrite confirmation dialog in the case of printing
625            * to file which already exists.
626            */
627           if (gtk_printer_is_virtual (printer))
628             {
629               GtkPrinterOption *option =
630                 gtk_printer_option_set_lookup (dialog->options,
631                                                "gtk-main-page-custom-input");
632 
633               if (option != NULL &&
634                   option->type == GTK_PRINTER_OPTION_TYPE_FILESAVE)
635                 {
636                   GFile *file = g_file_new_for_uri (option->value);
637 
638                   if (g_file_query_exists (file, NULL))
639                     {
640                       GtkWidget *message_dialog;
641                       GtkWindow *toplevel;
642                       char *basename;
643                       char *dirname;
644                       GFile *parent;
645 
646                       toplevel = get_toplevel (GTK_WIDGET (dialog));
647 
648                       basename = g_file_get_basename (file);
649                       parent = g_file_get_parent (file);
650                       dirname = g_file_get_parse_name (parent);
651                       g_object_unref (parent);
652 
653                       message_dialog = gtk_message_dialog_new (toplevel,
654                                                                GTK_DIALOG_MODAL |
655                                                                GTK_DIALOG_DESTROY_WITH_PARENT,
656                                                                GTK_MESSAGE_QUESTION,
657                                                                GTK_BUTTONS_NONE,
658                                                                _("A file named “%s” already exists.  Do you want to replace it?"),
659                                                                basename);
660 
661                       gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (message_dialog),
662                                                                 _("The file already exists in “%s”.  Replacing it will "
663                                                                 "overwrite its contents."),
664                                                                 dirname);
665 
666                       gtk_dialog_add_button (GTK_DIALOG (message_dialog),
667                                              _("_Cancel"),
668                                              GTK_RESPONSE_CANCEL);
669                       gtk_dialog_add_button (GTK_DIALOG (message_dialog),
670                                              _("_Replace"),
671                                              GTK_RESPONSE_ACCEPT);
672                       gtk_dialog_set_default_response (GTK_DIALOG (message_dialog),
673                                                        GTK_RESPONSE_ACCEPT);
674 
675                       if (gtk_window_has_group (toplevel))
676                         gtk_window_group_add_window (gtk_window_get_group (toplevel),
677                                                      GTK_WINDOW (message_dialog));
678 
679                       gtk_window_present (GTK_WINDOW (message_dialog));
680 
681                       /* Block on the confirmation dialog until we have a response,
682                        * so that we can stop the "response" signal emission on the
683                        * print dialog
684                        */
685                       ConfirmationData cdata;
686 
687                       cdata.loop = g_main_loop_new (NULL, FALSE);
688                       cdata.response = 0;
689 
690                       g_signal_connect (message_dialog, "response",
691                                         G_CALLBACK (on_confirmation_dialog_response),
692                                         &cdata);
693 
694                       g_main_loop_run (cdata.loop);
695                       g_main_loop_unref (cdata.loop);
696 
697                       g_free (dirname);
698                       g_free (basename);
699 
700                       if (cdata.response != GTK_RESPONSE_ACCEPT)
701                         g_signal_stop_emission_by_name (dialog, "response");
702                     }
703 
704                   g_object_unref (file);
705                 }
706             }
707         }
708     }
709 }
710 
711 static char *
get_printer_key(GtkPrinter * printer)712 get_printer_key (GtkPrinter *printer)
713 {
714   return g_strconcat ("", gtk_printer_get_name (printer), " ", gtk_printer_get_location (printer), NULL);
715 }
716 
717 static void
setup_paper_size_item(GtkSignalListItemFactory * factory,GtkListItem * item)718 setup_paper_size_item (GtkSignalListItemFactory *factory,
719                        GtkListItem              *item)
720 {
721   GtkWidget *label;
722 
723   label = gtk_label_new ("");
724   gtk_widget_set_halign (label, GTK_ALIGN_START);
725   gtk_list_item_set_child (item, label);
726 }
727 
728 static void
bind_paper_size_list_item(GtkSignalListItemFactory * factory,GtkListItem * item,GtkPrintUnixDialog * self)729 bind_paper_size_list_item (GtkSignalListItemFactory *factory,
730                            GtkListItem              *item,
731                            GtkPrintUnixDialog       *self)
732 {
733   GtkPageSetup *page_setup;
734   GtkWidget *label;
735   guint pos;
736   GListModel *papers;
737   GListModel *model;
738   gpointer first;
739 
740   page_setup = gtk_list_item_get_item (item);
741   label = gtk_list_item_get_child (item);
742 
743   pos = gtk_list_item_get_position (item);
744   papers = gtk_drop_down_get_model (GTK_DROP_DOWN (self->paper_size_combo));
745   model = gtk_flatten_list_model_get_model_for_item (GTK_FLATTEN_LIST_MODEL (papers), pos);
746   if (model != G_LIST_MODEL (self->manage_papers_list))
747     {
748       GtkPaperSize *paper_size = gtk_page_setup_get_paper_size (page_setup);
749       gtk_label_set_text (GTK_LABEL (label), gtk_paper_size_get_display_name (paper_size));
750     }
751   else
752     gtk_label_set_text (GTK_LABEL (label), _("Manage Custom Sizes…"));
753 
754   first = g_list_model_get_item (model, 0);
755   g_object_unref (first);
756   if (pos != 0 &&
757       page_setup == GTK_PAGE_SETUP (first))
758     gtk_widget_add_css_class (gtk_widget_get_parent (label), "separator");
759   else
760     gtk_widget_remove_css_class (gtk_widget_get_parent (label), "separator");
761 }
762 
763 static void
bind_paper_size_item(GtkSignalListItemFactory * factory,GtkListItem * item,GtkPrintUnixDialog * self)764 bind_paper_size_item (GtkSignalListItemFactory *factory,
765                       GtkListItem              *item,
766                       GtkPrintUnixDialog       *self)
767 {
768   GtkWidget *label;
769 
770   bind_paper_size_list_item (factory, item, self);
771 
772   label = gtk_list_item_get_child (item);
773   gtk_widget_remove_css_class (label, "separator-before");
774 }
775 
776 static void
gtk_print_unix_dialog_init(GtkPrintUnixDialog * dialog)777 gtk_print_unix_dialog_init (GtkPrintUnixDialog *dialog)
778 {
779   GtkWidget *widget;
780   GListModel *model;
781   GListModel *sorted;
782   GListModel *filtered;
783   GListModel *selection;
784   GtkSorter *sorter;
785   GtkFilter *filter;
786   GtkStringFilter *filter1;
787   GtkCustomFilter *filter2;
788   GtkListItemFactory *factory;
789   GListStore *store;
790   GListModel *paper_size_list;
791   GtkPageSetup *page_setup;
792 
793   dialog->print_backends = NULL;
794   dialog->current_page = -1;
795   dialog->number_up_layout_n_option = NULL;
796   dialog->number_up_layout_2_option = NULL;
797 
798   dialog->page_setup = gtk_page_setup_new ();
799   dialog->page_setup_set = FALSE;
800   dialog->embed_page_setup = FALSE;
801   dialog->internal_page_setup_change = FALSE;
802   dialog->page_setup_list = g_list_store_new (GTK_TYPE_PAGE_SETUP);
803   dialog->custom_paper_list = g_list_store_new (GTK_TYPE_PAGE_SETUP);
804   dialog->manage_papers_list = g_list_store_new (GTK_TYPE_PAGE_SETUP);
805   page_setup = gtk_page_setup_new ();
806   g_list_store_append (dialog->manage_papers_list, page_setup);
807   g_object_unref (page_setup);
808 
809   dialog->support_selection = FALSE;
810   dialog->has_selection = FALSE;
811 
812   g_type_ensure (GTK_TYPE_PRINTER);
813   g_type_ensure (GTK_TYPE_PRINTER_OPTION);
814   g_type_ensure (GTK_TYPE_PRINTER_OPTION_SET);
815   g_type_ensure (GTK_TYPE_PRINTER_OPTION_WIDGET);
816 
817   gtk_widget_init_template (GTK_WIDGET (dialog));
818   gtk_widget_add_css_class (GTK_WIDGET (dialog), "print");
819 
820   gtk_dialog_set_use_header_bar_from_setting (GTK_DIALOG (dialog));
821   gtk_dialog_add_buttons (GTK_DIALOG (dialog),
822                           _("Pre_view"), GTK_RESPONSE_APPLY,
823                           _("_Cancel"), GTK_RESPONSE_CANCEL,
824                           _("_Print"), GTK_RESPONSE_OK,
825                           NULL);
826   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
827   widget = gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
828   gtk_widget_set_sensitive (widget, FALSE);
829 
830   gtk_widget_set_visible (dialog->selection_radio, FALSE);
831   gtk_widget_set_visible (dialog->conflicts_widget, FALSE);
832 
833   factory = gtk_signal_list_item_factory_new ();
834   g_signal_connect (factory, "setup", G_CALLBACK (setup_paper_size_item), dialog);
835   g_signal_connect (factory, "bind", G_CALLBACK (bind_paper_size_item), dialog);
836   gtk_drop_down_set_factory (GTK_DROP_DOWN (dialog->paper_size_combo), factory);
837   g_object_unref (factory);
838 
839   factory = gtk_signal_list_item_factory_new ();
840   g_signal_connect (factory, "setup", G_CALLBACK (setup_paper_size_item), dialog);
841   g_signal_connect (factory, "bind", G_CALLBACK (bind_paper_size_list_item), dialog);
842   gtk_drop_down_set_list_factory (GTK_DROP_DOWN (dialog->paper_size_combo), factory);
843   g_object_unref (factory);
844 
845   store = g_list_store_new (G_TYPE_LIST_MODEL);
846   g_list_store_append (store, dialog->page_setup_list);
847   g_list_store_append (store, dialog->custom_paper_list);
848   g_list_store_append (store, dialog->manage_papers_list);
849   paper_size_list = G_LIST_MODEL (gtk_flatten_list_model_new (G_LIST_MODEL (store)));
850   gtk_drop_down_set_model (GTK_DROP_DOWN (dialog->paper_size_combo), paper_size_list);
851   g_object_unref (paper_size_list);
852 
853   /* Load backends */
854   model = load_print_backends (dialog);
855   sorter = GTK_SORTER (gtk_custom_sorter_new (default_printer_list_sort_func, NULL, NULL));
856   sorted = G_LIST_MODEL (gtk_sort_list_model_new (model, sorter));
857 
858   filter = GTK_FILTER (gtk_every_filter_new ());
859 
860   filter1 = gtk_string_filter_new (
861                 gtk_cclosure_expression_new (G_TYPE_STRING,
862                                              NULL, 0, NULL,
863                                              G_CALLBACK (get_printer_key),
864                                              NULL, NULL));
865   gtk_string_filter_set_match_mode (filter1, GTK_STRING_FILTER_MATCH_MODE_SUBSTRING);
866   gtk_string_filter_set_ignore_case (filter1, TRUE);
867   gtk_multi_filter_append (GTK_MULTI_FILTER (filter), GTK_FILTER (filter1));
868 
869   filter2 = gtk_custom_filter_new (is_printer_active, dialog, NULL);
870   gtk_multi_filter_append (GTK_MULTI_FILTER (filter), GTK_FILTER (filter2));
871 
872   filtered = G_LIST_MODEL (gtk_filter_list_model_new (sorted, filter));
873 
874   selection = G_LIST_MODEL (gtk_single_selection_new (filtered));
875   gtk_single_selection_set_autoselect (GTK_SINGLE_SELECTION (selection), FALSE);
876   gtk_single_selection_set_selected (GTK_SINGLE_SELECTION (selection), GTK_INVALID_LIST_POSITION);
877   gtk_column_view_set_model (GTK_COLUMN_VIEW (dialog->printer_list), GTK_SELECTION_MODEL (selection));
878   g_signal_connect (selection, "items-changed", G_CALLBACK (printer_added_cb), dialog);
879   g_signal_connect_swapped (selection, "notify::selected", G_CALLBACK (selected_printer_changed), dialog);
880   g_object_unref (selection);
881 
882   gtk_print_load_custom_papers (dialog->custom_paper_list);
883 
884   gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (dialog->collate_image),
885                                   draw_collate,
886                                   dialog, NULL);
887   gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (dialog->page_layout_preview),
888                                   draw_page,
889                                   dialog, NULL);
890 
891   gtk_css_node_set_name (gtk_widget_get_css_node (dialog->collate_image), g_quark_from_static_string ("drawing"));
892   gtk_css_node_set_name (gtk_widget_get_css_node (dialog->page_layout_preview), g_quark_from_static_string ("drawing"));
893 
894   dialog->collate_paper_node = gtk_css_node_new();
895   gtk_css_node_set_name (dialog->collate_paper_node, g_quark_from_static_string ("paper"));
896   gtk_css_node_set_parent (dialog->collate_paper_node,
897                            gtk_widget_get_css_node (dialog->collate_image));
898   g_object_unref (dialog->collate_paper_node);
899 
900   dialog->page_layout_paper_node = gtk_css_node_new();
901   gtk_css_node_set_name (dialog->page_layout_paper_node, g_quark_from_static_string ("paper"));
902   gtk_css_node_set_parent (dialog->page_layout_paper_node,
903                            gtk_widget_get_css_node (dialog->page_layout_preview));
904   g_object_unref (dialog->page_layout_paper_node);
905 }
906 
907 static void
gtk_print_unix_dialog_constructed(GObject * object)908 gtk_print_unix_dialog_constructed (GObject *object)
909 {
910   gboolean use_header;
911 
912   G_OBJECT_CLASS (gtk_print_unix_dialog_parent_class)->constructed (object);
913 
914   g_object_get (object, "use-header-bar", &use_header, NULL);
915   if (use_header)
916     {
917        /* Reorder the preview button */
918        GtkWidget *button, *parent;
919        button = gtk_dialog_get_widget_for_response (GTK_DIALOG (object), GTK_RESPONSE_APPLY);
920        g_object_ref (button);
921        parent = gtk_widget_get_ancestor (button, GTK_TYPE_HEADER_BAR);
922        gtk_box_remove (GTK_BOX (gtk_widget_get_parent (button)), button);
923        gtk_header_bar_pack_end (GTK_HEADER_BAR (parent), button);
924        g_object_unref (button);
925     }
926 
927   update_dialog_from_capabilities (GTK_PRINT_UNIX_DIALOG (object));
928 }
929 
930 static void
gtk_print_unix_dialog_dispose(GObject * object)931 gtk_print_unix_dialog_dispose (GObject *object)
932 {
933   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
934 
935   /* Make sure we don't destroy custom widgets owned by the backends */
936   clear_per_printer_ui (dialog);
937 
938   G_OBJECT_CLASS (gtk_print_unix_dialog_parent_class)->dispose (object);
939 }
940 
941 static void
disconnect_printer_details_request(GtkPrintUnixDialog * dialog,gboolean details_failed)942 disconnect_printer_details_request (GtkPrintUnixDialog *dialog,
943                                     gboolean            details_failed)
944 {
945   if (dialog->request_details_tag)
946     {
947       g_signal_handler_disconnect (dialog->request_details_printer,
948                                    dialog->request_details_tag);
949       dialog->request_details_tag = 0;
950       set_busy_cursor (dialog, FALSE);
951       if (details_failed)
952         gtk_printer_set_state_message (dialog->request_details_printer, _("Getting printer information failed"));
953       g_clear_object (&dialog->request_details_printer);
954     }
955 }
956 
957 static void
gtk_print_unix_dialog_finalize(GObject * object)958 gtk_print_unix_dialog_finalize (GObject *object)
959 {
960   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
961 
962   unschedule_idle_mark_conflicts (dialog);
963   disconnect_printer_details_request (dialog, FALSE);
964 
965   g_clear_object (&dialog->current_printer);
966   g_clear_object (&dialog->options);
967 
968   if (dialog->number_up_layout_2_option)
969     {
970       dialog->number_up_layout_2_option->choices[0] = NULL;
971       dialog->number_up_layout_2_option->choices[1] = NULL;
972       g_free (dialog->number_up_layout_2_option->choices_display[0]);
973       g_free (dialog->number_up_layout_2_option->choices_display[1]);
974       dialog->number_up_layout_2_option->choices_display[0] = NULL;
975       dialog->number_up_layout_2_option->choices_display[1] = NULL;
976       g_object_unref (dialog->number_up_layout_2_option);
977       dialog->number_up_layout_2_option = NULL;
978     }
979 
980   g_clear_object (&dialog->number_up_layout_n_option);
981   g_clear_object (&dialog->page_setup);
982   g_clear_object (&dialog->initial_settings);
983   g_clear_pointer (&dialog->waiting_for_printer, (GDestroyNotify)g_free);
984   g_clear_pointer (&dialog->format_for_printer, (GDestroyNotify)g_free);
985 
986   g_list_free (dialog->print_backends);
987   dialog->print_backends = NULL;
988 
989   g_clear_object (&dialog->page_setup_list);
990   g_clear_object (&dialog->custom_paper_list);
991   g_clear_object (&dialog->manage_papers_list);
992 
993   G_OBJECT_CLASS (gtk_print_unix_dialog_parent_class)->finalize (object);
994 }
995 
996 static void
gtk_print_unix_dialog_buildable_init(GtkBuildableIface * iface)997 gtk_print_unix_dialog_buildable_init (GtkBuildableIface *iface)
998 {
999   parent_buildable_iface = g_type_interface_peek_parent (iface);
1000 
1001   iface->get_internal_child = gtk_print_unix_dialog_buildable_get_internal_child;
1002 }
1003 
1004 static GObject *
gtk_print_unix_dialog_buildable_get_internal_child(GtkBuildable * buildable,GtkBuilder * builder,const char * childname)1005 gtk_print_unix_dialog_buildable_get_internal_child (GtkBuildable *buildable,
1006                                                     GtkBuilder   *builder,
1007                                                     const char   *childname)
1008 {
1009   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (buildable);
1010 
1011   if (strcmp (childname, "notebook") == 0)
1012     return G_OBJECT (dialog->notebook);
1013 
1014   return parent_buildable_iface->get_internal_child (buildable, builder, childname);
1015 }
1016 
1017 static void
printer_status_cb(GtkPrintBackend * backend,GtkPrinter * printer,GtkPrintUnixDialog * dialog)1018 printer_status_cb (GtkPrintBackend    *backend,
1019                    GtkPrinter         *printer,
1020                    GtkPrintUnixDialog *dialog)
1021 {
1022   GListModel *model;
1023 
1024   /* When the pause state change then we need to update sensitive property
1025    * of GTK_RESPONSE_OK button inside of selected_printer_changed function.
1026    */
1027   selected_printer_changed (dialog);
1028 
1029   model = G_LIST_MODEL (gtk_column_view_get_model (GTK_COLUMN_VIEW (dialog->printer_list)));
1030 
1031   if (gtk_print_backend_printer_list_is_done (backend) &&
1032       gtk_printer_is_default (printer) &&
1033       gtk_single_selection_get_selected (GTK_SINGLE_SELECTION (model)) == GTK_INVALID_LIST_POSITION)
1034     set_active_printer (dialog, gtk_printer_get_name (printer));
1035 }
1036 
1037 static void
printer_added_cb(GListModel * model,guint position,guint removed,guint added,GtkPrintUnixDialog * dialog)1038 printer_added_cb (GListModel         *model,
1039                   guint               position,
1040                   guint               removed,
1041                   guint               added,
1042                   GtkPrintUnixDialog *dialog)
1043 {
1044   guint i;
1045 
1046   for (i = position; i < position + added; i++)
1047     {
1048       GtkPrinter *printer = g_list_model_get_item (model, i);
1049 
1050       if (dialog->waiting_for_printer != NULL &&
1051           strcmp (gtk_printer_get_name (printer), dialog->waiting_for_printer) == 0)
1052         {
1053           gtk_single_selection_set_selected (GTK_SINGLE_SELECTION (model), i);
1054           g_free (dialog->waiting_for_printer);
1055           dialog->waiting_for_printer = NULL;
1056           g_object_unref (printer);
1057           return;
1058         }
1059       else if (is_default_printer (dialog, printer) &&
1060                gtk_single_selection_get_selected (GTK_SINGLE_SELECTION (model)) == GTK_INVALID_LIST_POSITION)
1061         {
1062           gtk_single_selection_set_selected (GTK_SINGLE_SELECTION (model), i);
1063           g_object_unref (printer);
1064           return;
1065         }
1066 
1067       g_object_unref (printer);
1068     }
1069 }
1070 
1071 static GListModel *
load_print_backends(GtkPrintUnixDialog * dialog)1072 load_print_backends (GtkPrintUnixDialog *dialog)
1073 {
1074   GList *node;
1075   GListStore *lists;
1076 
1077   lists = g_list_store_new (G_TYPE_LIST_MODEL);
1078 
1079   if (g_module_supported ())
1080     dialog->print_backends = gtk_print_backend_load_modules ();
1081 
1082   for (node = dialog->print_backends; node != NULL; node = node->next)
1083     {
1084       GtkPrintBackend *backend = node->data;
1085 
1086       g_signal_connect_object (backend, "printer-status-changed",
1087                                G_CALLBACK (printer_status_cb), G_OBJECT (dialog), 0);
1088       g_list_store_append (lists, gtk_print_backend_get_printers (backend));
1089     }
1090 
1091   return G_LIST_MODEL (gtk_flatten_list_model_new (G_LIST_MODEL (lists)));
1092 }
1093 
1094 static void
gtk_print_unix_dialog_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1095 gtk_print_unix_dialog_set_property (GObject      *object,
1096                                     guint         prop_id,
1097                                     const GValue *value,
1098                                     GParamSpec   *pspec)
1099 
1100 {
1101   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
1102 
1103   switch (prop_id)
1104     {
1105     case PROP_PAGE_SETUP:
1106       gtk_print_unix_dialog_set_page_setup (dialog, g_value_get_object (value));
1107       break;
1108     case PROP_CURRENT_PAGE:
1109       gtk_print_unix_dialog_set_current_page (dialog, g_value_get_int (value));
1110       break;
1111     case PROP_PRINT_SETTINGS:
1112       gtk_print_unix_dialog_set_settings (dialog, g_value_get_object (value));
1113       break;
1114     case PROP_MANUAL_CAPABILITIES:
1115       gtk_print_unix_dialog_set_manual_capabilities (dialog, g_value_get_flags (value));
1116       break;
1117     case PROP_SUPPORT_SELECTION:
1118       gtk_print_unix_dialog_set_support_selection (dialog, g_value_get_boolean (value));
1119       break;
1120     case PROP_HAS_SELECTION:
1121       gtk_print_unix_dialog_set_has_selection (dialog, g_value_get_boolean (value));
1122       break;
1123     case PROP_EMBED_PAGE_SETUP:
1124       gtk_print_unix_dialog_set_embed_page_setup (dialog, g_value_get_boolean (value));
1125       break;
1126     default:
1127       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1128       break;
1129     }
1130 }
1131 
1132 static void
gtk_print_unix_dialog_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1133 gtk_print_unix_dialog_get_property (GObject    *object,
1134                                     guint       prop_id,
1135                                     GValue     *value,
1136                                     GParamSpec *pspec)
1137 {
1138   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
1139 
1140   switch (prop_id)
1141     {
1142     case PROP_PAGE_SETUP:
1143       g_value_set_object (value, dialog->page_setup);
1144       break;
1145     case PROP_CURRENT_PAGE:
1146       g_value_set_int (value, dialog->current_page);
1147       break;
1148     case PROP_PRINT_SETTINGS:
1149       g_value_take_object (value, gtk_print_unix_dialog_get_settings (dialog));
1150       break;
1151     case PROP_SELECTED_PRINTER:
1152       g_value_set_object (value, dialog->current_printer);
1153       break;
1154     case PROP_MANUAL_CAPABILITIES:
1155       g_value_set_flags (value, dialog->manual_capabilities);
1156       break;
1157     case PROP_SUPPORT_SELECTION:
1158       g_value_set_boolean (value, dialog->support_selection);
1159       break;
1160     case PROP_HAS_SELECTION:
1161       g_value_set_boolean (value, dialog->has_selection);
1162       break;
1163     case PROP_EMBED_PAGE_SETUP:
1164       g_value_set_boolean (value, dialog->embed_page_setup);
1165       break;
1166     default:
1167       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1168       break;
1169     }
1170 }
1171 
1172 static gboolean
is_printer_active(gpointer item,gpointer data)1173 is_printer_active (gpointer item, gpointer data)
1174 {
1175   GtkPrinter *printer = item;
1176   GtkPrintUnixDialog *dialog = data;
1177   gboolean result;
1178 
1179   result = gtk_printer_is_active (printer);
1180 
1181   if (result &&
1182       dialog->manual_capabilities & (GTK_PRINT_CAPABILITY_GENERATE_PDF |
1183                                    GTK_PRINT_CAPABILITY_GENERATE_PS))
1184     {
1185        /* Check that the printer can handle at least one of the data
1186         * formats that the application supports.
1187         */
1188        result = ((dialog->manual_capabilities & GTK_PRINT_CAPABILITY_GENERATE_PDF) &&
1189                  gtk_printer_accepts_pdf (printer)) ||
1190                 ((dialog->manual_capabilities & GTK_PRINT_CAPABILITY_GENERATE_PS) &&
1191                  gtk_printer_accepts_ps (printer));
1192     }
1193 
1194   return result;
1195 }
1196 
1197 static int
default_printer_list_sort_func(gconstpointer a,gconstpointer b,gpointer user_data)1198 default_printer_list_sort_func (gconstpointer a,
1199                                 gconstpointer b,
1200                                 gpointer      user_data)
1201 {
1202   GtkPrinter *a_printer = (gpointer)a;
1203   GtkPrinter *b_printer = (gpointer)b;
1204   const char *a_name;
1205   const char *b_name;
1206 
1207   if (a_printer == NULL && b_printer == NULL)
1208     return 0;
1209   else if (a_printer == NULL)
1210    return 1;
1211   else if (b_printer == NULL)
1212    return -1;
1213 
1214   if (gtk_printer_is_virtual (a_printer) && gtk_printer_is_virtual (b_printer))
1215     return 0;
1216   else if (gtk_printer_is_virtual (a_printer) && !gtk_printer_is_virtual (b_printer))
1217     return -1;
1218   else if (!gtk_printer_is_virtual (a_printer) && gtk_printer_is_virtual (b_printer))
1219     return 1;
1220 
1221   a_name = gtk_printer_get_name (a_printer);
1222   b_name = gtk_printer_get_name (b_printer);
1223 
1224   if (a_name == NULL && b_name == NULL)
1225     return  0;
1226   else if (a_name == NULL && b_name != NULL)
1227     return  1;
1228   else if (a_name != NULL && b_name == NULL)
1229     return -1;
1230 
1231   return g_ascii_strcasecmp (a_name, b_name);
1232 }
1233 
1234 static GtkWidget *
wrap_in_frame(const char * label,GtkWidget * child)1235 wrap_in_frame (const char *label,
1236                GtkWidget   *child)
1237 {
1238   GtkWidget *box, *label_widget;
1239   char *bold_text;
1240 
1241   label_widget = gtk_label_new (NULL);
1242   gtk_widget_set_halign (label_widget, GTK_ALIGN_START);
1243   gtk_widget_set_valign (label_widget, GTK_ALIGN_CENTER);
1244   gtk_widget_show (label_widget);
1245 
1246   bold_text = g_markup_printf_escaped ("<b>%s</b>", label);
1247   gtk_label_set_markup (GTK_LABEL (label_widget), bold_text);
1248   g_free (bold_text);
1249 
1250   box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
1251   gtk_box_append (GTK_BOX (box), label_widget);
1252 
1253   gtk_widget_set_margin_start (child, 12);
1254   gtk_widget_set_halign (child, GTK_ALIGN_FILL);
1255   gtk_widget_set_valign (child, GTK_ALIGN_FILL);
1256 
1257   gtk_box_append (GTK_BOX (box), child);
1258 
1259   return box;
1260 }
1261 
1262 static gboolean
setup_option(GtkPrintUnixDialog * dialog,const char * option_name,GtkPrinterOptionWidget * widget)1263 setup_option (GtkPrintUnixDialog     *dialog,
1264               const char             *option_name,
1265               GtkPrinterOptionWidget *widget)
1266 {
1267   GtkPrinterOption *option;
1268 
1269   option = gtk_printer_option_set_lookup (dialog->options, option_name);
1270   gtk_printer_option_widget_set_source (widget, option);
1271 
1272   return option != NULL;
1273 }
1274 
1275 static void
add_option_to_extension_point(GtkPrinterOption * option,gpointer data)1276 add_option_to_extension_point (GtkPrinterOption *option,
1277                                gpointer          data)
1278 {
1279   GtkWidget *extension_point = data;
1280   GtkWidget *widget;
1281 
1282   widget = gtk_printer_option_widget_new (option);
1283   gtk_widget_show (widget);
1284 
1285   if (gtk_printer_option_widget_has_external_label (GTK_PRINTER_OPTION_WIDGET (widget)))
1286     {
1287       GtkWidget *label, *hbox;
1288 
1289       gtk_widget_set_valign (widget, GTK_ALIGN_BASELINE);
1290 
1291       label = gtk_printer_option_widget_get_external_label (GTK_PRINTER_OPTION_WIDGET (widget));
1292       gtk_widget_show (label);
1293       gtk_widget_set_halign (label, GTK_ALIGN_START);
1294       gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
1295       gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
1296 
1297       hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
1298       gtk_widget_set_valign (hbox, GTK_ALIGN_BASELINE);
1299       gtk_box_append (GTK_BOX (hbox), label);
1300       gtk_box_append (GTK_BOX (hbox), widget);
1301       gtk_widget_show (hbox);
1302 
1303       gtk_box_append (GTK_BOX (extension_point), hbox);
1304     }
1305   else
1306     gtk_box_append (GTK_BOX (extension_point), widget);
1307 }
1308 
1309 static int
grid_rows(GtkGrid * table)1310 grid_rows (GtkGrid *table)
1311 {
1312   int t0, t1, l, t, w, h;
1313   GtkWidget *c;
1314   gboolean first;
1315 
1316   t0 = t1 = 0;
1317   for (c = gtk_widget_get_first_child (GTK_WIDGET (table)), first = TRUE;
1318        c != NULL;
1319        c  = gtk_widget_get_next_sibling (GTK_WIDGET (c)), first = FALSE)
1320     {
1321       gtk_grid_query_child (table, c, &l, &t, &w, &h);
1322       if (first)
1323         {
1324           t0 = t;
1325           t1 = t + h;
1326         }
1327       else
1328         {
1329           if (t < t0)
1330             t0 = t;
1331           if (t + h > t1)
1332             t1 = t + h;
1333         }
1334     }
1335 
1336   return t1 - t0;
1337 }
1338 
1339 static void
add_option_to_table(GtkPrinterOption * option,gpointer user_data)1340 add_option_to_table (GtkPrinterOption *option,
1341                      gpointer          user_data)
1342 {
1343   GtkGrid *table;
1344   GtkWidget *label, *widget;
1345   guint row;
1346 
1347   table = GTK_GRID (user_data);
1348 
1349   if (g_str_has_prefix (option->name, "gtk-"))
1350     return;
1351 
1352   row = grid_rows (table);
1353 
1354   widget = gtk_printer_option_widget_new (option);
1355   gtk_widget_show (widget);
1356 
1357   if (gtk_printer_option_widget_has_external_label (GTK_PRINTER_OPTION_WIDGET (widget)))
1358     {
1359       label = gtk_printer_option_widget_get_external_label (GTK_PRINTER_OPTION_WIDGET (widget));
1360       gtk_widget_show (label);
1361 
1362       gtk_widget_set_halign (label, GTK_ALIGN_START);
1363       gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
1364       gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
1365 
1366       gtk_grid_attach (table, label, 0, row - 1, 1, 1);
1367       gtk_grid_attach (table, widget, 1, row - 1, 1, 1);
1368     }
1369   else
1370     gtk_grid_attach (table, widget, 0, row - 1, 2, 1);
1371 }
1372 
1373 static void
setup_page_table(GtkPrinterOptionSet * options,const char * group,GtkWidget * table,GtkWidget * page)1374 setup_page_table (GtkPrinterOptionSet *options,
1375                   const char          *group,
1376                   GtkWidget           *table,
1377                   GtkWidget           *page)
1378 {
1379   int nrows;
1380 
1381   gtk_printer_option_set_foreach_in_group (options, group,
1382                                            add_option_to_table,
1383                                            table);
1384 
1385   nrows = grid_rows (GTK_GRID (table));
1386   if (nrows == 0)
1387     gtk_widget_hide (page);
1388   else
1389     gtk_widget_show (page);
1390 }
1391 
1392 static void
update_print_at_option(GtkPrintUnixDialog * dialog)1393 update_print_at_option (GtkPrintUnixDialog *dialog)
1394 {
1395   GtkPrinterOption *option;
1396 
1397   option = gtk_printer_option_set_lookup (dialog->options, "gtk-print-time");
1398 
1399   if (option == NULL)
1400     return;
1401 
1402   if (dialog->updating_print_at)
1403     return;
1404 
1405   if (gtk_check_button_get_active (GTK_CHECK_BUTTON (dialog->print_at_radio)))
1406     gtk_printer_option_set (option, "at");
1407   else if (gtk_check_button_get_active (GTK_CHECK_BUTTON (dialog->print_hold_radio)))
1408     gtk_printer_option_set (option, "on-hold");
1409   else
1410     gtk_printer_option_set (option, "now");
1411 
1412   option = gtk_printer_option_set_lookup (dialog->options, "gtk-print-time-text");
1413   if (option != NULL)
1414     {
1415       const char *text;
1416 
1417       text = gtk_editable_get_text (GTK_EDITABLE (dialog->print_at_entry));
1418       gtk_printer_option_set (option, text);
1419     }
1420 }
1421 
1422 
1423 static gboolean
setup_print_at(GtkPrintUnixDialog * dialog)1424 setup_print_at (GtkPrintUnixDialog *dialog)
1425 {
1426   GtkPrinterOption *option;
1427 
1428   option = gtk_printer_option_set_lookup (dialog->options, "gtk-print-time");
1429 
1430   if (option == NULL)
1431     {
1432       gtk_check_button_set_active (GTK_CHECK_BUTTON (dialog->print_now_radio), TRUE);
1433       gtk_widget_set_sensitive (dialog->print_at_radio, FALSE);
1434       gtk_widget_set_sensitive (dialog->print_at_entry, FALSE);
1435       gtk_widget_set_sensitive (dialog->print_hold_radio, FALSE);
1436       gtk_editable_set_text (GTK_EDITABLE (dialog->print_at_entry), "");
1437       return FALSE;
1438     }
1439 
1440   dialog->updating_print_at = TRUE;
1441 
1442   gtk_widget_set_sensitive (dialog->print_at_entry, FALSE);
1443   gtk_widget_set_sensitive (dialog->print_at_radio,
1444                             gtk_printer_option_has_choice (option, "at"));
1445 
1446   gtk_widget_set_sensitive (dialog->print_hold_radio,
1447                             gtk_printer_option_has_choice (option, "on-hold"));
1448 
1449   update_print_at_option (dialog);
1450 
1451   if (strcmp (option->value, "at") == 0)
1452     gtk_check_button_set_active (GTK_CHECK_BUTTON (dialog->print_at_radio), TRUE);
1453   else if (strcmp (option->value, "on-hold") == 0)
1454     gtk_check_button_set_active (GTK_CHECK_BUTTON (dialog->print_hold_radio), TRUE);
1455   else
1456     gtk_check_button_set_active (GTK_CHECK_BUTTON (dialog->print_now_radio), TRUE);
1457 
1458   option = gtk_printer_option_set_lookup (dialog->options, "gtk-print-time-text");
1459   if (option != NULL)
1460     gtk_editable_set_text (GTK_EDITABLE (dialog->print_at_entry), option->value);
1461 
1462   dialog->updating_print_at = FALSE;
1463 
1464   return TRUE;
1465 }
1466 
1467 static void
update_dialog_from_settings(GtkPrintUnixDialog * dialog)1468 update_dialog_from_settings (GtkPrintUnixDialog *dialog)
1469 {
1470   GList *groups, *l;
1471   char *group;
1472   GtkWidget *table, *frame;
1473   gboolean has_advanced, has_job;
1474   guint nrows;
1475   GtkWidget *child;
1476 
1477   if (dialog->current_printer == NULL)
1478     {
1479        clear_per_printer_ui (dialog);
1480        gtk_widget_hide (dialog->job_page);
1481        gtk_widget_hide (dialog->advanced_page);
1482        gtk_widget_hide (dialog->image_quality_page);
1483        gtk_widget_hide (dialog->finishing_page);
1484        gtk_widget_hide (dialog->color_page);
1485        gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
1486 
1487        return;
1488     }
1489 
1490   setup_option (dialog, "gtk-n-up", dialog->pages_per_sheet);
1491   setup_option (dialog, "gtk-n-up-layout", dialog->number_up_layout);
1492   setup_option (dialog, "gtk-duplex", dialog->duplex);
1493   setup_option (dialog, "gtk-paper-type", dialog->paper_type);
1494   setup_option (dialog, "gtk-paper-source", dialog->paper_source);
1495   setup_option (dialog, "gtk-output-tray", dialog->output_tray);
1496 
1497   has_job = FALSE;
1498   has_job |= setup_option (dialog, "gtk-job-prio", dialog->job_prio);
1499   has_job |= setup_option (dialog, "gtk-billing-info", dialog->billing_info);
1500   has_job |= setup_option (dialog, "gtk-cover-before", dialog->cover_before);
1501   has_job |= setup_option (dialog, "gtk-cover-after", dialog->cover_after);
1502   has_job |= setup_print_at (dialog);
1503 
1504   if (has_job)
1505     gtk_widget_show (dialog->job_page);
1506   else
1507     gtk_widget_hide (dialog->job_page);
1508 
1509   setup_page_table (dialog->options,
1510                     "ImageQualityPage",
1511                     dialog->image_quality_table,
1512                     dialog->image_quality_page);
1513 
1514   setup_page_table (dialog->options,
1515                     "FinishingPage",
1516                     dialog->finishing_table,
1517                     dialog->finishing_page);
1518 
1519   setup_page_table (dialog->options,
1520                     "ColorPage",
1521                     dialog->color_table,
1522                     dialog->color_page);
1523 
1524   gtk_printer_option_set_foreach_in_group (dialog->options,
1525                                            "GtkPrintDialogExtension",
1526                                            add_option_to_extension_point,
1527                                            dialog->extension_point);
1528 
1529   /* A bit of a hack, keep the last option flush right.
1530    * This keeps the file format radios from moving as the
1531    * filename changes.
1532    */
1533   child = gtk_widget_get_last_child (dialog->extension_point);
1534   if (child && child != gtk_widget_get_first_child (dialog->extension_point))
1535     gtk_widget_set_halign (child, GTK_ALIGN_END);
1536 
1537   /* Put the rest of the groups in the advanced page */
1538   groups = gtk_printer_option_set_get_groups (dialog->options);
1539 
1540   has_advanced = FALSE;
1541   for (l = groups; l != NULL; l = l->next)
1542     {
1543       group = l->data;
1544 
1545       if (group == NULL)
1546         continue;
1547 
1548       if (strcmp (group, "ImageQualityPage") == 0 ||
1549           strcmp (group, "ColorPage") == 0 ||
1550           strcmp (group, "FinishingPage") == 0 ||
1551           strcmp (group, "GtkPrintDialogExtension") == 0)
1552         continue;
1553 
1554       table = gtk_grid_new ();
1555       gtk_grid_set_row_spacing (GTK_GRID (table), 6);
1556       gtk_grid_set_column_spacing (GTK_GRID (table), 12);
1557 
1558       gtk_printer_option_set_foreach_in_group (dialog->options,
1559                                                group,
1560                                                add_option_to_table,
1561                                                table);
1562 
1563       nrows = grid_rows (GTK_GRID (table));
1564       if (nrows == 0)
1565         {
1566           g_object_unref (g_object_ref_sink (table));
1567         }
1568       else
1569         {
1570           has_advanced = TRUE;
1571           frame = wrap_in_frame (group, table);
1572           gtk_box_append (GTK_BOX (dialog->advanced_vbox), frame);
1573         }
1574     }
1575 
1576   if (has_advanced)
1577     gtk_widget_show (dialog->advanced_page);
1578   else
1579     gtk_widget_hide (dialog->advanced_page);
1580 
1581   g_list_free_full (groups, g_free);
1582 }
1583 
1584 static void
update_dialog_from_capabilities(GtkPrintUnixDialog * dialog)1585 update_dialog_from_capabilities (GtkPrintUnixDialog *dialog)
1586 {
1587   GtkPrintCapabilities caps;
1588   gboolean can_collate;
1589   const char *copies;
1590   GtkWidget *button;
1591 
1592   copies = gtk_editable_get_text (GTK_EDITABLE (dialog->copies_spin));
1593   can_collate = (*copies != '\0' && atoi (copies) > 1);
1594 
1595   caps = dialog->manual_capabilities | dialog->printer_capabilities;
1596 
1597   gtk_widget_set_sensitive (dialog->page_set_combo,
1598                             caps & GTK_PRINT_CAPABILITY_PAGE_SET);
1599   gtk_widget_set_sensitive (dialog->copies_spin,
1600                             caps & GTK_PRINT_CAPABILITY_COPIES);
1601   gtk_widget_set_sensitive (dialog->collate_check,
1602                             can_collate &&
1603                             (caps & GTK_PRINT_CAPABILITY_COLLATE));
1604   gtk_widget_set_sensitive (dialog->reverse_check,
1605                             caps & GTK_PRINT_CAPABILITY_REVERSE);
1606   gtk_widget_set_sensitive (dialog->scale_spin,
1607                             caps & GTK_PRINT_CAPABILITY_SCALE);
1608   gtk_widget_set_sensitive (GTK_WIDGET (dialog->pages_per_sheet),
1609                             caps & GTK_PRINT_CAPABILITY_NUMBER_UP);
1610 
1611   button = gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_APPLY);
1612   gtk_widget_set_visible (button, (caps & GTK_PRINT_CAPABILITY_PREVIEW) != 0);
1613 
1614   update_collate_icon (NULL, dialog);
1615 }
1616 
1617 static gboolean
page_setup_is_equal(GtkPageSetup * a,GtkPageSetup * b)1618 page_setup_is_equal (GtkPageSetup *a,
1619                      GtkPageSetup *b)
1620 {
1621   return
1622     gtk_paper_size_is_equal (gtk_page_setup_get_paper_size (a),
1623                              gtk_page_setup_get_paper_size (b)) &&
1624     gtk_page_setup_get_top_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_top_margin (b, GTK_UNIT_MM) &&
1625     gtk_page_setup_get_bottom_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_bottom_margin (b, GTK_UNIT_MM) &&
1626     gtk_page_setup_get_left_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_left_margin (b, GTK_UNIT_MM) &&
1627     gtk_page_setup_get_right_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_right_margin (b, GTK_UNIT_MM);
1628 }
1629 
1630 static gboolean
page_setup_is_same_size(GtkPageSetup * a,GtkPageSetup * b)1631 page_setup_is_same_size (GtkPageSetup *a,
1632                          GtkPageSetup *b)
1633 {
1634   return gtk_paper_size_is_equal (gtk_page_setup_get_paper_size (a),
1635                                   gtk_page_setup_get_paper_size (b));
1636 }
1637 
1638 static gboolean
set_paper_size(GtkPrintUnixDialog * dialog,GtkPageSetup * page_setup,gboolean size_only,gboolean add_item)1639 set_paper_size (GtkPrintUnixDialog *dialog,
1640                 GtkPageSetup       *page_setup,
1641                 gboolean            size_only,
1642                 gboolean            add_item)
1643 {
1644   GListModel *model;
1645   GtkPageSetup *list_page_setup;
1646   guint i;
1647 
1648   if (!dialog->internal_page_setup_change)
1649     return TRUE;
1650 
1651   if (page_setup == NULL)
1652     return FALSE;
1653 
1654   model = gtk_drop_down_get_model (GTK_DROP_DOWN (dialog->paper_size_combo));
1655   for (i = 0; i < g_list_model_get_n_items (model); i++)
1656     {
1657       list_page_setup = g_list_model_get_item (model, i);
1658       if (list_page_setup == NULL)
1659         continue;
1660 
1661       if ((size_only && page_setup_is_same_size (page_setup, list_page_setup)) ||
1662           (!size_only && page_setup_is_equal (page_setup, list_page_setup)))
1663         {
1664           gtk_drop_down_set_selected (GTK_DROP_DOWN (dialog->paper_size_combo), i);
1665           gtk_drop_down_set_selected (GTK_DROP_DOWN (dialog->orientation_combo),
1666                                       gtk_page_setup_get_orientation (page_setup));
1667           g_object_unref (list_page_setup);
1668           return TRUE;
1669         }
1670 
1671       g_object_unref (list_page_setup);
1672     }
1673 
1674   if (add_item)
1675     {
1676       i = g_list_model_get_n_items (model);
1677       g_list_store_append (dialog->page_setup_list, page_setup);
1678       gtk_drop_down_set_selected (GTK_DROP_DOWN (dialog->paper_size_combo), i);
1679       gtk_drop_down_set_selected (GTK_DROP_DOWN (dialog->orientation_combo),
1680                                   gtk_page_setup_get_orientation (page_setup));
1681       return TRUE;
1682     }
1683 
1684   return FALSE;
1685 }
1686 
1687 static void
fill_custom_paper_sizes(GtkPrintUnixDialog * dialog)1688 fill_custom_paper_sizes (GtkPrintUnixDialog *dialog)
1689 {
1690   g_list_store_remove_all (dialog->custom_paper_list);
1691   gtk_print_load_custom_papers (dialog->custom_paper_list);
1692 }
1693 
1694 static void
fill_paper_sizes(GtkPrintUnixDialog * dialog,GtkPrinter * printer)1695 fill_paper_sizes (GtkPrintUnixDialog *dialog,
1696                   GtkPrinter         *printer)
1697 {
1698   GList *list, *l;
1699   GtkPageSetup *page_setup;
1700   GtkPaperSize *paper_size;
1701   int i;
1702 
1703   g_list_store_remove_all (dialog->page_setup_list);
1704 
1705   if (printer == NULL || (list = gtk_printer_list_papers (printer)) == NULL)
1706     {
1707       for (i = 0; i < G_N_ELEMENTS (common_paper_sizes); i++)
1708         {
1709           page_setup = gtk_page_setup_new ();
1710           paper_size = gtk_paper_size_new (common_paper_sizes[i]);
1711           gtk_page_setup_set_paper_size_and_default_margins (page_setup, paper_size);
1712           gtk_paper_size_free (paper_size);
1713           g_list_store_append (dialog->page_setup_list, page_setup);
1714           g_object_unref (page_setup);
1715         }
1716     }
1717   else
1718     {
1719       for (l = list; l != NULL; l = l->next)
1720         {
1721           page_setup = l->data;
1722           g_list_store_append (dialog->page_setup_list, page_setup);
1723           g_object_unref (page_setup);
1724         }
1725       g_list_free (list);
1726     }
1727 }
1728 
1729 static void
update_paper_sizes(GtkPrintUnixDialog * dialog)1730 update_paper_sizes (GtkPrintUnixDialog *dialog)
1731 {
1732   GtkPageSetup *current_page_setup = NULL;
1733   GtkPrinter   *printer;
1734 
1735   printer = gtk_print_unix_dialog_get_selected_printer (dialog);
1736 
1737   fill_paper_sizes (dialog, printer);
1738   fill_custom_paper_sizes (dialog);
1739 
1740   current_page_setup = gtk_page_setup_copy (gtk_print_unix_dialog_get_page_setup (dialog));
1741 
1742   if (current_page_setup)
1743     {
1744       if (!set_paper_size (dialog, current_page_setup, FALSE, FALSE))
1745         set_paper_size (dialog, current_page_setup, TRUE, TRUE);
1746 
1747       g_object_unref (current_page_setup);
1748     }
1749 }
1750 
1751 static void
mark_conflicts(GtkPrintUnixDialog * dialog)1752 mark_conflicts (GtkPrintUnixDialog *dialog)
1753 {
1754   GtkPrinter *printer;
1755   gboolean have_conflict;
1756 
1757   have_conflict = FALSE;
1758 
1759   printer = dialog->current_printer;
1760 
1761   if (printer)
1762     {
1763       g_signal_handler_block (dialog->options, dialog->options_changed_handler);
1764 
1765       gtk_printer_option_set_clear_conflicts (dialog->options);
1766       have_conflict = _gtk_printer_mark_conflicts (printer, dialog->options);
1767 
1768       g_signal_handler_unblock (dialog->options, dialog->options_changed_handler);
1769     }
1770 
1771   if (have_conflict)
1772     gtk_widget_show (dialog->conflicts_widget);
1773   else
1774     gtk_widget_hide (dialog->conflicts_widget);
1775 }
1776 
1777 static gboolean
mark_conflicts_callback(gpointer data)1778 mark_conflicts_callback (gpointer data)
1779 {
1780   GtkPrintUnixDialog *dialog = data;
1781 
1782   dialog->mark_conflicts_id = 0;
1783 
1784   mark_conflicts (dialog);
1785 
1786   return FALSE;
1787 }
1788 
1789 static void
unschedule_idle_mark_conflicts(GtkPrintUnixDialog * dialog)1790 unschedule_idle_mark_conflicts (GtkPrintUnixDialog *dialog)
1791 {
1792   if (dialog->mark_conflicts_id != 0)
1793     {
1794       g_source_remove (dialog->mark_conflicts_id);
1795       dialog->mark_conflicts_id = 0;
1796     }
1797 }
1798 
1799 static void
schedule_idle_mark_conflicts(GtkPrintUnixDialog * dialog)1800 schedule_idle_mark_conflicts (GtkPrintUnixDialog *dialog)
1801 {
1802   if (dialog->mark_conflicts_id != 0)
1803     return;
1804 
1805   dialog->mark_conflicts_id = g_idle_add (mark_conflicts_callback, dialog);
1806   gdk_source_set_static_name_by_id (dialog->mark_conflicts_id, "[gtk] mark_conflicts_callback");
1807 }
1808 
1809 static void
options_changed_cb(GtkPrintUnixDialog * dialog)1810 options_changed_cb (GtkPrintUnixDialog *dialog)
1811 {
1812   schedule_idle_mark_conflicts (dialog);
1813 
1814   g_free (dialog->waiting_for_printer);
1815   dialog->waiting_for_printer = NULL;
1816 }
1817 
1818 static void
clear_per_printer_ui(GtkPrintUnixDialog * dialog)1819 clear_per_printer_ui (GtkPrintUnixDialog *dialog)
1820 {
1821   GtkWidget *child;
1822 
1823   if (dialog->finishing_table == NULL)
1824     return;
1825 
1826   while ((child = gtk_widget_get_first_child (dialog->finishing_table)))
1827     gtk_grid_remove (GTK_GRID (dialog->finishing_table), child);
1828   while ((child = gtk_widget_get_first_child (dialog->image_quality_table)))
1829     gtk_grid_remove (GTK_GRID (dialog->image_quality_table), child);
1830   while ((child = gtk_widget_get_first_child (dialog->color_table)))
1831     gtk_grid_remove (GTK_GRID (dialog->color_table), child);
1832   while ((child = gtk_widget_get_first_child (dialog->advanced_vbox)))
1833     gtk_box_remove (GTK_BOX (dialog->advanced_vbox), child);
1834   while ((child = gtk_widget_get_first_child (dialog->extension_point)))
1835     gtk_box_remove (GTK_BOX (dialog->extension_point), child);
1836 }
1837 
1838 static void
printer_details_acquired(GtkPrinter * printer,gboolean success,GtkPrintUnixDialog * dialog)1839 printer_details_acquired (GtkPrinter         *printer,
1840                           gboolean            success,
1841                           GtkPrintUnixDialog *dialog)
1842 {
1843   disconnect_printer_details_request (dialog, !success);
1844 
1845   if (success)
1846     selected_printer_changed (dialog);
1847 }
1848 
1849 static void
selected_printer_changed(GtkPrintUnixDialog * dialog)1850 selected_printer_changed (GtkPrintUnixDialog *dialog)
1851 {
1852   GListModel *model = G_LIST_MODEL (gtk_column_view_get_model (GTK_COLUMN_VIEW (dialog->printer_list)));
1853   GtkPrinter *printer;
1854 
1855   /* Whenever the user selects a printer we stop looking for
1856    * the printer specified in the initial settings
1857    */
1858   if (dialog->waiting_for_printer &&
1859       !dialog->internal_printer_change)
1860     {
1861       g_free (dialog->waiting_for_printer);
1862       dialog->waiting_for_printer = NULL;
1863     }
1864 
1865   disconnect_printer_details_request (dialog, FALSE);
1866 
1867   printer = gtk_single_selection_get_selected_item (GTK_SINGLE_SELECTION (model));
1868 
1869   /* sets GTK_RESPONSE_OK button sensitivity depending on whether the printer
1870    * accepts/rejects jobs
1871    */
1872   if (printer != NULL)
1873     {
1874       if (!gtk_printer_is_accepting_jobs (printer))
1875         gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
1876       else if (dialog->current_printer == printer && gtk_printer_has_details (printer))
1877         gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
1878     }
1879 
1880   if (printer != NULL && !gtk_printer_has_details (printer))
1881     {
1882       gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
1883       dialog->request_details_tag = g_signal_connect (printer, "details-acquired",
1884                                                       G_CALLBACK (printer_details_acquired), dialog);
1885 
1886       dialog->request_details_printer = g_object_ref (printer);
1887       set_busy_cursor (dialog, TRUE);
1888       gtk_printer_set_state_message (printer, _("Getting printer information…"));
1889       gtk_printer_request_details (printer);
1890       return;
1891     }
1892 
1893   if (printer == dialog->current_printer)
1894     return;
1895 
1896   if (dialog->options)
1897     {
1898       g_clear_object (&dialog->options);
1899       clear_per_printer_ui (dialog);
1900     }
1901 
1902   g_clear_object (&dialog->current_printer);
1903   dialog->printer_capabilities = 0;
1904 
1905   if (printer != NULL && gtk_printer_is_accepting_jobs (printer))
1906     gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
1907   dialog->current_printer = g_object_ref (printer);
1908 
1909   if (printer != NULL)
1910     {
1911       if (!dialog->page_setup_set)
1912         {
1913           /* if no explicit page setup has been set, use the printer default */
1914           GtkPageSetup *page_setup;
1915 
1916           page_setup = gtk_printer_get_default_page_size (printer);
1917 
1918           if (!page_setup)
1919             page_setup = gtk_page_setup_new ();
1920 
1921           if (page_setup && dialog->page_setup)
1922             gtk_page_setup_set_orientation (page_setup, gtk_page_setup_get_orientation (dialog->page_setup));
1923 
1924           g_clear_object (&dialog->page_setup);
1925           dialog->page_setup = page_setup; /* transfer ownership */
1926         }
1927 
1928       dialog->printer_capabilities = gtk_printer_get_capabilities (printer);
1929       dialog->options = _gtk_printer_get_options (printer,
1930                                                 dialog->initial_settings,
1931                                                 dialog->page_setup,
1932                                                 dialog->manual_capabilities);
1933 
1934       dialog->options_changed_handler =
1935         g_signal_connect_swapped (dialog->options, "changed", G_CALLBACK (options_changed_cb), dialog);
1936       schedule_idle_mark_conflicts (dialog);
1937     }
1938 
1939   update_dialog_from_settings (dialog);
1940   update_dialog_from_capabilities (dialog);
1941 
1942   dialog->internal_page_setup_change = TRUE;
1943   update_paper_sizes (dialog);
1944   dialog->internal_page_setup_change = FALSE;
1945 
1946   g_object_notify (G_OBJECT (dialog), "selected-printer");
1947 }
1948 
1949 static void
update_collate_icon(GtkToggleButton * toggle_button,GtkPrintUnixDialog * dialog)1950 update_collate_icon (GtkToggleButton    *toggle_button,
1951                      GtkPrintUnixDialog *dialog)
1952 {
1953   gtk_widget_queue_draw (dialog->collate_image);
1954 }
1955 
1956 static void
paint_page(GtkPrintUnixDialog * dialog,GtkWidget * widget,cairo_t * cr,int x,int y,const char * text,int text_x)1957 paint_page (GtkPrintUnixDialog *dialog,
1958             GtkWidget  *widget,
1959             cairo_t    *cr,
1960             int         x,
1961             int         y,
1962             const char *text,
1963             int         text_x)
1964 {
1965   GtkStyleContext *context;
1966   int width, height;
1967   int text_y;
1968   GdkRGBA color;
1969 
1970   width = 20;
1971   height = 26;
1972   text_y = 21;
1973 
1974   context = gtk_widget_get_style_context (widget);
1975   gtk_style_context_save_to_node (context, dialog->collate_paper_node);
1976 
1977   gtk_render_background (context, cr, x, y, width, height);
1978   gtk_render_frame (context, cr, x, y, width, height);
1979 
1980   gtk_style_context_get_color (context, &color);
1981   cairo_set_source_rgba (cr, color.red, color.green, color.blue, color.alpha);
1982 
1983   cairo_select_font_face (cr, "Sans",
1984                           CAIRO_FONT_SLANT_NORMAL,
1985                           CAIRO_FONT_WEIGHT_NORMAL);
1986   cairo_set_font_size (cr, 9);
1987   cairo_move_to (cr, x + text_x, y + text_y);
1988   cairo_show_text (cr, text);
1989 
1990   gtk_style_context_restore (context);
1991 }
1992 
1993 static void
draw_collate(GtkDrawingArea * da,cairo_t * cr,int width,int height,gpointer data)1994 draw_collate (GtkDrawingArea *da,
1995               cairo_t        *cr,
1996               int             width,
1997               int             height,
1998               gpointer        data)
1999 {
2000   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (data);
2001   GtkWidget *widget = GTK_WIDGET (da);
2002   gboolean collate, reverse, rtl;
2003   int copies;
2004   int text_x;
2005   int x, y, x1, x2, p1, p2;
2006 
2007   collate = dialog_get_collate (dialog);
2008   reverse = dialog_get_reverse (dialog);
2009   copies = dialog_get_n_copies (dialog);
2010 
2011   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2012 
2013   x = (width - 30) / 2;
2014   y = (height - 36) / 2;
2015   if (rtl)
2016     {
2017       x1 = x;
2018       x2 = x - 36;
2019       p1 = 0;
2020       p2 = 10;
2021       text_x = 4;
2022     }
2023   else
2024     {
2025       x1 = x;
2026       x2 = x + 36;
2027       p1 = 10;
2028       p2 = 0;
2029       text_x = 11;
2030     }
2031 
2032   if (copies == 1)
2033     {
2034       paint_page (dialog, widget, cr, x1 + p1, y, reverse ? "1" : "2", text_x);
2035       paint_page (dialog, widget, cr, x1 + p2, y + 10, reverse ? "2" : "1", text_x);
2036     }
2037   else
2038     {
2039       paint_page (dialog, widget, cr, x1 + p1, y, collate == reverse ? "1" : "2", text_x);
2040       paint_page (dialog, widget, cr, x1 + p2, y + 10, reverse ? "2" : "1", text_x);
2041 
2042       paint_page (dialog, widget, cr, x2 + p1, y, reverse ? "1" : "2", text_x);
2043       paint_page (dialog, widget, cr, x2 + p2, y + 10, collate == reverse ? "2" : "1", text_x);
2044     }
2045 }
2046 
2047 static gboolean
page_range_entry_focus_changed(GtkWidget * entry,GParamSpec * pspec,GtkPrintUnixDialog * dialog)2048 page_range_entry_focus_changed (GtkWidget          *entry,
2049                                 GParamSpec         *pspec,
2050                                 GtkPrintUnixDialog *dialog)
2051 {
2052   if (gtk_widget_has_focus (entry))
2053     gtk_check_button_set_active (GTK_CHECK_BUTTON (dialog->page_range_radio), TRUE);
2054 
2055   return FALSE;
2056 }
2057 
2058 static void
update_page_range_entry_sensitivity(GtkWidget * button,GtkPrintUnixDialog * dialog)2059 update_page_range_entry_sensitivity (GtkWidget *button,
2060 				     GtkPrintUnixDialog *dialog)
2061 {
2062   gboolean active;
2063 
2064   active = gtk_check_button_get_active (GTK_CHECK_BUTTON (button));
2065 
2066   if (active)
2067     gtk_widget_grab_focus (dialog->page_range_entry);
2068 }
2069 
2070 static void
update_print_at_entry_sensitivity(GtkWidget * button,GtkPrintUnixDialog * dialog)2071 update_print_at_entry_sensitivity (GtkWidget *button,
2072 				   GtkPrintUnixDialog *dialog)
2073 {
2074   gboolean active;
2075 
2076   active = gtk_check_button_get_active (GTK_CHECK_BUTTON (button));
2077 
2078   gtk_widget_set_sensitive (dialog->print_at_entry, active);
2079 
2080   if (active)
2081     gtk_widget_grab_focus (dialog->print_at_entry);
2082 }
2083 
2084 static gboolean
is_range_separator(char c)2085 is_range_separator (char c)
2086 {
2087   return (c == ',' || c == ';' || c == ':');
2088 }
2089 
2090 static GtkPageRange *
dialog_get_page_ranges(GtkPrintUnixDialog * dialog,int * n_ranges_out)2091 dialog_get_page_ranges (GtkPrintUnixDialog *dialog,
2092                         int                *n_ranges_out)
2093 {
2094   int i, n_ranges;
2095   const char *text, *p;
2096   char *next;
2097   GtkPageRange *ranges;
2098   int start, end;
2099 
2100   text = gtk_editable_get_text (GTK_EDITABLE (dialog->page_range_entry));
2101 
2102   if (*text == 0)
2103     {
2104       *n_ranges_out = 0;
2105       return NULL;
2106     }
2107 
2108   n_ranges = 1;
2109   p = text;
2110   while (*p)
2111     {
2112       if (is_range_separator (*p))
2113         n_ranges++;
2114       p++;
2115     }
2116 
2117   ranges = g_new0 (GtkPageRange, n_ranges);
2118 
2119   i = 0;
2120   p = text;
2121   while (*p)
2122     {
2123       while (isspace (*p)) p++;
2124 
2125       if (*p == '-')
2126         {
2127           /* a half-open range like -2 */
2128           start = 1;
2129         }
2130       else
2131         {
2132           start = (int)strtol (p, &next, 10);
2133           if (start < 1)
2134             start = 1;
2135           p = next;
2136         }
2137 
2138       end = start;
2139 
2140       while (isspace (*p)) p++;
2141 
2142       if (*p == '-')
2143         {
2144           p++;
2145           end = (int)strtol (p, &next, 10);
2146           if (next == p) /* a half-open range like 2- */
2147             end = 0;
2148           else if (end < start)
2149             end = start;
2150         }
2151 
2152       ranges[i].start = start - 1;
2153       ranges[i].end = end - 1;
2154       i++;
2155 
2156       /* Skip until end or separator */
2157       while (*p && !is_range_separator (*p))
2158         p++;
2159 
2160       /* if not at end, skip separator */
2161       if (*p)
2162         p++;
2163     }
2164 
2165   *n_ranges_out = i;
2166 
2167   return ranges;
2168 }
2169 
2170 static void
dialog_set_page_ranges(GtkPrintUnixDialog * dialog,GtkPageRange * ranges,int n_ranges)2171 dialog_set_page_ranges (GtkPrintUnixDialog *dialog,
2172                         GtkPageRange       *ranges,
2173                         int                 n_ranges)
2174 {
2175   int i;
2176   GString *s = g_string_new (NULL);
2177 
2178   for (i = 0; i < n_ranges; i++)
2179     {
2180       g_string_append_printf (s, "%d", ranges[i].start + 1);
2181       if (ranges[i].end > ranges[i].start)
2182         g_string_append_printf (s, "-%d", ranges[i].end + 1);
2183       else if (ranges[i].end == -1)
2184         g_string_append (s, "-");
2185 
2186       if (i != n_ranges - 1)
2187         g_string_append (s, ",");
2188     }
2189 
2190   gtk_editable_set_text (GTK_EDITABLE (dialog->page_range_entry), s->str);
2191 
2192   g_string_free (s, TRUE);
2193 }
2194 
2195 static GtkPrintPages
dialog_get_print_pages(GtkPrintUnixDialog * dialog)2196 dialog_get_print_pages (GtkPrintUnixDialog *dialog)
2197 {
2198   if (gtk_check_button_get_active (GTK_CHECK_BUTTON (dialog->all_pages_radio)))
2199     return GTK_PRINT_PAGES_ALL;
2200   else if (gtk_check_button_get_active (GTK_CHECK_BUTTON (dialog->current_page_radio)))
2201     return GTK_PRINT_PAGES_CURRENT;
2202   else if (gtk_check_button_get_active (GTK_CHECK_BUTTON (dialog->selection_radio)))
2203     return GTK_PRINT_PAGES_SELECTION;
2204   else
2205     return GTK_PRINT_PAGES_RANGES;
2206 }
2207 
2208 static void
dialog_set_print_pages(GtkPrintUnixDialog * dialog,GtkPrintPages pages)2209 dialog_set_print_pages (GtkPrintUnixDialog *dialog,
2210                         GtkPrintPages       pages)
2211 {
2212   if (pages == GTK_PRINT_PAGES_RANGES)
2213     gtk_check_button_set_active (GTK_CHECK_BUTTON (dialog->page_range_radio), TRUE);
2214   else if (pages == GTK_PRINT_PAGES_CURRENT)
2215     gtk_check_button_set_active (GTK_CHECK_BUTTON (dialog->current_page_radio), TRUE);
2216   else if (pages == GTK_PRINT_PAGES_SELECTION)
2217     gtk_check_button_set_active (GTK_CHECK_BUTTON (dialog->selection_radio), TRUE);
2218   else
2219     gtk_check_button_set_active (GTK_CHECK_BUTTON (dialog->all_pages_radio), TRUE);
2220 }
2221 
2222 static double
dialog_get_scale(GtkPrintUnixDialog * dialog)2223 dialog_get_scale (GtkPrintUnixDialog *dialog)
2224 {
2225   if (gtk_widget_is_sensitive (dialog->scale_spin))
2226     return gtk_spin_button_get_value (GTK_SPIN_BUTTON (dialog->scale_spin));
2227   else
2228     return 100.0;
2229 }
2230 
2231 static void
dialog_set_scale(GtkPrintUnixDialog * dialog,double val)2232 dialog_set_scale (GtkPrintUnixDialog *dialog,
2233                   double              val)
2234 {
2235   gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->scale_spin), val);
2236 }
2237 
2238 static GtkPageSet
dialog_get_page_set(GtkPrintUnixDialog * dialog)2239 dialog_get_page_set (GtkPrintUnixDialog *dialog)
2240 {
2241   if (gtk_widget_is_sensitive (dialog->page_set_combo))
2242     return (GtkPageSet)gtk_drop_down_get_selected (GTK_DROP_DOWN (dialog->page_set_combo));
2243   else
2244     return GTK_PAGE_SET_ALL;
2245 }
2246 
2247 static void
dialog_set_page_set(GtkPrintUnixDialog * dialog,GtkPageSet val)2248 dialog_set_page_set (GtkPrintUnixDialog *dialog,
2249                      GtkPageSet          val)
2250 {
2251   gtk_drop_down_set_selected (GTK_DROP_DOWN (dialog->page_set_combo), (guint)val);
2252 }
2253 
2254 static int
dialog_get_n_copies(GtkPrintUnixDialog * dialog)2255 dialog_get_n_copies (GtkPrintUnixDialog *dialog)
2256 {
2257   GtkAdjustment *adjustment;
2258   const char *text;
2259   char *endptr = NULL;
2260   int n_copies;
2261 
2262   adjustment = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (dialog->copies_spin));
2263 
2264   text = gtk_editable_get_text (GTK_EDITABLE (dialog->copies_spin));
2265   n_copies = g_ascii_strtoull (text, &endptr, 0);
2266 
2267   if (gtk_widget_is_sensitive (dialog->copies_spin))
2268     {
2269       if (n_copies != 0 && endptr != text && (endptr != NULL && endptr[0] == '\0') &&
2270           n_copies >= gtk_adjustment_get_lower (adjustment) &&
2271           n_copies <= gtk_adjustment_get_upper (adjustment))
2272         {
2273           return n_copies;
2274         }
2275 
2276       return gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->copies_spin));
2277     }
2278 
2279   return 1;
2280 }
2281 
2282 static void
dialog_set_n_copies(GtkPrintUnixDialog * dialog,int n_copies)2283 dialog_set_n_copies (GtkPrintUnixDialog *dialog,
2284                      int                 n_copies)
2285 {
2286   gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->copies_spin), n_copies);
2287 }
2288 
2289 static gboolean
dialog_get_collate(GtkPrintUnixDialog * dialog)2290 dialog_get_collate (GtkPrintUnixDialog *dialog)
2291 {
2292   if (gtk_widget_is_sensitive (dialog->collate_check))
2293     return gtk_check_button_get_active (GTK_CHECK_BUTTON (dialog->collate_check));
2294   return FALSE;
2295 }
2296 
2297 static void
dialog_set_collate(GtkPrintUnixDialog * dialog,gboolean collate)2298 dialog_set_collate (GtkPrintUnixDialog *dialog,
2299                     gboolean            collate)
2300 {
2301   gtk_check_button_set_active (GTK_CHECK_BUTTON (dialog->collate_check), collate);
2302 }
2303 
2304 static gboolean
dialog_get_reverse(GtkPrintUnixDialog * dialog)2305 dialog_get_reverse (GtkPrintUnixDialog *dialog)
2306 {
2307   if (gtk_widget_is_sensitive (dialog->reverse_check))
2308     return gtk_check_button_get_active (GTK_CHECK_BUTTON (dialog->reverse_check));
2309   return FALSE;
2310 }
2311 
2312 static void
dialog_set_reverse(GtkPrintUnixDialog * dialog,gboolean reverse)2313 dialog_set_reverse (GtkPrintUnixDialog *dialog,
2314                     gboolean            reverse)
2315 {
2316   gtk_check_button_set_active (GTK_CHECK_BUTTON (dialog->reverse_check), reverse);
2317 }
2318 
2319 static int
dialog_get_pages_per_sheet(GtkPrintUnixDialog * dialog)2320 dialog_get_pages_per_sheet (GtkPrintUnixDialog *dialog)
2321 {
2322   const char *val;
2323   int num;
2324 
2325   val = gtk_printer_option_widget_get_value (dialog->pages_per_sheet);
2326 
2327   num = 1;
2328 
2329   if (val)
2330     {
2331       num = atoi(val);
2332       if (num < 1)
2333         num = 1;
2334     }
2335 
2336   return num;
2337 }
2338 
2339 static GtkNumberUpLayout
dialog_get_number_up_layout(GtkPrintUnixDialog * dialog)2340 dialog_get_number_up_layout (GtkPrintUnixDialog *dialog)
2341 {
2342   GtkPrintCapabilities       caps;
2343   GtkNumberUpLayout          layout;
2344   const char                *val;
2345   GEnumClass                *enum_class;
2346   GEnumValue                *enum_value;
2347 
2348   val = gtk_printer_option_widget_get_value (dialog->number_up_layout);
2349 
2350   caps = dialog->manual_capabilities | dialog->printer_capabilities;
2351 
2352   if ((caps & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT) == 0)
2353     return GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
2354 
2355   if (gtk_widget_get_direction (GTK_WIDGET (dialog)) == GTK_TEXT_DIR_LTR)
2356     layout = GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
2357   else
2358     layout = GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM;
2359 
2360   if (val == NULL)
2361     return layout;
2362 
2363   if (val[0] == '\0' && dialog->options)
2364     {
2365       GtkPrinterOption *option = gtk_printer_option_set_lookup (dialog->options, "gtk-n-up-layout");
2366       if (option)
2367         val = option->value;
2368     }
2369 
2370   enum_class = g_type_class_ref (GTK_TYPE_NUMBER_UP_LAYOUT);
2371   enum_value = g_enum_get_value_by_nick (enum_class, val);
2372   if (enum_value)
2373     layout = enum_value->value;
2374   g_type_class_unref (enum_class);
2375 
2376   return layout;
2377 }
2378 
2379 static void
draw_page(GtkDrawingArea * da,cairo_t * cr,int width,int height,gpointer data)2380 draw_page (GtkDrawingArea *da,
2381            cairo_t        *cr,
2382            int             width,
2383            int             height,
2384            gpointer        data)
2385 {
2386   GtkWidget *widget = GTK_WIDGET (da);
2387   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (data);
2388   GtkStyleContext *context;
2389   double ratio;
2390   int w, h, tmp;
2391   int pages_x, pages_y, i, x, y, layout_w, layout_h;
2392   double page_width, page_height;
2393   GtkPageOrientation orientation;
2394   gboolean landscape;
2395   PangoLayout *layout;
2396   PangoFontDescription *font;
2397   char *text;
2398   GdkRGBA color;
2399   GtkNumberUpLayout number_up_layout;
2400   int start_x, end_x, start_y, end_y;
2401   int dx, dy;
2402   gboolean horizontal;
2403   GtkPageSetup *page_setup;
2404   double paper_width, paper_height;
2405   double pos_x, pos_y;
2406   int pages_per_sheet;
2407   gboolean ltr = TRUE;
2408 
2409   orientation = gtk_page_setup_get_orientation (dialog->page_setup);
2410   landscape =
2411     (orientation == GTK_PAGE_ORIENTATION_LANDSCAPE) ||
2412     (orientation == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE);
2413 
2414   number_up_layout = dialog_get_number_up_layout (dialog);
2415 
2416   cairo_save (cr);
2417 
2418   page_setup = gtk_print_unix_dialog_get_page_setup (dialog);
2419 
2420   if (page_setup != NULL)
2421     {
2422       if (!landscape)
2423         {
2424           paper_width = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM);
2425           paper_height = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM);
2426         }
2427       else
2428         {
2429           paper_width = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM);
2430           paper_height = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM);
2431         }
2432 
2433       if (paper_width < paper_height)
2434         {
2435           h = EXAMPLE_PAGE_AREA_SIZE - 3;
2436           w = (paper_height != 0) ? h * paper_width / paper_height : 0;
2437         }
2438       else
2439         {
2440           w = EXAMPLE_PAGE_AREA_SIZE - 3;
2441           h = (paper_width != 0) ? w * paper_height / paper_width : 0;
2442         }
2443 
2444       if (paper_width == 0)
2445         w = 0;
2446 
2447       if (paper_height == 0)
2448         h = 0;
2449     }
2450   else
2451     {
2452       ratio = G_SQRT2;
2453       w = (EXAMPLE_PAGE_AREA_SIZE - 3) / ratio;
2454       h = EXAMPLE_PAGE_AREA_SIZE - 3;
2455     }
2456 
2457   pages_per_sheet = dialog_get_pages_per_sheet (dialog);
2458   switch (pages_per_sheet)
2459     {
2460     default:
2461     case 1:
2462       pages_x = 1; pages_y = 1;
2463       break;
2464     case 2:
2465       landscape = !landscape;
2466       pages_x = 1; pages_y = 2;
2467       break;
2468     case 4:
2469       pages_x = 2; pages_y = 2;
2470       break;
2471     case 6:
2472       landscape = !landscape;
2473       pages_x = 2; pages_y = 3;
2474       break;
2475     case 9:
2476       pages_x = 3; pages_y = 3;
2477       break;
2478     case 16:
2479       pages_x = 4; pages_y = 4;
2480       break;
2481     }
2482 
2483   if (landscape)
2484     {
2485       tmp = w;
2486       w = h;
2487       h = tmp;
2488 
2489       tmp = pages_x;
2490       pages_x = pages_y;
2491       pages_y = tmp;
2492     }
2493 
2494   context = gtk_widget_get_style_context (widget);
2495   gtk_style_context_save_to_node (context, dialog->page_layout_paper_node);
2496   gtk_style_context_get_color (context, &color);
2497 
2498   pos_x = (width - w) / 2;
2499   pos_y = (height - h) / 2 - 10;
2500   cairo_translate (cr, pos_x, pos_y);
2501 
2502   gtk_render_background (context, cr, 1, 1, w, h);
2503   gtk_render_frame (context, cr, 1, 1, w, h);
2504 
2505   cairo_set_line_width (cr, 1.0);
2506 
2507   i = 1;
2508 
2509   page_width = (double)w / pages_x;
2510   page_height = (double)h / pages_y;
2511 
2512   layout  = pango_cairo_create_layout (cr);
2513 
2514   font = pango_font_description_new ();
2515   pango_font_description_set_family (font, "sans");
2516 
2517   if (page_height > 0)
2518     pango_font_description_set_absolute_size (font, page_height * 0.4 * PANGO_SCALE);
2519   else
2520     pango_font_description_set_absolute_size (font, 1);
2521 
2522   pango_layout_set_font_description (layout, font);
2523   pango_font_description_free (font);
2524 
2525   pango_layout_set_width (layout, page_width * PANGO_SCALE);
2526   pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
2527 
2528   switch (number_up_layout)
2529     {
2530       default:
2531       case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM:
2532         start_x = 0;
2533         end_x = pages_x - 1;
2534         start_y = 0;
2535         end_y = pages_y - 1;
2536         dx = 1;
2537         dy = 1;
2538         horizontal = TRUE;
2539         break;
2540       case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP:
2541         start_x = 0;
2542         end_x = pages_x - 1;
2543         start_y = pages_y - 1;
2544         end_y = 0;
2545         dx = 1;
2546         dy = - 1;
2547         horizontal = TRUE;
2548         break;
2549       case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM:
2550         start_x = pages_x - 1;
2551         end_x = 0;
2552         start_y = 0;
2553         end_y = pages_y - 1;
2554         dx = - 1;
2555         dy = 1;
2556         horizontal = TRUE;
2557         break;
2558       case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP:
2559         start_x = pages_x - 1;
2560         end_x = 0;
2561         start_y = pages_y - 1;
2562         end_y = 0;
2563         dx = - 1;
2564         dy = - 1;
2565         horizontal = TRUE;
2566         break;
2567       case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT:
2568         start_x = 0;
2569         end_x = pages_x - 1;
2570         start_y = 0;
2571         end_y = pages_y - 1;
2572         dx = 1;
2573         dy = 1;
2574         horizontal = FALSE;
2575         break;
2576       case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_RIGHT_TO_LEFT:
2577         start_x = pages_x - 1;
2578         end_x = 0;
2579         start_y = 0;
2580         end_y = pages_y - 1;
2581         dx = - 1;
2582         dy = 1;
2583         horizontal = FALSE;
2584         break;
2585       case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT:
2586         start_x = 0;
2587         end_x = pages_x - 1;
2588         start_y = pages_y - 1;
2589         end_y = 0;
2590         dx = 1;
2591         dy = - 1;
2592         horizontal = FALSE;
2593         break;
2594       case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_RIGHT_TO_LEFT:
2595         start_x = pages_x - 1;
2596         end_x = 0;
2597         start_y = pages_y - 1;
2598         end_y = 0;
2599         dx = - 1;
2600         dy = - 1;
2601         horizontal = FALSE;
2602         break;
2603     }
2604 
2605   cairo_set_source_rgba (cr, color.red, color.green, color.blue, color.alpha);
2606   if (horizontal)
2607     for (y = start_y; y != end_y + dy; y += dy)
2608       {
2609         for (x = start_x; x != end_x + dx; x += dx)
2610           {
2611             text = g_strdup_printf ("%d", i++);
2612             pango_layout_set_text (layout, text, -1);
2613             g_free (text);
2614             pango_layout_get_size (layout, &layout_w, &layout_h);
2615             cairo_save (cr);
2616             cairo_translate (cr,
2617                              x * page_width,
2618                              y * page_height + (page_height - layout_h / 1024.0) / 2);
2619 
2620             pango_cairo_show_layout (cr, layout);
2621             cairo_restore (cr);
2622           }
2623       }
2624   else
2625     for (x = start_x; x != end_x + dx; x += dx)
2626       {
2627         for (y = start_y; y != end_y + dy; y += dy)
2628           {
2629             text = g_strdup_printf ("%d", i++);
2630             pango_layout_set_text (layout, text, -1);
2631             g_free (text);
2632             pango_layout_get_size (layout, &layout_w, &layout_h);
2633             cairo_save (cr);
2634             cairo_translate (cr,
2635                              x * page_width,
2636                              y * page_height + (page_height - layout_h / 1024.0) / 2);
2637 
2638             pango_cairo_show_layout (cr, layout);
2639             cairo_restore (cr);
2640           }
2641       }
2642 
2643   g_object_unref (layout);
2644 
2645   gtk_style_context_restore (context);
2646 
2647   gtk_style_context_get_color (context, &color);
2648 
2649   if (page_setup != NULL)
2650     {
2651       PangoContext *pango_c = NULL;
2652       PangoFontDescription *pango_f = NULL;
2653       int font_size = 12 * PANGO_SCALE;
2654 
2655       pos_x += 1;
2656       pos_y += 1;
2657 
2658       if (pages_per_sheet == 2 || pages_per_sheet == 6)
2659         {
2660           paper_width = gtk_page_setup_get_paper_height (page_setup, _gtk_print_get_default_user_units ());
2661           paper_height = gtk_page_setup_get_paper_width (page_setup, _gtk_print_get_default_user_units ());
2662         }
2663       else
2664         {
2665           paper_width = gtk_page_setup_get_paper_width (page_setup, _gtk_print_get_default_user_units ());
2666           paper_height = gtk_page_setup_get_paper_height (page_setup, _gtk_print_get_default_user_units ());
2667         }
2668 
2669       cairo_restore (cr);
2670       cairo_save (cr);
2671 
2672       layout = pango_cairo_create_layout (cr);
2673 
2674       font = pango_font_description_new ();
2675       pango_font_description_set_family (font, "sans");
2676 
2677       pango_c = gtk_widget_get_pango_context (widget);
2678       if (pango_c != NULL)
2679         {
2680           pango_f = pango_context_get_font_description (pango_c);
2681           if (pango_f != NULL)
2682             font_size = pango_font_description_get_size (pango_f);
2683         }
2684 
2685       pango_font_description_set_size (font, font_size);
2686       pango_layout_set_font_description (layout, font);
2687       pango_font_description_free (font);
2688 
2689       pango_layout_set_width (layout, -1);
2690       pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
2691 
2692       if (_gtk_print_get_default_user_units () == GTK_UNIT_MM)
2693         text = g_strdup_printf ("%.1f mm", paper_height);
2694       else
2695         text = g_strdup_printf ("%.2f inch", paper_height);
2696 
2697       pango_layout_set_text (layout, text, -1);
2698       g_free (text);
2699       pango_layout_get_size (layout, &layout_w, &layout_h);
2700 
2701       ltr = gtk_widget_get_direction (GTK_WIDGET (dialog)) == GTK_TEXT_DIR_LTR;
2702 
2703       if (ltr)
2704         cairo_translate (cr, pos_x - layout_w / PANGO_SCALE - 2 * RULER_DISTANCE,
2705                              (height - layout_h / PANGO_SCALE) / 2);
2706       else
2707         cairo_translate (cr, pos_x + w + 2 * RULER_DISTANCE,
2708                              (height - layout_h / PANGO_SCALE) / 2);
2709 
2710       gdk_cairo_set_source_rgba (cr, &color);
2711       pango_cairo_show_layout (cr, layout);
2712 
2713       cairo_restore (cr);
2714       cairo_save (cr);
2715 
2716       if (_gtk_print_get_default_user_units () == GTK_UNIT_MM)
2717         text = g_strdup_printf ("%.1f mm", paper_width);
2718       else
2719         text = g_strdup_printf ("%.2f inch", paper_width);
2720 
2721       pango_layout_set_text (layout, text, -1);
2722       g_free (text);
2723       pango_layout_get_size (layout, &layout_w, &layout_h);
2724 
2725       cairo_translate (cr, (width - layout_w / PANGO_SCALE) / 2,
2726                            pos_y + h + 2 * RULER_DISTANCE);
2727 
2728       gdk_cairo_set_source_rgba (cr, &color);
2729       pango_cairo_show_layout (cr, layout);
2730 
2731       g_object_unref (layout);
2732 
2733       cairo_restore (cr);
2734 
2735       cairo_set_line_width (cr, 1);
2736 
2737       gdk_cairo_set_source_rgba (cr, &color);
2738 
2739       if (ltr)
2740         {
2741           cairo_move_to (cr, pos_x - RULER_DISTANCE, pos_y);
2742           cairo_line_to (cr, pos_x - RULER_DISTANCE, pos_y + h);
2743           cairo_stroke (cr);
2744 
2745           cairo_move_to (cr, pos_x - RULER_DISTANCE - RULER_RADIUS, pos_y - 0.5);
2746           cairo_line_to (cr, pos_x - RULER_DISTANCE + RULER_RADIUS, pos_y - 0.5);
2747           cairo_stroke (cr);
2748 
2749           cairo_move_to (cr, pos_x - RULER_DISTANCE - RULER_RADIUS, pos_y + h + 0.5);
2750           cairo_line_to (cr, pos_x - RULER_DISTANCE + RULER_RADIUS, pos_y + h + 0.5);
2751           cairo_stroke (cr);
2752         }
2753       else
2754         {
2755           cairo_move_to (cr, pos_x + w + RULER_DISTANCE, pos_y);
2756           cairo_line_to (cr, pos_x + w + RULER_DISTANCE, pos_y + h);
2757           cairo_stroke (cr);
2758 
2759           cairo_move_to (cr, pos_x + w + RULER_DISTANCE - RULER_RADIUS, pos_y - 0.5);
2760           cairo_line_to (cr, pos_x + w + RULER_DISTANCE + RULER_RADIUS, pos_y - 0.5);
2761           cairo_stroke (cr);
2762 
2763           cairo_move_to (cr, pos_x + w + RULER_DISTANCE - RULER_RADIUS, pos_y + h + 0.5);
2764           cairo_line_to (cr, pos_x + w + RULER_DISTANCE + RULER_RADIUS, pos_y + h + 0.5);
2765           cairo_stroke (cr);
2766         }
2767 
2768       cairo_move_to (cr, pos_x, pos_y + h + RULER_DISTANCE);
2769       cairo_line_to (cr, pos_x + w, pos_y + h + RULER_DISTANCE);
2770       cairo_stroke (cr);
2771 
2772       cairo_move_to (cr, pos_x - 0.5, pos_y + h + RULER_DISTANCE - RULER_RADIUS);
2773       cairo_line_to (cr, pos_x - 0.5, pos_y + h + RULER_DISTANCE + RULER_RADIUS);
2774       cairo_stroke (cr);
2775 
2776       cairo_move_to (cr, pos_x + w + 0.5, pos_y + h + RULER_DISTANCE - RULER_RADIUS);
2777       cairo_line_to (cr, pos_x + w + 0.5, pos_y + h + RULER_DISTANCE + RULER_RADIUS);
2778       cairo_stroke (cr);
2779     }
2780 }
2781 
2782 static void
redraw_page_layout_preview(GtkPrintUnixDialog * dialog)2783 redraw_page_layout_preview (GtkPrintUnixDialog *dialog)
2784 {
2785   if (dialog->page_layout_preview)
2786     gtk_widget_queue_draw (dialog->page_layout_preview);
2787 }
2788 
2789 static void
update_number_up_layout(GtkPrintUnixDialog * dialog)2790 update_number_up_layout (GtkPrintUnixDialog *dialog)
2791 {
2792   GtkPrintCapabilities       caps;
2793   GtkPrinterOptionSet       *set;
2794   GtkNumberUpLayout          layout;
2795   GtkPrinterOption          *option;
2796   GtkPrinterOption          *old_option;
2797   GtkPageOrientation         page_orientation;
2798 
2799   set = dialog->options;
2800 
2801   caps = dialog->manual_capabilities | dialog->printer_capabilities;
2802 
2803   if (caps & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT)
2804     {
2805       if (dialog->number_up_layout_n_option == NULL)
2806         {
2807           dialog->number_up_layout_n_option = gtk_printer_option_set_lookup (set, "gtk-n-up-layout");
2808           if (dialog->number_up_layout_n_option == NULL)
2809             {
2810               const char *n_up_layout[] = { "lrtb", "lrbt", "rltb", "rlbt", "tblr", "tbrl", "btlr", "btrl" };
2811                /* Translators: These strings name the possible arrangements of
2812                 * multiple pages on a sheet when printing (same as in gtkprintbackendcups.c)
2813                 */
2814               const char *n_up_layout_display[] = { N_("Left to right, top to bottom"), N_("Left to right, bottom to top"),
2815                                                     N_("Right to left, top to bottom"), N_("Right to left, bottom to top"),
2816                                                     N_("Top to bottom, left to right"), N_("Top to bottom, right to left"),
2817                                                     N_("Bottom to top, left to right"), N_("Bottom to top, right to left") };
2818               int i;
2819 
2820               dialog->number_up_layout_n_option = gtk_printer_option_new ("gtk-n-up-layout",
2821                                                                         _("Page Ordering"),
2822                                                                         GTK_PRINTER_OPTION_TYPE_PICKONE);
2823               gtk_printer_option_allocate_choices (dialog->number_up_layout_n_option, 8);
2824 
2825               for (i = 0; i < G_N_ELEMENTS (n_up_layout_display); i++)
2826                 {
2827                   dialog->number_up_layout_n_option->choices[i] = g_strdup (n_up_layout[i]);
2828                   dialog->number_up_layout_n_option->choices_display[i] = g_strdup (_(n_up_layout_display[i]));
2829                 }
2830             }
2831           g_object_ref (dialog->number_up_layout_n_option);
2832 
2833           dialog->number_up_layout_2_option = gtk_printer_option_new ("gtk-n-up-layout",
2834                                                                     _("Page Ordering"),
2835                                                                     GTK_PRINTER_OPTION_TYPE_PICKONE);
2836           gtk_printer_option_allocate_choices (dialog->number_up_layout_2_option, 2);
2837         }
2838 
2839       page_orientation = gtk_page_setup_get_orientation (dialog->page_setup);
2840       if (page_orientation == GTK_PAGE_ORIENTATION_PORTRAIT ||
2841           page_orientation == GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT)
2842         {
2843           if (! (dialog->number_up_layout_2_option->choices[0] == dialog->number_up_layout_n_option->choices[0] &&
2844                  dialog->number_up_layout_2_option->choices[1] == dialog->number_up_layout_n_option->choices[2]))
2845             {
2846               g_free (dialog->number_up_layout_2_option->choices_display[0]);
2847               g_free (dialog->number_up_layout_2_option->choices_display[1]);
2848               dialog->number_up_layout_2_option->choices[0] = dialog->number_up_layout_n_option->choices[0];
2849               dialog->number_up_layout_2_option->choices[1] = dialog->number_up_layout_n_option->choices[2];
2850               dialog->number_up_layout_2_option->choices_display[0] = g_strdup ( _("Left to right"));
2851               dialog->number_up_layout_2_option->choices_display[1] = g_strdup ( _("Right to left"));
2852             }
2853         }
2854       else
2855         {
2856           if (! (dialog->number_up_layout_2_option->choices[0] == dialog->number_up_layout_n_option->choices[0] &&
2857                  dialog->number_up_layout_2_option->choices[1] == dialog->number_up_layout_n_option->choices[1]))
2858             {
2859               g_free (dialog->number_up_layout_2_option->choices_display[0]);
2860               g_free (dialog->number_up_layout_2_option->choices_display[1]);
2861               dialog->number_up_layout_2_option->choices[0] = dialog->number_up_layout_n_option->choices[0];
2862               dialog->number_up_layout_2_option->choices[1] = dialog->number_up_layout_n_option->choices[1];
2863               dialog->number_up_layout_2_option->choices_display[0] = g_strdup ( _("Top to bottom"));
2864               dialog->number_up_layout_2_option->choices_display[1] = g_strdup ( _("Bottom to top"));
2865             }
2866         }
2867 
2868       layout = dialog_get_number_up_layout (dialog);
2869 
2870       old_option = gtk_printer_option_set_lookup (set, "gtk-n-up-layout");
2871       if (old_option != NULL)
2872         gtk_printer_option_set_remove (set, old_option);
2873 
2874       if (dialog_get_pages_per_sheet (dialog) != 1)
2875         {
2876           GEnumClass *enum_class;
2877           GEnumValue *enum_value;
2878           enum_class = g_type_class_ref (GTK_TYPE_NUMBER_UP_LAYOUT);
2879 
2880           if (dialog_get_pages_per_sheet (dialog) == 2)
2881             {
2882               option = dialog->number_up_layout_2_option;
2883 
2884               switch (layout)
2885                 {
2886                 case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM:
2887                 case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT:
2888                   enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM);
2889                   break;
2890 
2891                 case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP:
2892                 case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT:
2893                   enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP);
2894                   break;
2895 
2896                 case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM:
2897                 case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_RIGHT_TO_LEFT:
2898                   enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM);
2899                   break;
2900 
2901                 case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP:
2902                 case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_RIGHT_TO_LEFT:
2903                   enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP);
2904                   break;
2905 
2906                 default:
2907                   g_assert_not_reached();
2908                   enum_value = NULL;
2909                 }
2910             }
2911           else
2912             {
2913               option = dialog->number_up_layout_n_option;
2914 
2915               enum_value = g_enum_get_value (enum_class, layout);
2916             }
2917 
2918           g_assert (enum_value != NULL);
2919           gtk_printer_option_set (option, enum_value->value_nick);
2920           g_type_class_unref (enum_class);
2921 
2922           gtk_printer_option_set_add (set, option);
2923         }
2924     }
2925 
2926   setup_option (dialog, "gtk-n-up-layout", dialog->number_up_layout);
2927 
2928   if (dialog->number_up_layout != NULL)
2929     gtk_widget_set_sensitive (GTK_WIDGET (dialog->number_up_layout),
2930                               (caps & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT) &&
2931                               (dialog_get_pages_per_sheet (dialog) > 1));
2932 }
2933 
2934 static void
custom_paper_dialog_response_cb(GtkDialog * custom_paper_dialog,int response_id,gpointer user_data)2935 custom_paper_dialog_response_cb (GtkDialog *custom_paper_dialog,
2936                                  int        response_id,
2937                                  gpointer   user_data)
2938 {
2939   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (user_data);
2940 
2941   dialog->internal_page_setup_change = TRUE;
2942   gtk_print_load_custom_papers (dialog->custom_paper_list);
2943   update_paper_sizes (dialog);
2944   dialog->internal_page_setup_change = FALSE;
2945 
2946   if (dialog->page_setup_set)
2947     {
2948       GListModel *model;
2949       guint n, i;
2950 
2951       model = G_LIST_MODEL (dialog->custom_paper_list);
2952       n = g_list_model_get_n_items (model);
2953       for (i = 0; i < n; i++)
2954         {
2955           GtkPageSetup *page_setup = g_list_model_get_item (model, i);
2956 
2957           if (g_strcmp0 (gtk_paper_size_get_display_name (gtk_page_setup_get_paper_size (page_setup)),
2958                          gtk_paper_size_get_display_name (gtk_page_setup_get_paper_size (dialog->page_setup))) == 0)
2959             gtk_print_unix_dialog_set_page_setup (dialog, page_setup);
2960 
2961           g_clear_object (&page_setup);
2962         }
2963     }
2964 
2965   gtk_window_destroy (GTK_WINDOW (custom_paper_dialog));
2966 }
2967 
2968 static void
orientation_changed(GObject * object,GParamSpec * pspec,GtkPrintUnixDialog * dialog)2969 orientation_changed (GObject            *object,
2970                      GParamSpec         *pspec,
2971                      GtkPrintUnixDialog *dialog)
2972 {
2973   GtkPageOrientation orientation;
2974   GtkPageSetup *page_setup;
2975 
2976   if (dialog->internal_page_setup_change)
2977     return;
2978 
2979   orientation = (GtkPageOrientation) gtk_drop_down_get_selected (GTK_DROP_DOWN (dialog->orientation_combo));
2980 
2981   if (dialog->page_setup)
2982     {
2983       page_setup = gtk_page_setup_copy (dialog->page_setup);
2984       if (page_setup)
2985         gtk_page_setup_set_orientation (page_setup, orientation);
2986 
2987       gtk_print_unix_dialog_set_page_setup (dialog, page_setup);
2988     }
2989 
2990   redraw_page_layout_preview (dialog);
2991 }
2992 
2993 static void
paper_size_changed(GtkDropDown * combo_box,GParamSpec * pspec,GtkPrintUnixDialog * dialog)2994 paper_size_changed (GtkDropDown *combo_box,
2995                     GParamSpec *pspec,
2996                     GtkPrintUnixDialog *dialog)
2997 {
2998   GtkPageSetup *page_setup, *last_page_setup;
2999   GtkPageOrientation orientation;
3000   guint selected;
3001 
3002   if (dialog->internal_page_setup_change)
3003     return;
3004 
3005   selected = gtk_drop_down_get_selected (GTK_DROP_DOWN (combo_box));
3006   if (selected != GTK_INVALID_LIST_POSITION)
3007     {
3008       GListModel *papers, *model;
3009 
3010       papers = gtk_drop_down_get_model (GTK_DROP_DOWN (dialog->paper_size_combo));
3011       page_setup = g_list_model_get_item (papers, selected);
3012       model = gtk_flatten_list_model_get_model_for_item (GTK_FLATTEN_LIST_MODEL (papers), selected);
3013 
3014       if (model == G_LIST_MODEL (dialog->manage_papers_list))
3015         {
3016           GtkWidget *custom_paper_dialog;
3017 
3018           /* Change from "manage" menu item to last value */
3019           if (dialog->page_setup)
3020             last_page_setup = g_object_ref (dialog->page_setup);
3021           else
3022             last_page_setup = gtk_page_setup_new (); /* "good" default */
3023 
3024           if (!set_paper_size (dialog, last_page_setup, FALSE, FALSE))
3025             set_paper_size (dialog, last_page_setup, TRUE, TRUE);
3026           g_object_unref (last_page_setup);
3027 
3028           /* And show the custom paper dialog */
3029           custom_paper_dialog = _gtk_custom_paper_unix_dialog_new (GTK_WINDOW (dialog), _("Manage Custom Sizes"));
3030           g_signal_connect (custom_paper_dialog, "response", G_CALLBACK (custom_paper_dialog_response_cb), dialog);
3031           gtk_window_present (GTK_WINDOW (custom_paper_dialog));
3032 
3033           g_object_unref (page_setup);
3034 
3035           return;
3036         }
3037 
3038       if (dialog->page_setup)
3039         orientation = gtk_page_setup_get_orientation (dialog->page_setup);
3040       else
3041         orientation = GTK_PAGE_ORIENTATION_PORTRAIT;
3042 
3043       gtk_page_setup_set_orientation (page_setup, orientation);
3044       gtk_print_unix_dialog_set_page_setup (dialog, page_setup);
3045 
3046       g_object_unref (page_setup);
3047     }
3048 
3049   redraw_page_layout_preview (dialog);
3050 }
3051 
3052 /**
3053  * gtk_print_unix_dialog_new:
3054  * @title: (nullable): Title of the dialog
3055  * @parent: (nullable): Transient parent of the dialog
3056  *
3057  * Creates a new `GtkPrintUnixDialog`.
3058  *
3059  * Returns: a new `GtkPrintUnixDialog`
3060  */
3061 GtkWidget *
gtk_print_unix_dialog_new(const char * title,GtkWindow * parent)3062 gtk_print_unix_dialog_new (const char *title,
3063                            GtkWindow   *parent)
3064 {
3065   GtkWidget *result;
3066 
3067   result = g_object_new (GTK_TYPE_PRINT_UNIX_DIALOG,
3068                          "transient-for", parent,
3069                          "title", title ? title : _("Print"),
3070                          NULL);
3071 
3072   return result;
3073 }
3074 
3075 /**
3076  * gtk_print_unix_dialog_get_selected_printer: (attributes org.gtk.Method.get_property=selected-printer)
3077  * @dialog: a `GtkPrintUnixDialog`
3078  *
3079  * Gets the currently selected printer.
3080  *
3081  * Returns: (transfer none): the currently selected printer
3082  */
3083 GtkPrinter *
gtk_print_unix_dialog_get_selected_printer(GtkPrintUnixDialog * dialog)3084 gtk_print_unix_dialog_get_selected_printer (GtkPrintUnixDialog *dialog)
3085 {
3086   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
3087 
3088   return dialog->current_printer;
3089 }
3090 
3091 /**
3092  * gtk_print_unix_dialog_set_page_setup: (attributes org.gtk.Method.set_property=page-setup)
3093  * @dialog: a `GtkPrintUnixDialog`
3094  * @page_setup: a `GtkPageSetup`
3095  *
3096  * Sets the page setup of the `GtkPrintUnixDialog`.
3097  */
3098 void
gtk_print_unix_dialog_set_page_setup(GtkPrintUnixDialog * dialog,GtkPageSetup * page_setup)3099 gtk_print_unix_dialog_set_page_setup (GtkPrintUnixDialog *dialog,
3100                                       GtkPageSetup       *page_setup)
3101 {
3102   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
3103   g_return_if_fail (GTK_IS_PAGE_SETUP (page_setup));
3104 
3105   if (dialog->page_setup != page_setup)
3106     {
3107       g_clear_object (&dialog->page_setup);
3108       dialog->page_setup = g_object_ref (page_setup);
3109 
3110       dialog->page_setup_set = TRUE;
3111 
3112       g_object_notify (G_OBJECT (dialog), "page-setup");
3113     }
3114 }
3115 
3116 /**
3117  * gtk_print_unix_dialog_get_page_setup: (attributes org.gtk.Method.get_property=page-setup)
3118  * @dialog: a `GtkPrintUnixDialog`
3119  *
3120  * Gets the page setup that is used by the `GtkPrintUnixDialog`.
3121  *
3122  * Returns: (transfer none): the page setup of @dialog.
3123  */
3124 GtkPageSetup *
gtk_print_unix_dialog_get_page_setup(GtkPrintUnixDialog * dialog)3125 gtk_print_unix_dialog_get_page_setup (GtkPrintUnixDialog *dialog)
3126 {
3127   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
3128 
3129   return dialog->page_setup;
3130 }
3131 
3132 /**
3133  * gtk_print_unix_dialog_get_page_setup_set:
3134  * @dialog: a `GtkPrintUnixDialog`
3135  *
3136  * Gets whether a page setup was set by the user.
3137  *
3138  * Returns: whether a page setup was set by user.
3139  */
3140 gboolean
gtk_print_unix_dialog_get_page_setup_set(GtkPrintUnixDialog * dialog)3141 gtk_print_unix_dialog_get_page_setup_set (GtkPrintUnixDialog *dialog)
3142 {
3143   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), FALSE);
3144 
3145   return dialog->page_setup_set;
3146 }
3147 
3148 /**
3149  * gtk_print_unix_dialog_set_current_page: (attributes org.gtk.Method.set_property=current-page)
3150  * @dialog: a `GtkPrintUnixDialog`
3151  * @current_page: the current page number.
3152  *
3153  * Sets the current page number.
3154  *
3155  * If @current_page is not -1, this enables the current page choice
3156  * for the range of pages to print.
3157  */
3158 void
gtk_print_unix_dialog_set_current_page(GtkPrintUnixDialog * dialog,int current_page)3159 gtk_print_unix_dialog_set_current_page (GtkPrintUnixDialog *dialog,
3160                                         int                 current_page)
3161 {
3162   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
3163 
3164   if (dialog->current_page != current_page)
3165     {
3166       dialog->current_page = current_page;
3167 
3168       if (dialog->current_page_radio)
3169         gtk_widget_set_sensitive (dialog->current_page_radio, current_page != -1);
3170 
3171       g_object_notify (G_OBJECT (dialog), "current-page");
3172     }
3173 }
3174 
3175 /**
3176  * gtk_print_unix_dialog_get_current_page: (attributes org.gtk.Method.get_property=current-page)
3177  * @dialog: a `GtkPrintUnixDialog`
3178  *
3179  * Gets the current page of the `GtkPrintUnixDialog`.
3180  *
3181  * Returns: the current page of @dialog
3182  */
3183 int
gtk_print_unix_dialog_get_current_page(GtkPrintUnixDialog * dialog)3184 gtk_print_unix_dialog_get_current_page (GtkPrintUnixDialog *dialog)
3185 {
3186   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), -1);
3187 
3188   return dialog->current_page;
3189 }
3190 
3191 static gboolean
set_active_printer(GtkPrintUnixDialog * dialog,const char * printer_name)3192 set_active_printer (GtkPrintUnixDialog *dialog,
3193                     const char         *printer_name)
3194 {
3195   GListModel *model;
3196   GtkPrinter *printer;
3197   guint i;
3198 
3199   model = G_LIST_MODEL (gtk_column_view_get_model (GTK_COLUMN_VIEW (dialog->printer_list)));
3200 
3201   for (i = 0; i < g_list_model_get_n_items (model); i++)
3202     {
3203       printer = g_list_model_get_item (model, i);
3204 
3205       if (strcmp (gtk_printer_get_name (printer), printer_name) == 0)
3206         {
3207           gtk_single_selection_set_selected (GTK_SINGLE_SELECTION (model), i);
3208 
3209           g_free (dialog->waiting_for_printer);
3210           dialog->waiting_for_printer = NULL;
3211 
3212           g_object_unref (printer);
3213           return TRUE;
3214         }
3215 
3216       g_object_unref (printer);
3217     }
3218 
3219   return FALSE;
3220 }
3221 
3222 /**
3223  * gtk_print_unix_dialog_set_settings: (attributes org.gtk.Method.set_property=print-settings)
3224  * @dialog: a `GtkPrintUnixDialog`
3225  * @settings: (nullable): a `GtkPrintSettings`
3226  *
3227  * Sets the `GtkPrintSettings` for the `GtkPrintUnixDialog`.
3228  *
3229  * Typically, this is used to restore saved print settings
3230  * from a previous print operation before the print dialog
3231  * is shown.
3232  */
3233 void
gtk_print_unix_dialog_set_settings(GtkPrintUnixDialog * dialog,GtkPrintSettings * settings)3234 gtk_print_unix_dialog_set_settings (GtkPrintUnixDialog *dialog,
3235                                     GtkPrintSettings   *settings)
3236 {
3237   const char *printer;
3238   GtkPageRange *ranges;
3239   int num_ranges;
3240 
3241   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
3242   g_return_if_fail (settings == NULL || GTK_IS_PRINT_SETTINGS (settings));
3243 
3244   if (settings != NULL)
3245     {
3246       dialog_set_collate (dialog, gtk_print_settings_get_collate (settings));
3247       dialog_set_reverse (dialog, gtk_print_settings_get_reverse (settings));
3248       dialog_set_n_copies (dialog, gtk_print_settings_get_n_copies (settings));
3249       dialog_set_scale (dialog, gtk_print_settings_get_scale (settings));
3250       dialog_set_page_set (dialog, gtk_print_settings_get_page_set (settings));
3251       dialog_set_print_pages (dialog, gtk_print_settings_get_print_pages (settings));
3252       ranges = gtk_print_settings_get_page_ranges (settings, &num_ranges);
3253       if (ranges)
3254         {
3255           dialog_set_page_ranges (dialog, ranges, num_ranges);
3256           g_free (ranges);
3257         }
3258 
3259       dialog->format_for_printer =
3260         g_strdup (gtk_print_settings_get (settings, "format-for-printer"));
3261     }
3262 
3263   if (dialog->initial_settings)
3264     g_object_unref (dialog->initial_settings);
3265 
3266   dialog->initial_settings = settings;
3267 
3268   g_free (dialog->waiting_for_printer);
3269   dialog->waiting_for_printer = NULL;
3270 
3271   if (settings)
3272     {
3273       g_object_ref (settings);
3274 
3275       printer = gtk_print_settings_get_printer (settings);
3276 
3277       if (printer && !set_active_printer (dialog, printer))
3278         dialog->waiting_for_printer = g_strdup (printer);
3279     }
3280 
3281   g_object_notify (G_OBJECT (dialog), "print-settings");
3282 }
3283 
3284 /**
3285  * gtk_print_unix_dialog_get_settings: (attributes org.gtk.Method.set_property=print-settings)
3286  * @dialog: a `GtkPrintUnixDialog`
3287  *
3288  * Gets a new `GtkPrintSettings` object that represents the
3289  * current values in the print dialog.
3290  *
3291  * Note that this creates a new object, and you need to unref
3292  * it if don’t want to keep it.
3293  *
3294  * Returns: (transfer full): a new `GtkPrintSettings` object with the values from @dialog
3295  */
3296 GtkPrintSettings *
gtk_print_unix_dialog_get_settings(GtkPrintUnixDialog * dialog)3297 gtk_print_unix_dialog_get_settings (GtkPrintUnixDialog *dialog)
3298 {
3299   GtkPrintSettings *settings;
3300   GtkPrintPages print_pages;
3301   GtkPageRange *ranges;
3302   int n_ranges;
3303 
3304   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
3305 
3306   settings = gtk_print_settings_new ();
3307 
3308   if (dialog->current_printer)
3309     gtk_print_settings_set_printer (settings,
3310                                     gtk_printer_get_name (dialog->current_printer));
3311   else
3312     gtk_print_settings_set_printer (settings, "default");
3313 
3314   gtk_print_settings_set (settings, "format-for-printer",
3315                           dialog->format_for_printer);
3316 
3317   gtk_print_settings_set_collate (settings,
3318                                   dialog_get_collate (dialog));
3319 
3320   gtk_print_settings_set_reverse (settings,
3321                                   dialog_get_reverse (dialog));
3322 
3323   gtk_print_settings_set_n_copies (settings,
3324                                    dialog_get_n_copies (dialog));
3325 
3326   gtk_print_settings_set_scale (settings,
3327                                 dialog_get_scale (dialog));
3328 
3329   gtk_print_settings_set_page_set (settings,
3330                                    dialog_get_page_set (dialog));
3331 
3332   print_pages = dialog_get_print_pages (dialog);
3333   gtk_print_settings_set_print_pages (settings, print_pages);
3334 
3335   ranges = dialog_get_page_ranges (dialog, &n_ranges);
3336   if (ranges)
3337     {
3338       gtk_print_settings_set_page_ranges (settings, ranges, n_ranges);
3339       g_free (ranges);
3340     }
3341 
3342   /* TODO: print when. How to handle? */
3343 
3344   if (dialog->current_printer)
3345     _gtk_printer_get_settings_from_options (dialog->current_printer,
3346                                             dialog->options,
3347                                             settings);
3348 
3349   return settings;
3350 }
3351 
3352 /**
3353  * gtk_print_unix_dialog_add_custom_tab:
3354  * @dialog: a `GtkPrintUnixDialog`
3355  * @child: the widget to put in the custom tab
3356  * @tab_label: the widget to use as tab label
3357  *
3358  * Adds a custom tab to the print dialog.
3359  */
3360 void
gtk_print_unix_dialog_add_custom_tab(GtkPrintUnixDialog * dialog,GtkWidget * child,GtkWidget * tab_label)3361 gtk_print_unix_dialog_add_custom_tab (GtkPrintUnixDialog *dialog,
3362                                       GtkWidget          *child,
3363                                       GtkWidget          *tab_label)
3364 {
3365   gtk_notebook_insert_page (GTK_NOTEBOOK (dialog->notebook),
3366                             child, tab_label, 2);
3367   gtk_widget_show (child);
3368   gtk_widget_show (tab_label);
3369 }
3370 
3371 /**
3372  * gtk_print_unix_dialog_set_manual_capabilities: (attributes org.gtk.Method.set_property=manual-capabilities)
3373  * @dialog: a `GtkPrintUnixDialog`
3374  * @capabilities: the printing capabilities of your application
3375  *
3376  * This lets you specify the printing capabilities your application
3377  * supports.
3378  *
3379  * For instance, if you can handle scaling the output then you pass
3380  * %GTK_PRINT_CAPABILITY_SCALE. If you don’t pass that, then the dialog
3381  * will only let you select the scale if the printing system automatically
3382  * handles scaling.
3383  */
3384 void
gtk_print_unix_dialog_set_manual_capabilities(GtkPrintUnixDialog * dialog,GtkPrintCapabilities capabilities)3385 gtk_print_unix_dialog_set_manual_capabilities (GtkPrintUnixDialog   *dialog,
3386                                                GtkPrintCapabilities  capabilities)
3387 {
3388   if (dialog->manual_capabilities != capabilities)
3389     {
3390       dialog->manual_capabilities = capabilities;
3391       update_dialog_from_capabilities (dialog);
3392 
3393       if (dialog->current_printer)
3394         {
3395           g_clear_object (&dialog->current_printer);
3396           selected_printer_changed (dialog);
3397        }
3398 
3399       g_object_notify (G_OBJECT (dialog), "manual-capabilities");
3400     }
3401 }
3402 
3403 /**
3404  * gtk_print_unix_dialog_get_manual_capabilities: (attributes org.gtk.Method.get_property=manual-capabilities)
3405  * @dialog: a `GtkPrintUnixDialog`
3406  *
3407  * Gets the capabilities that have been set on this `GtkPrintUnixDialog`.
3408  *
3409  * Returns: the printing capabilities
3410  */
3411 GtkPrintCapabilities
gtk_print_unix_dialog_get_manual_capabilities(GtkPrintUnixDialog * dialog)3412 gtk_print_unix_dialog_get_manual_capabilities (GtkPrintUnixDialog *dialog)
3413 {
3414   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), FALSE);
3415 
3416   return dialog->manual_capabilities;
3417 }
3418 
3419 /**
3420  * gtk_print_unix_dialog_set_support_selection: (attributes org.gtk.Method.set_property=support-selection)
3421  * @dialog: a `GtkPrintUnixDialog`
3422  * @support_selection: %TRUE to allow print selection
3423  *
3424  * Sets whether the print dialog allows user to print a selection.
3425  */
3426 void
gtk_print_unix_dialog_set_support_selection(GtkPrintUnixDialog * dialog,gboolean support_selection)3427 gtk_print_unix_dialog_set_support_selection (GtkPrintUnixDialog *dialog,
3428                                              gboolean            support_selection)
3429 {
3430   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
3431 
3432   support_selection = support_selection != FALSE;
3433   if (dialog->support_selection != support_selection)
3434     {
3435       dialog->support_selection = support_selection;
3436 
3437       if (dialog->selection_radio)
3438         {
3439           if (support_selection)
3440             {
3441               gtk_widget_set_sensitive (dialog->selection_radio, dialog->has_selection);
3442               gtk_widget_show (dialog->selection_radio);
3443             }
3444           else
3445             {
3446               gtk_widget_set_sensitive (dialog->selection_radio, FALSE);
3447               gtk_widget_hide (dialog->selection_radio);
3448             }
3449         }
3450 
3451       g_object_notify (G_OBJECT (dialog), "support-selection");
3452     }
3453 }
3454 
3455 /**
3456  * gtk_print_unix_dialog_get_support_selection: (attributes org.gtk.Method.get_property=support-selection)
3457  * @dialog: a `GtkPrintUnixDialog`
3458  *
3459  * Gets whether the print dialog allows user to print a selection.
3460  *
3461  * Returns: whether the application supports print of selection
3462  */
3463 gboolean
gtk_print_unix_dialog_get_support_selection(GtkPrintUnixDialog * dialog)3464 gtk_print_unix_dialog_get_support_selection (GtkPrintUnixDialog *dialog)
3465 {
3466   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), FALSE);
3467 
3468   return dialog->support_selection;
3469 }
3470 
3471 /**
3472  * gtk_print_unix_dialog_set_has_selection: (attributes org.gtk.Method.set_property=has-selection)
3473  * @dialog: a `GtkPrintUnixDialog`
3474  * @has_selection: %TRUE indicates that a selection exists
3475  *
3476  * Sets whether a selection exists.
3477  */
3478 void
gtk_print_unix_dialog_set_has_selection(GtkPrintUnixDialog * dialog,gboolean has_selection)3479 gtk_print_unix_dialog_set_has_selection (GtkPrintUnixDialog *dialog,
3480                                          gboolean            has_selection)
3481 {
3482   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
3483 
3484   has_selection = has_selection != FALSE;
3485   if (dialog->has_selection != has_selection)
3486     {
3487       dialog->has_selection = has_selection;
3488 
3489       if (dialog->selection_radio)
3490         {
3491           if (dialog->support_selection)
3492             gtk_widget_set_sensitive (dialog->selection_radio, has_selection);
3493           else
3494             gtk_widget_set_sensitive (dialog->selection_radio, FALSE);
3495         }
3496 
3497       g_object_notify (G_OBJECT (dialog), "has-selection");
3498     }
3499 }
3500 
3501 /**
3502  * gtk_print_unix_dialog_get_has_selection: (attributes org.gtk.Method.get_property=has-selection)
3503  * @dialog: a `GtkPrintUnixDialog`
3504  *
3505  * Gets whether there is a selection.
3506  *
3507  * Returns: whether there is a selection
3508  */
3509 gboolean
gtk_print_unix_dialog_get_has_selection(GtkPrintUnixDialog * dialog)3510 gtk_print_unix_dialog_get_has_selection (GtkPrintUnixDialog *dialog)
3511 {
3512   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), FALSE);
3513 
3514   return dialog->has_selection;
3515 }
3516 
3517 /**
3518  * gtk_print_unix_dialog_set_embed_page_setup: (attributes org.gtk.Method.set_property=embed-page-setup)
3519  * @dialog: a `GtkPrintUnixDialog`
3520  * @embed: embed page setup selection
3521  *
3522  * Embed page size combo box and orientation combo box into page setup page.
3523  */
3524 void
gtk_print_unix_dialog_set_embed_page_setup(GtkPrintUnixDialog * dialog,gboolean embed)3525 gtk_print_unix_dialog_set_embed_page_setup (GtkPrintUnixDialog *dialog,
3526                                             gboolean            embed)
3527 {
3528   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
3529 
3530   embed = embed != FALSE;
3531   if (dialog->embed_page_setup != embed)
3532     {
3533       dialog->embed_page_setup = embed;
3534 
3535       gtk_widget_set_sensitive (dialog->paper_size_combo, dialog->embed_page_setup);
3536       gtk_widget_set_sensitive (dialog->orientation_combo, dialog->embed_page_setup);
3537 
3538       if (dialog->embed_page_setup)
3539         {
3540           if (dialog->paper_size_combo != NULL)
3541             g_signal_connect (dialog->paper_size_combo, "notify::selected", G_CALLBACK (paper_size_changed), dialog);
3542 
3543           if (dialog->orientation_combo)
3544             g_signal_connect (dialog->orientation_combo, "notify::selected", G_CALLBACK (orientation_changed), dialog);
3545         }
3546       else
3547         {
3548           if (dialog->paper_size_combo != NULL)
3549             g_signal_handlers_disconnect_by_func (dialog->paper_size_combo, G_CALLBACK (paper_size_changed), dialog);
3550 
3551           if (dialog->orientation_combo)
3552             g_signal_handlers_disconnect_by_func (dialog->orientation_combo, G_CALLBACK (orientation_changed), dialog);
3553         }
3554 
3555       dialog->internal_page_setup_change = TRUE;
3556       update_paper_sizes (dialog);
3557       dialog->internal_page_setup_change = FALSE;
3558     }
3559 }
3560 
3561 /**
3562  * gtk_print_unix_dialog_get_embed_page_setup: (attributes org.gtk.Method.get_property=embed-page-setup)
3563  * @dialog: a `GtkPrintUnixDialog`
3564  *
3565  * Gets whether to embed the page setup.
3566  *
3567  * Returns: whether to embed the page setup
3568  */
3569 gboolean
gtk_print_unix_dialog_get_embed_page_setup(GtkPrintUnixDialog * dialog)3570 gtk_print_unix_dialog_get_embed_page_setup (GtkPrintUnixDialog *dialog)
3571 {
3572   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), FALSE);
3573 
3574   return dialog->embed_page_setup;
3575 }
3576