]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintunixdialog.c
Cosmetics
[~andy/gtk] / gtk / gtkprintunixdialog.c
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 "gtkprintbackend.h"
32 #include "gtkprinter-private.h"
33 #include "gtkprinteroptionwidget.h"
34 #include "gtkprintutils.h"
35
36 #include "gtkspinbutton.h"
37 #include "gtkcellrendererpixbuf.h"
38 #include "gtkcellrenderertext.h"
39 #include "gtkstock.h"
40 #include "gtkiconfactory.h"
41 #include "gtkimage.h"
42 #include "gtktreeselection.h"
43 #include "gtknotebook.h"
44 #include "gtkscrolledwindow.h"
45 #include "gtkcombobox.h"
46 #include "gtktogglebutton.h"
47 #include "gtkradiobutton.h"
48 #include "gtkdrawingarea.h"
49 #include "gtkbox.h"
50 #include "gtkgrid.h"
51 #include "gtkframe.h"
52 #include "gtklabel.h"
53 #include "gtkeventbox.h"
54 #include "gtkbuildable.h"
55 #include "gtkmessagedialog.h"
56 #include "gtkbutton.h"
57 #include "gtkintl.h"
58 #include "gtkprivate.h"
59 #include "gtktypebuiltins.h"
60
61
62 /**
63  * SECTION:gtkprintunixdialog
64  * @Short_description: A print dialog
65  * @Title: GtkPrintUnixDialog
66  * @See_also: #GtkPageSetupUnixDialog, #GtkPrinter, #GtkPrintJob
67  *
68  * GtkPrintUnixDialog implements a print dialog for platforms
69  * which don't provide a native print dialog, like Unix. It can
70  * be used very much like any other GTK+ dialog, at the cost of
71  * the portability offered by the
72  * <link linkend="gtk-High-level-Printing-API">high-level printing API</link>
73  *
74  * In order to print something with #GtkPrintUnixDialog, you need
75  * to use gtk_print_unix_dialog_get_selected_printer() to obtain
76  * a #GtkPrinter object and use it to construct a #GtkPrintJob using
77  * gtk_print_job_new().
78  *
79  * #GtkPrintUnixDialog uses the following response values:
80  * <variablelist>
81  *   <varlistentry><term>%GTK_RESPONSE_OK</term>
82  *     <listitem><para>for the "Print" button</para></listitem>
83  *   </varlistentry>
84  *   <varlistentry><term>%GTK_RESPONSE_APPLY</term>
85  *     <listitem><para>for the "Preview" button</para></listitem>
86  *   </varlistentry>
87  *   <varlistentry><term>%GTK_RESPONSE_CANCEL</term>
88  *     <listitem><para>for the "Cancel" button</para></listitem>
89  *   </varlistentry>
90  * </variablelist>
91  *
92  * <!-- FIXME example here -->
93  *
94  * Printing support was added in GTK+ 2.10.
95  *
96  * <refsect2 id="GtkPrintUnixDialog-BUILDER-UI">
97  * <title>GtkPrintUnixDialog as GtkBuildable</title>
98  * <para>
99  * The GtkPrintUnixDialog implementation of the GtkBuildable interface exposes its
100  * @notebook internal children with the name "notebook".
101  *
102  * <example>
103  * <title>A <structname>GtkPrintUnixDialog</structname> UI definition fragment.</title>
104  * <programlisting><![CDATA[
105  * <object class="GtkPrintUnixDialog" id="dialog1">
106  *   <child internal-child="notebook">
107  *     <object class="GtkNotebook" id="notebook">
108  *       <child>
109  *         <object class="GtkLabel" id="tabcontent">
110  *         <property name="label">Content on notebook tab</property>
111  *         </object>
112  *       </child>
113  *       <child type="tab">
114  *         <object class="GtkLabel" id="tablabel">
115  *           <property name="label">Tab label</property>
116  *         </object>
117  *         <packing>
118  *           <property name="tab_expand">False</property>
119  *           <property name="tab_fill">False</property>
120  *         </packing>
121  *       </child>
122  *     </object>
123  *   </child>
124  * </object>
125  * ]]></programlisting>
126  * </example>
127  * </para>
128  * </refsect2>
129  */
130
131
132 #define EXAMPLE_PAGE_AREA_SIZE 110
133 #define RULER_DISTANCE 7.5
134 #define RULER_RADIUS 2
135
136
137 static void     gtk_print_unix_dialog_destroy      (GtkPrintUnixDialog *dialog);
138 static void     gtk_print_unix_dialog_finalize     (GObject            *object);
139 static void     gtk_print_unix_dialog_set_property (GObject            *object,
140                                                     guint               prop_id,
141                                                     const GValue       *value,
142                                                     GParamSpec         *pspec);
143 static void     gtk_print_unix_dialog_get_property (GObject            *object,
144                                                     guint               prop_id,
145                                                     GValue             *value,
146                                                     GParamSpec         *pspec);
147 static void     gtk_print_unix_dialog_style_updated (GtkWidget          *widget);
148 static void     populate_dialog                    (GtkPrintUnixDialog *dialog);
149 static void     unschedule_idle_mark_conflicts     (GtkPrintUnixDialog *dialog);
150 static void     selected_printer_changed           (GtkTreeSelection   *selection,
151                                                     GtkPrintUnixDialog *dialog);
152 static void     clear_per_printer_ui               (GtkPrintUnixDialog *dialog);
153 static void     printer_added_cb                   (GtkPrintBackend    *backend,
154                                                     GtkPrinter         *printer,
155                                                     GtkPrintUnixDialog *dialog);
156 static void     printer_removed_cb                 (GtkPrintBackend    *backend,
157                                                     GtkPrinter         *printer,
158                                                     GtkPrintUnixDialog *dialog);
159 static void     printer_status_cb                  (GtkPrintBackend    *backend,
160                                                     GtkPrinter         *printer,
161                                                     GtkPrintUnixDialog *dialog);
162 static void     update_collate_icon                (GtkToggleButton    *toggle_button,
163                                                     GtkPrintUnixDialog *dialog);
164 static gboolean dialog_get_collate                 (GtkPrintUnixDialog *dialog);
165 static gboolean dialog_get_reverse                 (GtkPrintUnixDialog *dialog);
166 static gint     dialog_get_n_copies                (GtkPrintUnixDialog *dialog);
167
168 static void     set_cell_sensitivity_func          (GtkTreeViewColumn *tree_column,
169                                                     GtkCellRenderer   *cell,
170                                                     GtkTreeModel      *model,
171                                                     GtkTreeIter       *iter,
172                                                     gpointer           data);
173 static gboolean set_active_printer                 (GtkPrintUnixDialog *dialog,
174                                                     const gchar        *printer_name);
175 static void redraw_page_layout_preview             (GtkPrintUnixDialog *dialog);
176
177 /* GtkBuildable */
178 static void gtk_print_unix_dialog_buildable_init                    (GtkBuildableIface *iface);
179 static GObject *gtk_print_unix_dialog_buildable_get_internal_child  (GtkBuildable *buildable,
180                                                                      GtkBuilder   *builder,
181                                                                      const gchar  *childname);
182
183 static const gchar const common_paper_sizes[][16] = {
184   "na_letter",
185   "na_legal",
186   "iso_a4",
187   "iso_a5",
188   "roc_16k",
189   "iso_b5",
190   "jis_b5",
191   "na_number-10",
192   "iso_dl",
193   "jpn_chou3",
194   "na_ledger",
195   "iso_a3",
196 };
197
198 enum {
199   PAGE_SETUP_LIST_COL_PAGE_SETUP,
200   PAGE_SETUP_LIST_COL_IS_SEPARATOR,
201   PAGE_SETUP_LIST_N_COLS
202 };
203
204 enum {
205   PROP_0,
206   PROP_PAGE_SETUP,
207   PROP_CURRENT_PAGE,
208   PROP_PRINT_SETTINGS,
209   PROP_SELECTED_PRINTER,
210   PROP_MANUAL_CAPABILITIES,
211   PROP_SUPPORT_SELECTION,
212   PROP_HAS_SELECTION,
213   PROP_EMBED_PAGE_SETUP
214 };
215
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 struct GtkPrintUnixDialogPrivate
227 {
228   GtkWidget *notebook;
229
230   GtkWidget *printer_treeview;
231
232   GtkPrintCapabilities manual_capabilities;
233   GtkPrintCapabilities printer_capabilities;
234
235   GtkTreeModel *printer_list;
236   GtkTreeModelFilter *printer_list_filter;
237
238   GtkPageSetup *page_setup;
239   gboolean page_setup_set;
240   gboolean embed_page_setup;
241   GtkListStore *page_setup_list;
242   GtkListStore *custom_paper_list;
243
244   gboolean support_selection;
245   gboolean has_selection;
246
247   GtkWidget *all_pages_radio;
248   GtkWidget *current_page_radio;
249   GtkWidget *selection_radio;
250   GtkWidget *range_table;
251   GtkWidget *page_range_radio;
252   GtkWidget *page_range_entry;
253
254   GtkWidget *copies_spin;
255   GtkWidget *collate_check;
256   GtkWidget *reverse_check;
257   GtkWidget *collate_image;
258   GtkWidget *page_layout_preview;
259   GtkWidget *scale_spin;
260   GtkWidget *page_set_combo;
261   GtkWidget *print_now_radio;
262   GtkWidget *print_at_radio;
263   GtkWidget *print_at_entry;
264   GtkWidget *print_hold_radio;
265   GtkWidget *preview_button;
266   GtkWidget *paper_size_combo;
267   GtkWidget *paper_size_combo_label;
268   GtkWidget *orientation_combo;
269   GtkWidget *orientation_combo_label;
270   gboolean internal_page_setup_change;
271   gboolean updating_print_at;
272   GtkPrinterOptionWidget *pages_per_sheet;
273   GtkPrinterOptionWidget *duplex;
274   GtkPrinterOptionWidget *paper_type;
275   GtkPrinterOptionWidget *paper_source;
276   GtkPrinterOptionWidget *output_tray;
277   GtkPrinterOptionWidget *job_prio;
278   GtkPrinterOptionWidget *billing_info;
279   GtkPrinterOptionWidget *cover_before;
280   GtkPrinterOptionWidget *cover_after;
281   GtkPrinterOptionWidget *number_up_layout;
282
283   GtkWidget *conflicts_widget;
284
285   GtkWidget *job_page;
286   GtkWidget *finishing_table;
287   GtkWidget *finishing_page;
288   GtkWidget *image_quality_table;
289   GtkWidget *image_quality_page;
290   GtkWidget *color_table;
291   GtkWidget *color_page;
292
293   GtkWidget *advanced_vbox;
294   GtkWidget *advanced_page;
295
296   GtkWidget *extension_point;
297
298   /* These are set initially on selected printer (either default printer,
299    * printer taken from set settings, or user-selected), but when any
300    * setting is changed by the user it is cleared.
301    */
302   GtkPrintSettings *initial_settings;
303
304   GtkPrinterOption *number_up_layout_n_option;
305   GtkPrinterOption *number_up_layout_2_option;
306
307   /* This is the initial printer set by set_settings. We look for it in
308    * the added printers. We clear this whenever the user manually changes
309    * to another printer, when the user changes a setting or when we find
310    * this printer.
311    */
312   char *waiting_for_printer;
313   gboolean internal_printer_change;
314
315   GList *print_backends;
316
317   GtkPrinter *current_printer;
318   GtkPrinter *request_details_printer;
319   gulong request_details_tag;
320   GtkPrinterOptionSet *options;
321   gulong options_changed_handler;
322   gulong mark_conflicts_id;
323
324   gchar *format_for_printer;
325
326   gint current_page;
327 };
328
329 G_DEFINE_TYPE_WITH_CODE (GtkPrintUnixDialog, gtk_print_unix_dialog, GTK_TYPE_DIALOG,
330                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
331                                                 gtk_print_unix_dialog_buildable_init))
332
333 static GtkBuildableIface *parent_buildable_iface;
334
335 static gboolean
336 is_default_printer (GtkPrintUnixDialog *dialog,
337                     GtkPrinter         *printer)
338 {
339   GtkPrintUnixDialogPrivate *priv = dialog->priv;
340
341   if (priv->format_for_printer)
342     return strcmp (priv->format_for_printer,
343                    gtk_printer_get_name (printer)) == 0;
344  else
345    return gtk_printer_is_default (printer);
346 }
347
348 static void
349 gtk_print_unix_dialog_class_init (GtkPrintUnixDialogClass *class)
350 {
351   GObjectClass *object_class;
352   GtkWidgetClass *widget_class;
353
354   object_class = (GObjectClass *) class;
355   widget_class = (GtkWidgetClass *) class;
356
357   object_class->finalize = gtk_print_unix_dialog_finalize;
358   object_class->set_property = gtk_print_unix_dialog_set_property;
359   object_class->get_property = gtk_print_unix_dialog_get_property;
360
361   widget_class->style_updated = gtk_print_unix_dialog_style_updated;
362
363   g_object_class_install_property (object_class,
364                                    PROP_PAGE_SETUP,
365                                    g_param_spec_object ("page-setup",
366                                                         P_("Page Setup"),
367                                                         P_("The GtkPageSetup to use"),
368                                                         GTK_TYPE_PAGE_SETUP,
369                                                         GTK_PARAM_READWRITE));
370
371   g_object_class_install_property (object_class,
372                                    PROP_CURRENT_PAGE,
373                                    g_param_spec_int ("current-page",
374                                                      P_("Current Page"),
375                                                      P_("The current page in the document"),
376                                                      -1,
377                                                      G_MAXINT,
378                                                      -1,
379                                                      GTK_PARAM_READWRITE));
380
381   g_object_class_install_property (object_class,
382                                    PROP_PRINT_SETTINGS,
383                                    g_param_spec_object ("print-settings",
384                                                         P_("Print Settings"),
385                                                         P_("The GtkPrintSettings used for initializing the dialog"),
386                                                         GTK_TYPE_PRINT_SETTINGS,
387                                                         GTK_PARAM_READWRITE));
388
389   g_object_class_install_property (object_class,
390                                    PROP_SELECTED_PRINTER,
391                                    g_param_spec_object ("selected-printer",
392                                                         P_("Selected Printer"),
393                                                         P_("The GtkPrinter which is selected"),
394                                                         GTK_TYPE_PRINTER,
395                                                         GTK_PARAM_READABLE));
396
397   g_object_class_install_property (object_class,
398                                    PROP_MANUAL_CAPABILITIES,
399                                    g_param_spec_flags ("manual-capabilities",
400                                                        P_("Manual Capabilities"),
401                                                        P_("Capabilities the application can handle"),
402                                                        GTK_TYPE_PRINT_CAPABILITIES,
403                                                        0,
404                                                        GTK_PARAM_READWRITE));
405
406   g_object_class_install_property (object_class,
407                                    PROP_SUPPORT_SELECTION,
408                                    g_param_spec_boolean ("support-selection",
409                                                          P_("Support Selection"),
410                                                          P_("Whether the dialog supports selection"),
411                                                          FALSE,
412                                                          GTK_PARAM_READWRITE));
413
414   g_object_class_install_property (object_class,
415                                    PROP_HAS_SELECTION,
416                                    g_param_spec_boolean ("has-selection",
417                                                          P_("Has Selection"),
418                                                          P_("Whether the application has a selection"),
419                                                          FALSE,
420                                                          GTK_PARAM_READWRITE));
421
422    g_object_class_install_property (object_class,
423                                    PROP_EMBED_PAGE_SETUP,
424                                    g_param_spec_boolean ("embed-page-setup",
425                                                          P_("Embed Page Setup"),
426                                                          P_("TRUE if page setup combos are embedded in GtkPrintUnixDialog"),
427                                                          FALSE,
428                                                          GTK_PARAM_READWRITE));
429
430   g_type_class_add_private (class, sizeof (GtkPrintUnixDialogPrivate));
431 }
432
433 /* Returns a toplevel GtkWindow, or NULL if none */
434 static GtkWindow *
435 get_toplevel (GtkWidget *widget)
436 {
437   GtkWidget *toplevel = NULL;
438
439   toplevel = gtk_widget_get_toplevel (widget);
440   if (!gtk_widget_is_toplevel (toplevel))
441     return NULL;
442   else
443     return GTK_WINDOW (toplevel);
444 }
445
446 static void
447 set_busy_cursor (GtkPrintUnixDialog *dialog,
448                  gboolean            busy)
449 {
450   GtkWidget *widget;
451   GtkWindow *toplevel;
452   GdkDisplay *display;
453   GdkCursor *cursor;
454
455   toplevel = get_toplevel (GTK_WIDGET (dialog));
456   widget = GTK_WIDGET (toplevel);
457
458   if (!toplevel || !gtk_widget_get_realized (widget))
459     return;
460
461   display = gtk_widget_get_display (widget);
462
463   if (busy)
464     cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
465   else
466     cursor = NULL;
467
468   gdk_window_set_cursor (gtk_widget_get_window (widget), cursor);
469   gdk_display_flush (display);
470
471   if (cursor)
472     g_object_unref (cursor);
473 }
474
475 static void
476 add_custom_button_to_dialog (GtkDialog   *dialog,
477                              const gchar *mnemonic_label,
478                              const gchar *stock_id,
479                              gint         response_id)
480 {
481   GtkWidget *button = NULL;
482
483   button = gtk_button_new_with_mnemonic (mnemonic_label);
484   gtk_widget_set_can_default (button, TRUE);
485   gtk_button_set_image (GTK_BUTTON (button),
486                         gtk_image_new_from_stock (stock_id,
487                                                   GTK_ICON_SIZE_BUTTON));
488   gtk_widget_show (button);
489
490   gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, response_id);
491 }
492
493 /* This function handles error messages before printing.
494  */
495 static gboolean
496 error_dialogs (GtkPrintUnixDialog *print_dialog,
497                gint                print_dialog_response_id,
498                gpointer            data)
499 {
500   GtkPrintUnixDialogPrivate *priv = print_dialog->priv;
501   GtkPrinterOption          *option = NULL;
502   GtkPrinter                *printer = NULL;
503   GtkWindow                 *toplevel = NULL;
504   GtkWidget                 *dialog = NULL;
505   GFile                     *file = NULL;
506   gchar                     *basename = NULL;
507   gchar                     *dirname = NULL;
508   int                        response;
509
510   if (print_dialog != NULL && print_dialog_response_id == GTK_RESPONSE_OK)
511     {
512       printer = gtk_print_unix_dialog_get_selected_printer (print_dialog);
513
514       if (printer != NULL)
515         {
516           if (priv->request_details_tag || !gtk_printer_is_accepting_jobs (printer))
517             {
518               g_signal_stop_emission_by_name (print_dialog, "response");
519               return TRUE;
520             }
521
522           /* Shows overwrite confirmation dialog in the case of printing
523            * to file which already exists.
524            */
525           if (gtk_printer_is_virtual (printer))
526             {
527               option = gtk_printer_option_set_lookup (priv->options,
528                                                       "gtk-main-page-custom-input");
529
530               if (option != NULL &&
531                   option->type == GTK_PRINTER_OPTION_TYPE_FILESAVE)
532                 {
533                   file = g_file_new_for_uri (option->value);
534
535                   if (file != NULL &&
536                       g_file_query_exists (file, NULL))
537                     {
538                       toplevel = get_toplevel (GTK_WIDGET (print_dialog));
539
540                       basename = g_file_get_basename (file);
541                       dirname = g_file_get_parse_name (g_file_get_parent (file));
542
543                       dialog = gtk_message_dialog_new (toplevel,
544                                                        GTK_DIALOG_MODAL |
545                                                        GTK_DIALOG_DESTROY_WITH_PARENT,
546                                                        GTK_MESSAGE_QUESTION,
547                                                        GTK_BUTTONS_NONE,
548                                                        _("A file named \"%s\" already exists.  Do you want to replace it?"),
549                                                        basename);
550
551                       gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
552                                                                 _("The file already exists in \"%s\".  Replacing it will "
553                                                                 "overwrite its contents."),
554                                                                 dirname);
555
556                       gtk_dialog_add_button (GTK_DIALOG (dialog),
557                                              GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
558                       add_custom_button_to_dialog (GTK_DIALOG (dialog),
559                                                    _("_Replace"),
560                                                    GTK_STOCK_PRINT,
561                                                    GTK_RESPONSE_ACCEPT);
562                       gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
563                                                                GTK_RESPONSE_ACCEPT,
564                                                                GTK_RESPONSE_CANCEL,
565                                                                -1);
566                       gtk_dialog_set_default_response (GTK_DIALOG (dialog),
567                                                        GTK_RESPONSE_ACCEPT);
568
569                       if (gtk_window_has_group (toplevel))
570                         gtk_window_group_add_window (gtk_window_get_group (toplevel),
571                                                      GTK_WINDOW (dialog));
572
573                       response = gtk_dialog_run (GTK_DIALOG (dialog));
574
575                       gtk_widget_destroy (dialog);
576
577                       g_free (dirname);
578                       g_free (basename);
579
580                       if (response != GTK_RESPONSE_ACCEPT)
581                         {
582                           g_signal_stop_emission_by_name (print_dialog, "response");
583                           g_object_unref (file);
584                           return TRUE;
585                         }
586                     }
587
588                   g_object_unref (file);
589                 }
590             }
591         }
592     }
593   return FALSE;
594 }
595
596 static void
597 gtk_print_unix_dialog_init (GtkPrintUnixDialog *dialog)
598 {
599   GtkPrintUnixDialogPrivate *priv;
600
601   dialog->priv = G_TYPE_INSTANCE_GET_PRIVATE (dialog,
602                                               GTK_TYPE_PRINT_UNIX_DIALOG,
603                                               GtkPrintUnixDialogPrivate);
604   priv = dialog->priv;
605
606   priv->print_backends = NULL;
607   priv->current_page = -1;
608   priv->number_up_layout_n_option = NULL;
609   priv->number_up_layout_2_option = NULL;
610
611   priv->page_setup = gtk_page_setup_new ();
612   priv->page_setup_set = FALSE;
613   priv->embed_page_setup = FALSE;
614   priv->internal_page_setup_change = FALSE;
615
616   priv->support_selection = FALSE;
617   priv->has_selection = FALSE;
618
619   g_signal_connect (dialog, "destroy",
620                     (GCallback) gtk_print_unix_dialog_destroy, NULL);
621
622   g_signal_connect (dialog, "response",
623                     (GCallback) error_dialogs, NULL);
624
625   g_signal_connect (dialog, "notify::page-setup",
626                     (GCallback) redraw_page_layout_preview, NULL);
627
628   priv->preview_button = gtk_button_new_from_stock (GTK_STOCK_PRINT_PREVIEW);
629   gtk_widget_show (priv->preview_button);
630
631   gtk_dialog_add_action_widget (GTK_DIALOG (dialog),
632                                 priv->preview_button,
633                                 GTK_RESPONSE_APPLY);
634   gtk_dialog_add_buttons (GTK_DIALOG (dialog),
635                           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
636                           GTK_STOCK_PRINT, GTK_RESPONSE_OK,
637                           NULL);
638   gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
639                                            GTK_RESPONSE_APPLY,
640                                            GTK_RESPONSE_OK,
641                                            GTK_RESPONSE_CANCEL,
642                                            -1);
643
644   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
645   gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
646
647   priv->page_setup_list = gtk_list_store_new (PAGE_SETUP_LIST_N_COLS,
648                                               G_TYPE_OBJECT,
649                                               G_TYPE_BOOLEAN);
650
651   priv->custom_paper_list = gtk_list_store_new (1, G_TYPE_OBJECT);
652   _gtk_print_load_custom_papers (priv->custom_paper_list);
653
654   populate_dialog (dialog);
655 }
656
657 static void
658 gtk_print_unix_dialog_destroy (GtkPrintUnixDialog *dialog)
659 {
660   /* Make sure we don't destroy custom widgets owned by the backends */
661   clear_per_printer_ui (dialog);
662 }
663
664 static void
665 disconnect_printer_details_request (GtkPrintUnixDialog *dialog,
666                                     gboolean            details_failed)
667 {
668   GtkPrintUnixDialogPrivate *priv = dialog->priv;
669
670   if (priv->request_details_tag)
671     {
672       g_signal_handler_disconnect (priv->request_details_printer,
673                                    priv->request_details_tag);
674       priv->request_details_tag = 0;
675       set_busy_cursor (dialog, FALSE);
676       if (details_failed)
677         gtk_list_store_set (GTK_LIST_STORE (priv->printer_list),
678                             g_object_get_data (G_OBJECT (priv->request_details_printer),
679                                                "gtk-print-tree-iter"),
680                             PRINTER_LIST_COL_STATE,
681                              _("Getting printer information failed"),
682                             -1);
683       else
684         gtk_list_store_set (GTK_LIST_STORE (priv->printer_list),
685                             g_object_get_data (G_OBJECT (priv->request_details_printer),
686                                                "gtk-print-tree-iter"),
687                             PRINTER_LIST_COL_STATE,
688                             gtk_printer_get_state_message (priv->request_details_printer),
689                             -1);
690       g_object_unref (priv->request_details_printer);
691       priv->request_details_printer = NULL;
692     }
693 }
694
695 static void
696 gtk_print_unix_dialog_finalize (GObject *object)
697 {
698   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
699   GtkPrintUnixDialogPrivate *priv = dialog->priv;
700   GtkPrintBackend *backend;
701   GList *node;
702
703   unschedule_idle_mark_conflicts (dialog);
704   disconnect_printer_details_request (dialog, FALSE);
705
706   g_clear_object (&priv->current_printer);
707   g_clear_object (&priv->printer_list);
708   g_clear_object (&priv->custom_paper_list);
709   g_clear_object (&priv->printer_list_filter);
710   g_clear_object (&priv->options);
711
712   if (priv->number_up_layout_2_option)
713     {
714       priv->number_up_layout_2_option->choices[0] = NULL;
715       priv->number_up_layout_2_option->choices[1] = NULL;
716       g_free (priv->number_up_layout_2_option->choices_display[0]);
717       g_free (priv->number_up_layout_2_option->choices_display[1]);
718       priv->number_up_layout_2_option->choices_display[0] = NULL;
719       priv->number_up_layout_2_option->choices_display[1] = NULL;
720       g_object_unref (priv->number_up_layout_2_option);
721       priv->number_up_layout_2_option = NULL;
722     }
723
724   g_clear_object (&priv->number_up_layout_n_option);
725   g_clear_object (&priv->page_setup);
726   g_clear_object (&priv->initial_settings);
727   g_clear_pointer (&priv->waiting_for_printer, (GDestroyNotify)g_free);
728   g_clear_pointer (&priv->format_for_printer, (GDestroyNotify)g_free);
729
730   for (node = priv->print_backends; node != NULL; node = node->next)
731     {
732       backend = GTK_PRINT_BACKEND (node->data);
733
734       g_signal_handlers_disconnect_by_func (backend, printer_added_cb, dialog);
735       g_signal_handlers_disconnect_by_func (backend, printer_removed_cb, dialog);
736       g_signal_handlers_disconnect_by_func (backend, printer_status_cb, dialog);
737
738       gtk_print_backend_destroy (backend);
739       g_object_unref (backend);
740     }
741
742   g_list_free (priv->print_backends);
743   priv->print_backends = NULL;
744
745   g_clear_object (&priv->page_setup_list);
746
747   G_OBJECT_CLASS (gtk_print_unix_dialog_parent_class)->finalize (object);
748 }
749
750 static void
751 printer_removed_cb (GtkPrintBackend    *backend,
752                     GtkPrinter         *printer,
753                     GtkPrintUnixDialog *dialog)
754 {
755   GtkPrintUnixDialogPrivate *priv = dialog->priv;
756   GtkTreeIter *iter;
757
758   iter = g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter");
759   gtk_list_store_remove (GTK_LIST_STORE (priv->printer_list), iter);
760 }
761
762 static void
763 gtk_print_unix_dialog_buildable_init (GtkBuildableIface *iface)
764 {
765   parent_buildable_iface = g_type_interface_peek_parent (iface);
766
767   iface->get_internal_child = gtk_print_unix_dialog_buildable_get_internal_child;
768 }
769
770 static GObject *
771 gtk_print_unix_dialog_buildable_get_internal_child (GtkBuildable *buildable,
772                                                     GtkBuilder   *builder,
773                                                     const gchar  *childname)
774 {
775   if (strcmp (childname, "notebook") == 0)
776     return G_OBJECT (GTK_PRINT_UNIX_DIALOG (buildable)->priv->notebook);
777
778   return parent_buildable_iface->get_internal_child (buildable, builder, childname);
779 }
780
781 /* This function controls "sensitive" property of GtkCellRenderer
782  * based on pause state of printers.
783  */
784 void set_cell_sensitivity_func (GtkTreeViewColumn *tree_column,
785                                 GtkCellRenderer   *cell,
786                                 GtkTreeModel      *tree_model,
787                                 GtkTreeIter       *iter,
788                                 gpointer           data)
789 {
790   GtkPrinter *printer;
791
792   gtk_tree_model_get (tree_model, iter,
793                       PRINTER_LIST_COL_PRINTER_OBJ, &printer,
794                       -1);
795
796   if (printer != NULL && !gtk_printer_is_accepting_jobs (printer))
797     g_object_set (cell, "sensitive", FALSE, NULL);
798   else
799     g_object_set (cell, "sensitive", TRUE, NULL);
800
801   g_object_unref (printer);
802 }
803
804 static void
805 printer_status_cb (GtkPrintBackend    *backend,
806                    GtkPrinter         *printer,
807                    GtkPrintUnixDialog *dialog)
808 {
809   GtkPrintUnixDialogPrivate *priv = dialog->priv;
810   GtkTreeIter *iter;
811   GtkTreeSelection *selection;
812
813   iter = g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter");
814
815   gtk_list_store_set (GTK_LIST_STORE (priv->printer_list), iter,
816                       PRINTER_LIST_COL_ICON, gtk_printer_get_icon_name (printer),
817                       PRINTER_LIST_COL_STATE, gtk_printer_get_state_message (printer),
818                       PRINTER_LIST_COL_JOBS, gtk_printer_get_job_count (printer),
819                       PRINTER_LIST_COL_LOCATION, gtk_printer_get_location (printer),
820                       -1);
821
822   /* When the pause state change then we need to update sensitive property
823    * of GTK_RESPONSE_OK button inside of selected_printer_changed function.
824    */
825   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
826   selected_printer_changed (selection, dialog);
827
828   if (gtk_print_backend_printer_list_is_done (backend) &&
829       gtk_printer_is_default (printer) &&
830       (gtk_tree_selection_count_selected_rows (selection) == 0))
831     set_active_printer (dialog, gtk_printer_get_name (printer));
832 }
833
834 static void
835 printer_added_cb (GtkPrintBackend    *backend,
836                   GtkPrinter         *printer,
837                   GtkPrintUnixDialog *dialog)
838 {
839   GtkPrintUnixDialogPrivate *priv = dialog->priv;
840   GtkTreeIter iter, filter_iter;
841   GtkTreeSelection *selection;
842   GtkTreePath *path;
843
844   gtk_list_store_append (GTK_LIST_STORE (priv->printer_list), &iter);
845
846   g_object_set_data_full (G_OBJECT (printer),
847                          "gtk-print-tree-iter",
848                           gtk_tree_iter_copy (&iter),
849                           (GDestroyNotify) gtk_tree_iter_free);
850
851   gtk_list_store_set (GTK_LIST_STORE (priv->printer_list), &iter,
852                       PRINTER_LIST_COL_ICON, gtk_printer_get_icon_name (printer),
853                       PRINTER_LIST_COL_NAME, gtk_printer_get_name (printer),
854                       PRINTER_LIST_COL_STATE, gtk_printer_get_state_message (printer),
855                       PRINTER_LIST_COL_JOBS, gtk_printer_get_job_count (printer),
856                       PRINTER_LIST_COL_LOCATION, gtk_printer_get_location (printer),
857                       PRINTER_LIST_COL_PRINTER_OBJ, printer,
858                       -1);
859
860   gtk_tree_model_filter_convert_child_iter_to_iter (priv->printer_list_filter,
861                                                     &filter_iter, &iter);
862   path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->printer_list_filter), &filter_iter);
863
864   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
865
866   if (priv->waiting_for_printer != NULL &&
867       strcmp (gtk_printer_get_name (printer), priv->waiting_for_printer) == 0)
868     {
869       priv->internal_printer_change = TRUE;
870       gtk_tree_selection_select_iter (selection, &filter_iter);
871       gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->printer_treeview),
872                                     path, NULL, TRUE, 0.5, 0.0);
873       priv->internal_printer_change = FALSE;
874       g_free (priv->waiting_for_printer);
875       priv->waiting_for_printer = NULL;
876     }
877   else if (is_default_printer (dialog, printer) &&
878            gtk_tree_selection_count_selected_rows (selection) == 0)
879     {
880       priv->internal_printer_change = TRUE;
881       gtk_tree_selection_select_iter (selection, &filter_iter);
882       gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->printer_treeview),
883                                     path, NULL, TRUE, 0.5, 0.0);
884       priv->internal_printer_change = FALSE;
885     }
886
887   gtk_tree_path_free (path);
888 }
889
890 static void
891 printer_list_initialize (GtkPrintUnixDialog *dialog,
892                          GtkPrintBackend    *print_backend)
893 {
894   GList *list;
895   GList *node;
896
897   g_return_if_fail (print_backend != NULL);
898
899   g_signal_connect_object (print_backend, "printer-added",
900                            (GCallback) printer_added_cb, G_OBJECT (dialog), 0);
901
902   g_signal_connect_object (print_backend, "printer-removed",
903                            (GCallback) printer_removed_cb, G_OBJECT (dialog), 0);
904
905   g_signal_connect_object (print_backend, "printer-status-changed",
906                            (GCallback) printer_status_cb, G_OBJECT (dialog), 0);
907
908   list = gtk_print_backend_get_printer_list (print_backend);
909
910   node = list;
911   while (node != NULL)
912     {
913       printer_added_cb (print_backend, node->data, dialog);
914       node = node->next;
915     }
916
917   g_list_free (list);
918 }
919
920 static void
921 load_print_backends (GtkPrintUnixDialog *dialog)
922 {
923   GtkPrintUnixDialogPrivate *priv = dialog->priv;
924   GList *node;
925
926   if (g_module_supported ())
927     priv->print_backends = gtk_print_backend_load_modules ();
928
929   for (node = priv->print_backends; node != NULL; node = node->next)
930     {
931       GtkPrintBackend *backend = node->data;
932       printer_list_initialize (dialog, backend);
933     }
934 }
935
936 static void
937 gtk_print_unix_dialog_set_property (GObject      *object,
938                                     guint         prop_id,
939                                     const GValue *value,
940                                     GParamSpec   *pspec)
941
942 {
943   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
944
945   switch (prop_id)
946     {
947     case PROP_PAGE_SETUP:
948       gtk_print_unix_dialog_set_page_setup (dialog, g_value_get_object (value));
949       break;
950     case PROP_CURRENT_PAGE:
951       gtk_print_unix_dialog_set_current_page (dialog, g_value_get_int (value));
952       break;
953     case PROP_PRINT_SETTINGS:
954       gtk_print_unix_dialog_set_settings (dialog, g_value_get_object (value));
955       break;
956     case PROP_MANUAL_CAPABILITIES:
957       gtk_print_unix_dialog_set_manual_capabilities (dialog, g_value_get_flags (value));
958       break;
959     case PROP_SUPPORT_SELECTION:
960       gtk_print_unix_dialog_set_support_selection (dialog, g_value_get_boolean (value));
961       break;
962     case PROP_HAS_SELECTION:
963       gtk_print_unix_dialog_set_has_selection (dialog, g_value_get_boolean (value));
964       break;
965     case PROP_EMBED_PAGE_SETUP:
966       gtk_print_unix_dialog_set_embed_page_setup (dialog, g_value_get_boolean (value));
967       break;
968     default:
969       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
970       break;
971     }
972 }
973
974 static void
975 gtk_print_unix_dialog_get_property (GObject    *object,
976                                     guint       prop_id,
977                                     GValue     *value,
978                                     GParamSpec *pspec)
979 {
980   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
981   GtkPrintUnixDialogPrivate *priv = dialog->priv;
982
983   switch (prop_id)
984     {
985     case PROP_PAGE_SETUP:
986       g_value_set_object (value, priv->page_setup);
987       break;
988     case PROP_CURRENT_PAGE:
989       g_value_set_int (value, priv->current_page);
990       break;
991     case PROP_PRINT_SETTINGS:
992       g_value_take_object (value, gtk_print_unix_dialog_get_settings (dialog));
993       break;
994     case PROP_SELECTED_PRINTER:
995       g_value_set_object (value, priv->current_printer);
996       break;
997     case PROP_MANUAL_CAPABILITIES:
998       g_value_set_flags (value, priv->manual_capabilities);
999       break;
1000     case PROP_SUPPORT_SELECTION:
1001       g_value_set_boolean (value, priv->support_selection);
1002       break;
1003     case PROP_HAS_SELECTION:
1004       g_value_set_boolean (value, priv->has_selection);
1005       break;
1006     case PROP_EMBED_PAGE_SETUP:
1007       g_value_set_boolean (value, priv->embed_page_setup);
1008       break;
1009     default:
1010       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1011       break;
1012     }
1013 }
1014
1015 static gboolean
1016 is_printer_active (GtkTreeModel       *model,
1017                    GtkTreeIter        *iter,
1018                    GtkPrintUnixDialog *dialog)
1019 {
1020   gboolean result;
1021   GtkPrinter *printer;
1022   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1023
1024   gtk_tree_model_get (model, iter,
1025                       PRINTER_LIST_COL_PRINTER_OBJ, &printer,
1026                       -1);
1027
1028   if (printer == NULL)
1029     return FALSE;
1030
1031   result = gtk_printer_is_active (printer);
1032
1033   if (result &&
1034       priv->manual_capabilities & (GTK_PRINT_CAPABILITY_GENERATE_PDF |
1035                                    GTK_PRINT_CAPABILITY_GENERATE_PS))
1036     {
1037        /* Check that the printer can handle at least one of the data
1038         * formats that the application supports.
1039         */
1040        result = ((priv->manual_capabilities & GTK_PRINT_CAPABILITY_GENERATE_PDF) &&
1041                  gtk_printer_accepts_pdf (printer)) ||
1042                 ((priv->manual_capabilities & GTK_PRINT_CAPABILITY_GENERATE_PS) &&
1043                  gtk_printer_accepts_ps (printer));
1044     }
1045
1046   g_object_unref (printer);
1047
1048   return result;
1049 }
1050
1051 static gint
1052 default_printer_list_sort_func (GtkTreeModel *model,
1053                                 GtkTreeIter  *a,
1054                                 GtkTreeIter  *b,
1055                                 gpointer      user_data)
1056 {
1057   gchar *a_name;
1058   gchar *b_name;
1059   GtkPrinter *a_printer;
1060   GtkPrinter *b_printer;
1061   gint result;
1062
1063   gtk_tree_model_get (model, a,
1064                       PRINTER_LIST_COL_NAME, &a_name,
1065                       PRINTER_LIST_COL_PRINTER_OBJ, &a_printer,
1066                       -1);
1067   gtk_tree_model_get (model, b,
1068                       PRINTER_LIST_COL_NAME, &b_name,
1069                       PRINTER_LIST_COL_PRINTER_OBJ, &b_printer,
1070                       -1);
1071
1072   if (a_printer == NULL && b_printer == NULL)
1073     result = 0;
1074   else if (a_printer == NULL)
1075    result = G_MAXINT;
1076   else if (b_printer == NULL)
1077    result = G_MININT;
1078   else if (gtk_printer_is_virtual (a_printer) && gtk_printer_is_virtual (b_printer))
1079     result = 0;
1080   else if (gtk_printer_is_virtual (a_printer) && !gtk_printer_is_virtual (b_printer))
1081     result = G_MININT;
1082   else if (!gtk_printer_is_virtual (a_printer) && gtk_printer_is_virtual (b_printer))
1083     result = G_MAXINT;
1084   else if (a_name == NULL && b_name == NULL)
1085     result = 0;
1086   else if (a_name == NULL && b_name != NULL)
1087     result = 1;
1088   else if (a_name != NULL && b_name == NULL)
1089     result = -1;
1090   else
1091     result = g_ascii_strcasecmp (a_name, b_name);
1092
1093   g_free (a_name);
1094   g_free (b_name);
1095   if (a_printer)
1096     g_object_unref (a_printer);
1097   if (b_printer)
1098     g_object_unref (b_printer);
1099
1100   return result;
1101 }
1102
1103 static void
1104 create_printer_list_model (GtkPrintUnixDialog *dialog)
1105 {
1106   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1107   GtkListStore *model;
1108   GtkTreeSortable *sort;
1109
1110   model = gtk_list_store_new (PRINTER_LIST_N_COLS,
1111                               G_TYPE_STRING,
1112                               G_TYPE_STRING,
1113                               G_TYPE_STRING,
1114                               G_TYPE_INT,
1115                               G_TYPE_STRING,
1116                               G_TYPE_OBJECT);
1117
1118   priv->printer_list = (GtkTreeModel *)model;
1119   priv->printer_list_filter = (GtkTreeModelFilter *) gtk_tree_model_filter_new ((GtkTreeModel *)model,
1120                                                                                         NULL);
1121
1122   gtk_tree_model_filter_set_visible_func (priv->printer_list_filter,
1123                                           (GtkTreeModelFilterVisibleFunc) is_printer_active,
1124                                           dialog,
1125                                           NULL);
1126
1127   sort = GTK_TREE_SORTABLE (model);
1128   gtk_tree_sortable_set_default_sort_func (sort,
1129                                            default_printer_list_sort_func,
1130                                            NULL,
1131                                            NULL);
1132
1133   gtk_tree_sortable_set_sort_column_id (sort,
1134                                         GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
1135                                         GTK_SORT_ASCENDING);
1136
1137 }
1138
1139
1140 static GtkWidget *
1141 wrap_in_frame (const gchar *label,
1142                GtkWidget   *child)
1143 {
1144   GtkWidget *frame, *label_widget;
1145   gchar *bold_text;
1146
1147   label_widget = gtk_label_new (NULL);
1148   gtk_widget_set_halign (label_widget, GTK_ALIGN_START);
1149   gtk_widget_set_valign (label_widget, GTK_ALIGN_CENTER);
1150   gtk_widget_show (label_widget);
1151
1152   bold_text = g_markup_printf_escaped ("<b>%s</b>", label);
1153   gtk_label_set_markup (GTK_LABEL (label_widget), bold_text);
1154   g_free (bold_text);
1155
1156   frame = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
1157   gtk_box_pack_start (GTK_BOX (frame), label_widget, FALSE, FALSE, 0);
1158
1159   gtk_widget_set_margin_left (child, 12);
1160   gtk_widget_set_halign (child, GTK_ALIGN_FILL);
1161   gtk_widget_set_valign (child, GTK_ALIGN_FILL);
1162
1163   gtk_box_pack_start (GTK_BOX (frame), child, FALSE, FALSE, 0);
1164
1165   gtk_widget_show (frame);
1166
1167   return frame;
1168 }
1169
1170 static gboolean
1171 setup_option (GtkPrintUnixDialog     *dialog,
1172               const gchar            *option_name,
1173               GtkPrinterOptionWidget *widget)
1174 {
1175   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1176   GtkPrinterOption *option;
1177
1178   option = gtk_printer_option_set_lookup (priv->options, option_name);
1179   gtk_printer_option_widget_set_source (widget, option);
1180
1181   return option != NULL;
1182 }
1183
1184 static void
1185 add_option_to_extension_point (GtkPrinterOption *option,
1186                                gpointer          data)
1187 {
1188   GtkWidget *extension_point = data;
1189   GtkWidget *widget;
1190
1191   widget = gtk_printer_option_widget_new (option);
1192   gtk_widget_show (widget);
1193
1194   if (gtk_printer_option_widget_has_external_label (GTK_PRINTER_OPTION_WIDGET (widget)))
1195     {
1196       GtkWidget *label, *hbox;
1197
1198       label = gtk_printer_option_widget_get_external_label (GTK_PRINTER_OPTION_WIDGET (widget));
1199       gtk_widget_show (label);
1200       gtk_widget_set_halign (label, GTK_ALIGN_START);
1201       gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
1202       gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
1203
1204       hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
1205       gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1206       gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
1207       gtk_widget_show (hbox);
1208
1209       gtk_box_pack_start (GTK_BOX (extension_point), hbox, FALSE, FALSE, 0);
1210     }
1211   else
1212     gtk_box_pack_start (GTK_BOX (extension_point), widget, FALSE, FALSE, 0);
1213 }
1214
1215 static gint
1216 grid_rows (GtkGrid *table)
1217 {
1218   gint t0, t1, t, h;
1219   GList *children, *c;
1220
1221   children = gtk_container_get_children (GTK_CONTAINER (table));
1222   t0 = t1 = 0;
1223   for (c = children; c; c = c->next)
1224     {
1225       gtk_container_child_get (GTK_CONTAINER (table), c->data,
1226                                "top-attach", &t,
1227                                "height", &h,
1228                                NULL);
1229       if (c == children)
1230         {
1231           t0 = t;
1232           t1 = t + h;
1233         }
1234       else
1235         {
1236           if (t < t0)
1237             t0 = t;
1238           if (t + h > t1)
1239             t1 = t + h;
1240         }
1241     }
1242   g_list_free (children);
1243
1244   return t1 - t0;
1245 }
1246
1247 static void
1248 add_option_to_table (GtkPrinterOption *option,
1249                      gpointer          user_data)
1250 {
1251   GtkGrid *table;
1252   GtkWidget *label, *widget;
1253   guint row;
1254
1255   table = GTK_GRID (user_data);
1256
1257   if (g_str_has_prefix (option->name, "gtk-"))
1258     return;
1259
1260   row = grid_rows (table);
1261
1262   widget = gtk_printer_option_widget_new (option);
1263   gtk_widget_show (widget);
1264
1265   if (gtk_printer_option_widget_has_external_label (GTK_PRINTER_OPTION_WIDGET (widget)))
1266     {
1267       label = gtk_printer_option_widget_get_external_label (GTK_PRINTER_OPTION_WIDGET (widget));
1268       gtk_widget_show (label);
1269
1270       gtk_widget_set_halign (label, GTK_ALIGN_START);
1271       gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
1272       gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
1273
1274       gtk_grid_attach (table, label, 0, row - 1, 1, 1);
1275       gtk_grid_attach (table, widget, 1, row - 1, 1, 1);
1276     }
1277   else
1278     gtk_grid_attach (table, widget, 0, row - 1, 2, 1);
1279 }
1280
1281 static void
1282 setup_page_table (GtkPrinterOptionSet *options,
1283                   const gchar         *group,
1284                   GtkWidget           *table,
1285                   GtkWidget           *page)
1286 {
1287   gint nrows;
1288
1289   gtk_printer_option_set_foreach_in_group (options, group,
1290                                            add_option_to_table,
1291                                            table);
1292
1293   nrows = grid_rows (GTK_GRID (table));
1294   if (nrows == 0)
1295     gtk_widget_hide (page);
1296   else
1297     gtk_widget_show (page);
1298 }
1299
1300 static void
1301 update_print_at_option (GtkPrintUnixDialog *dialog)
1302 {
1303   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1304   GtkPrinterOption *option;
1305
1306   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time");
1307
1308   if (option == NULL)
1309     return;
1310
1311   if (priv->updating_print_at)
1312     return;
1313
1314   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->print_at_radio)))
1315     gtk_printer_option_set (option, "at");
1316   else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->print_hold_radio)))
1317     gtk_printer_option_set (option, "on-hold");
1318   else
1319     gtk_printer_option_set (option, "now");
1320
1321   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time-text");
1322   if (option != NULL)
1323     {
1324       const gchar *text;
1325
1326       text = gtk_entry_get_text (GTK_ENTRY (priv->print_at_entry));
1327       gtk_printer_option_set (option, text);
1328     }
1329 }
1330
1331
1332 static gboolean
1333 setup_print_at (GtkPrintUnixDialog *dialog)
1334 {
1335   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1336   GtkPrinterOption *option;
1337
1338   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time");
1339
1340   if (option == NULL)
1341     {
1342       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_now_radio),
1343                                     TRUE);
1344       gtk_widget_set_sensitive (priv->print_at_radio, FALSE);
1345       gtk_widget_set_sensitive (priv->print_at_entry, FALSE);
1346       gtk_widget_set_sensitive (priv->print_hold_radio, FALSE);
1347       gtk_entry_set_text (GTK_ENTRY (priv->print_at_entry), "");
1348       return FALSE;
1349     }
1350
1351   priv->updating_print_at = TRUE;
1352
1353   gtk_widget_set_sensitive (priv->print_at_entry, FALSE);
1354   gtk_widget_set_sensitive (priv->print_at_radio,
1355                             gtk_printer_option_has_choice (option, "at"));
1356
1357   gtk_widget_set_sensitive (priv->print_hold_radio,
1358                             gtk_printer_option_has_choice (option, "on-hold"));
1359
1360   update_print_at_option (dialog);
1361
1362   if (strcmp (option->value, "at") == 0)
1363     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_at_radio),
1364                                   TRUE);
1365   else if (strcmp (option->value, "on-hold") == 0)
1366     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_hold_radio),
1367                                   TRUE);
1368   else
1369     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_now_radio),
1370                                   TRUE);
1371
1372   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time-text");
1373   if (option != NULL)
1374     gtk_entry_set_text (GTK_ENTRY (priv->print_at_entry), option->value);
1375
1376   priv->updating_print_at = FALSE;
1377
1378   return TRUE;
1379 }
1380
1381 static void
1382 update_dialog_from_settings (GtkPrintUnixDialog *dialog)
1383 {
1384   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1385   GList *groups, *l;
1386   gchar *group;
1387   GtkWidget *table, *frame;
1388   gboolean has_advanced, has_job;
1389   guint nrows;
1390
1391   if (priv->current_printer == NULL)
1392     {
1393        clear_per_printer_ui (dialog);
1394        gtk_widget_hide (priv->job_page);
1395        gtk_widget_hide (priv->advanced_page);
1396        gtk_widget_hide (priv->image_quality_page);
1397        gtk_widget_hide (priv->finishing_page);
1398        gtk_widget_hide (priv->color_page);
1399        gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
1400
1401        return;
1402     }
1403
1404   setup_option (dialog, "gtk-n-up", priv->pages_per_sheet);
1405   setup_option (dialog, "gtk-n-up-layout", priv->number_up_layout);
1406   setup_option (dialog, "gtk-duplex", priv->duplex);
1407   setup_option (dialog, "gtk-paper-type", priv->paper_type);
1408   setup_option (dialog, "gtk-paper-source", priv->paper_source);
1409   setup_option (dialog, "gtk-output-tray", priv->output_tray);
1410
1411   has_job = FALSE;
1412   has_job |= setup_option (dialog, "gtk-job-prio", priv->job_prio);
1413   has_job |= setup_option (dialog, "gtk-billing-info", priv->billing_info);
1414   has_job |= setup_option (dialog, "gtk-cover-before", priv->cover_before);
1415   has_job |= setup_option (dialog, "gtk-cover-after", priv->cover_after);
1416   has_job |= setup_print_at (dialog);
1417
1418   if (has_job)
1419     gtk_widget_show (priv->job_page);
1420   else
1421     gtk_widget_hide (priv->job_page);
1422
1423   setup_page_table (priv->options,
1424                     "ImageQualityPage",
1425                     priv->image_quality_table,
1426                     priv->image_quality_page);
1427
1428   setup_page_table (priv->options,
1429                     "FinishingPage",
1430                     priv->finishing_table,
1431                     priv->finishing_page);
1432
1433   setup_page_table (priv->options,
1434                     "ColorPage",
1435                     priv->color_table,
1436                     priv->color_page);
1437
1438   gtk_printer_option_set_foreach_in_group (priv->options,
1439                                            "GtkPrintDialogExtension",
1440                                            add_option_to_extension_point,
1441                                            priv->extension_point);
1442
1443   /* Put the rest of the groups in the advanced page */
1444   groups = gtk_printer_option_set_get_groups (priv->options);
1445
1446   has_advanced = FALSE;
1447   for (l = groups; l != NULL; l = l->next)
1448     {
1449       group = l->data;
1450
1451       if (group == NULL)
1452         continue;
1453
1454       if (strcmp (group, "ImageQualityPage") == 0 ||
1455           strcmp (group, "ColorPage") == 0 ||
1456           strcmp (group, "FinishingPage") == 0 ||
1457           strcmp (group, "GtkPrintDialogExtension") == 0)
1458         continue;
1459
1460       table = gtk_grid_new ();
1461       gtk_grid_set_row_spacing (GTK_GRID (table), 6);
1462       gtk_grid_set_column_spacing (GTK_GRID (table), 12);
1463
1464       gtk_printer_option_set_foreach_in_group (priv->options,
1465                                                group,
1466                                                add_option_to_table,
1467                                                table);
1468
1469       nrows = grid_rows (GTK_GRID (table));
1470       if (nrows == 0)
1471         gtk_widget_destroy (table);
1472       else
1473         {
1474           has_advanced = TRUE;
1475           frame = wrap_in_frame (group, table);
1476           gtk_widget_show (table);
1477           gtk_widget_show (frame);
1478
1479           gtk_box_pack_start (GTK_BOX (priv->advanced_vbox),
1480                               frame, FALSE, FALSE, 0);
1481         }
1482     }
1483
1484   if (has_advanced)
1485     gtk_widget_show (priv->advanced_page);
1486   else
1487     gtk_widget_hide (priv->advanced_page);
1488
1489   g_list_free_full (groups, g_free);
1490 }
1491
1492 static void
1493 update_dialog_from_capabilities (GtkPrintUnixDialog *dialog)
1494 {
1495   GtkPrintCapabilities caps;
1496   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1497   gboolean can_collate;
1498   const gchar *copies;
1499
1500   copies = gtk_entry_get_text (GTK_ENTRY (priv->copies_spin));
1501   can_collate = (*copies != '\0' && atoi (copies) > 1);
1502
1503   caps = priv->manual_capabilities | priv->printer_capabilities;
1504
1505   gtk_widget_set_sensitive (priv->page_set_combo,
1506                             caps & GTK_PRINT_CAPABILITY_PAGE_SET);
1507   gtk_widget_set_sensitive (priv->copies_spin,
1508                             caps & GTK_PRINT_CAPABILITY_COPIES);
1509   gtk_widget_set_sensitive (priv->collate_check,
1510                             can_collate &&
1511                             (caps & GTK_PRINT_CAPABILITY_COLLATE));
1512   gtk_widget_set_sensitive (priv->reverse_check,
1513                             caps & GTK_PRINT_CAPABILITY_REVERSE);
1514   gtk_widget_set_sensitive (priv->scale_spin,
1515                             caps & GTK_PRINT_CAPABILITY_SCALE);
1516   gtk_widget_set_sensitive (GTK_WIDGET (priv->pages_per_sheet),
1517                             caps & GTK_PRINT_CAPABILITY_NUMBER_UP);
1518
1519   if (caps & GTK_PRINT_CAPABILITY_PREVIEW)
1520     gtk_widget_show (priv->preview_button);
1521   else
1522     gtk_widget_hide (priv->preview_button);
1523
1524   update_collate_icon (NULL, dialog);
1525
1526   gtk_tree_model_filter_refilter (priv->printer_list_filter);
1527 }
1528
1529 static gboolean
1530 page_setup_is_equal (GtkPageSetup *a,
1531                      GtkPageSetup *b)
1532 {
1533   return
1534     gtk_paper_size_is_equal (gtk_page_setup_get_paper_size (a),
1535                              gtk_page_setup_get_paper_size (b)) &&
1536     gtk_page_setup_get_top_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_top_margin (b, GTK_UNIT_MM) &&
1537     gtk_page_setup_get_bottom_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_bottom_margin (b, GTK_UNIT_MM) &&
1538     gtk_page_setup_get_left_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_left_margin (b, GTK_UNIT_MM) &&
1539     gtk_page_setup_get_right_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_right_margin (b, GTK_UNIT_MM);
1540 }
1541
1542 static gboolean
1543 page_setup_is_same_size (GtkPageSetup *a,
1544                          GtkPageSetup *b)
1545 {
1546   return gtk_paper_size_is_equal (gtk_page_setup_get_paper_size (a),
1547                                   gtk_page_setup_get_paper_size (b));
1548 }
1549
1550 static gboolean
1551 set_paper_size (GtkPrintUnixDialog *dialog,
1552                 GtkPageSetup       *page_setup,
1553                 gboolean            size_only,
1554                 gboolean            add_item)
1555 {
1556   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1557   GtkTreeModel *model;
1558   GtkTreeIter iter;
1559   GtkPageSetup *list_page_setup;
1560
1561   if (!priv->internal_page_setup_change)
1562     return TRUE;
1563
1564   if (page_setup == NULL)
1565     return FALSE;
1566
1567   model = GTK_TREE_MODEL (priv->page_setup_list);
1568
1569   if (gtk_tree_model_get_iter_first (model, &iter))
1570     {
1571       do
1572         {
1573           gtk_tree_model_get (GTK_TREE_MODEL (priv->page_setup_list), &iter,
1574                               PAGE_SETUP_LIST_COL_PAGE_SETUP, &list_page_setup,
1575                               -1);
1576           if (list_page_setup == NULL)
1577             continue;
1578
1579           if ((size_only && page_setup_is_same_size (page_setup, list_page_setup)) ||
1580               (!size_only && page_setup_is_equal (page_setup, list_page_setup)))
1581             {
1582               gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->paper_size_combo),
1583                                              &iter);
1584               gtk_combo_box_set_active (GTK_COMBO_BOX (priv->orientation_combo),
1585                                         gtk_page_setup_get_orientation (page_setup));
1586               g_object_unref (list_page_setup);
1587               return TRUE;
1588             }
1589
1590           g_object_unref (list_page_setup);
1591
1592         } while (gtk_tree_model_iter_next (model, &iter));
1593     }
1594
1595   if (add_item)
1596     {
1597       gtk_list_store_append (priv->page_setup_list, &iter);
1598       gtk_list_store_set (priv->page_setup_list, &iter,
1599                           PAGE_SETUP_LIST_COL_IS_SEPARATOR, TRUE,
1600                           -1);
1601       gtk_list_store_append (priv->page_setup_list, &iter);
1602       gtk_list_store_set (priv->page_setup_list, &iter,
1603                           PAGE_SETUP_LIST_COL_PAGE_SETUP, page_setup,
1604                           -1);
1605       gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->paper_size_combo),
1606                                      &iter);
1607       gtk_combo_box_set_active (GTK_COMBO_BOX (priv->orientation_combo),
1608                                 gtk_page_setup_get_orientation (page_setup));
1609       return TRUE;
1610     }
1611
1612   return FALSE;
1613 }
1614
1615 static void
1616 fill_custom_paper_sizes (GtkPrintUnixDialog *dialog)
1617 {
1618   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1619   GtkTreeIter iter, paper_iter;
1620   GtkTreeModel *model;
1621
1622   model = GTK_TREE_MODEL (priv->custom_paper_list);
1623   if (gtk_tree_model_get_iter_first (model, &iter))
1624     {
1625       gtk_list_store_append (priv->page_setup_list, &paper_iter);
1626       gtk_list_store_set (priv->page_setup_list, &paper_iter,
1627                           PAGE_SETUP_LIST_COL_IS_SEPARATOR, TRUE,
1628                           -1);
1629       do
1630         {
1631           GtkPageSetup *page_setup;
1632           gtk_tree_model_get (model, &iter, 0, &page_setup, -1);
1633
1634           gtk_list_store_append (priv->page_setup_list, &paper_iter);
1635           gtk_list_store_set (priv->page_setup_list, &paper_iter,
1636                               PAGE_SETUP_LIST_COL_PAGE_SETUP, page_setup,
1637                               -1);
1638
1639           g_object_unref (page_setup);
1640         } while (gtk_tree_model_iter_next (model, &iter));
1641     }
1642
1643   gtk_list_store_append (priv->page_setup_list, &paper_iter);
1644   gtk_list_store_set (priv->page_setup_list, &paper_iter,
1645                       PAGE_SETUP_LIST_COL_IS_SEPARATOR, TRUE,
1646                       -1);
1647   gtk_list_store_append (priv->page_setup_list, &paper_iter);
1648   gtk_list_store_set (priv->page_setup_list, &paper_iter,
1649                       PAGE_SETUP_LIST_COL_PAGE_SETUP, NULL,
1650                       -1);
1651 }
1652
1653 static void
1654 fill_paper_sizes (GtkPrintUnixDialog *dialog,
1655                   GtkPrinter         *printer)
1656 {
1657   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1658   GList *list, *l;
1659   GtkPageSetup *page_setup;
1660   GtkPaperSize *paper_size;
1661   GtkTreeIter iter;
1662   gint i;
1663
1664   gtk_list_store_clear (priv->page_setup_list);
1665
1666   if (printer == NULL || (list = gtk_printer_list_papers (printer)) == NULL)
1667     {
1668       for (i = 0; i < G_N_ELEMENTS (common_paper_sizes); i++)
1669         {
1670           page_setup = gtk_page_setup_new ();
1671           paper_size = gtk_paper_size_new (common_paper_sizes[i]);
1672           gtk_page_setup_set_paper_size_and_default_margins (page_setup, paper_size);
1673           gtk_paper_size_free (paper_size);
1674
1675           gtk_list_store_append (priv->page_setup_list, &iter);
1676           gtk_list_store_set (priv->page_setup_list, &iter,
1677                               PAGE_SETUP_LIST_COL_PAGE_SETUP, page_setup,
1678                               -1);
1679           g_object_unref (page_setup);
1680         }
1681     }
1682   else
1683     {
1684       for (l = list; l != NULL; l = l->next)
1685         {
1686           page_setup = l->data;
1687           gtk_list_store_append (priv->page_setup_list, &iter);
1688           gtk_list_store_set (priv->page_setup_list, &iter,
1689                               PAGE_SETUP_LIST_COL_PAGE_SETUP, page_setup,
1690                               -1);
1691           g_object_unref (page_setup);
1692         }
1693       g_list_free (list);
1694     }
1695
1696   fill_custom_paper_sizes (dialog);
1697 }
1698
1699 static void
1700 update_paper_sizes (GtkPrintUnixDialog *dialog)
1701 {
1702   GtkPageSetup *current_page_setup = NULL;
1703   GtkPrinter   *printer;
1704
1705   printer = gtk_print_unix_dialog_get_selected_printer (dialog);
1706
1707   fill_paper_sizes (dialog, printer);
1708
1709   current_page_setup = gtk_page_setup_copy (gtk_print_unix_dialog_get_page_setup (dialog));
1710
1711   if (current_page_setup)
1712     {
1713       if (!set_paper_size (dialog, current_page_setup, FALSE, FALSE))
1714         set_paper_size (dialog, current_page_setup, TRUE, TRUE);
1715
1716       g_object_unref (current_page_setup);
1717     }
1718 }
1719
1720 static void
1721 mark_conflicts (GtkPrintUnixDialog *dialog)
1722 {
1723   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1724   GtkPrinter *printer;
1725   gboolean have_conflict;
1726
1727   have_conflict = FALSE;
1728
1729   printer = priv->current_printer;
1730
1731   if (printer)
1732     {
1733
1734       g_signal_handler_block (priv->options,
1735                               priv->options_changed_handler);
1736
1737       gtk_printer_option_set_clear_conflicts (priv->options);
1738
1739       have_conflict = _gtk_printer_mark_conflicts (printer,
1740                                                    priv->options);
1741
1742       g_signal_handler_unblock (priv->options,
1743                                 priv->options_changed_handler);
1744     }
1745
1746   if (have_conflict)
1747     gtk_widget_show (priv->conflicts_widget);
1748   else
1749     gtk_widget_hide (priv->conflicts_widget);
1750 }
1751
1752 static gboolean
1753 mark_conflicts_callback (gpointer data)
1754 {
1755   GtkPrintUnixDialog *dialog = data;
1756   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1757
1758   priv->mark_conflicts_id = 0;
1759
1760   mark_conflicts (dialog);
1761
1762   return FALSE;
1763 }
1764
1765 static void
1766 unschedule_idle_mark_conflicts (GtkPrintUnixDialog *dialog)
1767 {
1768   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1769
1770   if (priv->mark_conflicts_id != 0)
1771     {
1772       g_source_remove (priv->mark_conflicts_id);
1773       priv->mark_conflicts_id = 0;
1774     }
1775 }
1776
1777 static void
1778 schedule_idle_mark_conflicts (GtkPrintUnixDialog *dialog)
1779 {
1780   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1781
1782   if (priv->mark_conflicts_id != 0)
1783     return;
1784
1785   priv->mark_conflicts_id = gdk_threads_add_idle (mark_conflicts_callback,
1786                                         dialog);
1787 }
1788
1789 static void
1790 options_changed_cb (GtkPrintUnixDialog *dialog)
1791 {
1792   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1793
1794   schedule_idle_mark_conflicts (dialog);
1795
1796   g_free (priv->waiting_for_printer);
1797   priv->waiting_for_printer = NULL;
1798 }
1799
1800 static void
1801 remove_custom_widget (GtkWidget    *widget,
1802                       GtkContainer *container)
1803 {
1804   gtk_container_remove (container, widget);
1805 }
1806
1807 static void
1808 extension_point_clear_children (GtkContainer *container)
1809 {
1810   gtk_container_foreach (container,
1811                          (GtkCallback)remove_custom_widget,
1812                          container);
1813 }
1814
1815 static void
1816 clear_per_printer_ui (GtkPrintUnixDialog *dialog)
1817 {
1818   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1819
1820   gtk_container_foreach (GTK_CONTAINER (priv->finishing_table),
1821                          (GtkCallback)gtk_widget_destroy, NULL);
1822   gtk_container_foreach (GTK_CONTAINER (priv->image_quality_table),
1823                          (GtkCallback)gtk_widget_destroy, NULL);
1824   gtk_container_foreach (GTK_CONTAINER (priv->color_table),
1825                          (GtkCallback)gtk_widget_destroy, NULL);
1826   gtk_container_foreach (GTK_CONTAINER (priv->advanced_vbox),
1827                          (GtkCallback)gtk_widget_destroy, NULL);
1828   extension_point_clear_children (GTK_CONTAINER (priv->extension_point));
1829 }
1830
1831 static void
1832 printer_details_acquired (GtkPrinter         *printer,
1833                           gboolean            success,
1834                           GtkPrintUnixDialog *dialog)
1835 {
1836   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1837
1838   disconnect_printer_details_request (dialog, !success);
1839
1840   if (success)
1841     {
1842       GtkTreeSelection *selection;
1843       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
1844
1845       selected_printer_changed (selection, dialog);
1846     }
1847 }
1848
1849 static void
1850 selected_printer_changed (GtkTreeSelection   *selection,
1851                           GtkPrintUnixDialog *dialog)
1852 {
1853   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1854   GtkPrinter *printer;
1855   GtkTreeIter iter, filter_iter;
1856
1857   /* Whenever the user selects a printer we stop looking for
1858    * the printer specified in the initial settings
1859    */
1860   if (priv->waiting_for_printer &&
1861       !priv->internal_printer_change)
1862     {
1863       g_free (priv->waiting_for_printer);
1864       priv->waiting_for_printer = NULL;
1865     }
1866
1867   disconnect_printer_details_request (dialog, FALSE);
1868
1869   printer = NULL;
1870   if (gtk_tree_selection_get_selected (selection, NULL, &filter_iter))
1871     {
1872       gtk_tree_model_filter_convert_iter_to_child_iter (priv->printer_list_filter,
1873                                                         &iter,
1874                                                         &filter_iter);
1875
1876       gtk_tree_model_get (priv->printer_list, &iter,
1877                           PRINTER_LIST_COL_PRINTER_OBJ, &printer,
1878                           -1);
1879     }
1880
1881   /* sets GTK_RESPONSE_OK button sensitivity depending on whether the printer
1882    * accepts/rejects jobs
1883    */
1884   if (printer != NULL)
1885     {
1886       if (!gtk_printer_is_accepting_jobs (printer))
1887         gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
1888       else if (priv->current_printer == printer && gtk_printer_has_details (printer))
1889
1890         gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
1891     }
1892
1893   if (printer != NULL && !gtk_printer_has_details (printer))
1894     {
1895       gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
1896       priv->request_details_tag =
1897         g_signal_connect (printer, "details-acquired",
1898                           G_CALLBACK (printer_details_acquired), dialog);
1899       /* take the reference */
1900       priv->request_details_printer = printer;
1901       gtk_printer_request_details (printer);
1902       set_busy_cursor (dialog, TRUE);
1903       gtk_list_store_set (GTK_LIST_STORE (priv->printer_list),
1904                           g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter"),
1905                           PRINTER_LIST_COL_STATE, _("Getting printer information..."),
1906                           -1);
1907       return;
1908     }
1909
1910   if (printer == priv->current_printer)
1911     {
1912       if (printer)
1913         g_object_unref (printer);
1914       return;
1915     }
1916
1917   if (priv->options)
1918     {
1919       g_clear_object (&priv->options);
1920       clear_per_printer_ui (dialog);
1921     }
1922
1923   g_clear_object (&priv->current_printer);
1924   priv->printer_capabilities = 0;
1925
1926   if (printer != NULL && gtk_printer_is_accepting_jobs (printer))
1927     gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
1928   priv->current_printer = printer;
1929
1930   if (printer != NULL)
1931     {
1932       if (!priv->page_setup_set)
1933         {
1934           /* if no explicit page setup has been set, use the printer default */
1935           GtkPageSetup *page_setup;
1936
1937           page_setup = gtk_printer_get_default_page_size (printer);
1938
1939           if (!page_setup)
1940             page_setup = gtk_page_setup_new ();
1941
1942           if (page_setup && priv->page_setup)
1943             gtk_page_setup_set_orientation (page_setup, gtk_page_setup_get_orientation (priv->page_setup));
1944
1945           g_object_unref (priv->page_setup);
1946           priv->page_setup = page_setup;
1947         }
1948
1949       priv->printer_capabilities = gtk_printer_get_capabilities (printer);
1950       priv->options = _gtk_printer_get_options (printer,
1951                                                 priv->initial_settings,
1952                                                 priv->page_setup,
1953                                                 priv->manual_capabilities);
1954
1955       priv->options_changed_handler =
1956         g_signal_connect_swapped (priv->options, "changed", G_CALLBACK (options_changed_cb), dialog);
1957       schedule_idle_mark_conflicts (dialog);
1958     }
1959
1960   update_dialog_from_settings (dialog);
1961   update_dialog_from_capabilities (dialog);
1962
1963   priv->internal_page_setup_change = TRUE;
1964   update_paper_sizes (dialog);
1965   priv->internal_page_setup_change = FALSE;
1966
1967   g_object_notify ( G_OBJECT(dialog), "selected-printer");
1968 }
1969
1970 static void
1971 update_collate_icon (GtkToggleButton    *toggle_button,
1972                      GtkPrintUnixDialog *dialog)
1973 {
1974   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1975
1976   gtk_widget_queue_draw (priv->collate_image);
1977 }
1978
1979 static void
1980 paint_page (GtkWidget *widget,
1981             cairo_t   *cr,
1982             gfloat     scale,
1983             gint       x_offset,
1984             gint       y_offset,
1985             gchar     *text,
1986             gint       text_x)
1987 {
1988   GtkStyleContext *context;
1989   gint x, y, width, height;
1990   gint text_y, linewidth;
1991   GdkRGBA color;
1992
1993   x = x_offset * scale;
1994   y = y_offset * scale;
1995   width = 20 * scale;
1996   height = 26 * scale;
1997
1998   linewidth = 2;
1999   text_y = 21;
2000
2001   context = gtk_widget_get_style_context (widget);
2002
2003   gtk_style_context_save (context);
2004   gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
2005
2006   gtk_style_context_get_background_color (context, 0, &color);
2007   gdk_cairo_set_source_rgba (cr, &color);
2008   cairo_rectangle (cr, x, y, width, height);
2009   cairo_fill (cr);
2010
2011   gtk_style_context_get_color (context, 0, &color);
2012   gdk_cairo_set_source_rgba (cr, &color);
2013   cairo_set_line_width (cr, linewidth);
2014   cairo_rectangle (cr, x + linewidth/2.0, y + linewidth/2.0, width - linewidth, height - linewidth);
2015   cairo_stroke (cr);
2016
2017   cairo_select_font_face (cr, "Sans",
2018                           CAIRO_FONT_SLANT_NORMAL,
2019                           CAIRO_FONT_WEIGHT_NORMAL);
2020   cairo_set_font_size (cr, (gint)(9 * scale));
2021   cairo_move_to (cr, x + (gint)(text_x * scale), y + (gint)(text_y * scale));
2022   cairo_show_text (cr, text);
2023
2024   gtk_style_context_restore (context);
2025 }
2026
2027 static gboolean
2028 draw_collate_cb (GtkWidget          *widget,
2029                  cairo_t            *cr,
2030                  GtkPrintUnixDialog *dialog)
2031 {
2032   GtkSettings *settings;
2033   gint size;
2034   gfloat scale;
2035   gboolean collate, reverse, rtl;
2036   gint copies;
2037   gint text_x;
2038
2039   collate = dialog_get_collate (dialog);
2040   reverse = dialog_get_reverse (dialog);
2041   copies = dialog_get_n_copies (dialog);
2042
2043   rtl = (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_RTL);
2044
2045   settings = gtk_widget_get_settings (widget);
2046   gtk_icon_size_lookup_for_settings (settings,
2047                                      GTK_ICON_SIZE_DIALOG,
2048                                      &size,
2049                                      NULL);
2050   scale = size / 48.0;
2051   text_x = rtl ? 4 : 11;
2052
2053   if (copies == 1)
2054     {
2055       paint_page (widget, cr, scale, rtl ? 40: 15, 5, reverse ? "1" : "2", text_x);
2056       paint_page (widget, cr, scale, rtl ? 50: 5, 15, reverse ? "2" : "1", text_x);
2057     }
2058   else
2059     {
2060       paint_page (widget, cr, scale, rtl ? 40: 15, 5, collate == reverse ? "1" : "2", text_x);
2061       paint_page (widget, cr, scale, rtl ? 50: 5, 15, reverse ? "2" : "1", text_x);
2062
2063       paint_page (widget, cr, scale, rtl ? 5 : 50, 5, reverse ? "1" : "2", text_x);
2064       paint_page (widget, cr, scale, rtl ? 15 : 40, 15, collate == reverse ? "2" : "1", text_x);
2065     }
2066
2067   return TRUE;
2068 }
2069
2070 static void
2071 gtk_print_unix_dialog_style_updated (GtkWidget *widget)
2072 {
2073   GTK_WIDGET_CLASS (gtk_print_unix_dialog_parent_class)->style_updated (widget);
2074
2075   if (gtk_widget_has_screen (widget))
2076     {
2077       GtkPrintUnixDialog *dialog = (GtkPrintUnixDialog *)widget;
2078       GtkPrintUnixDialogPrivate *priv = dialog->priv;
2079       GtkSettings *settings;
2080       gint size;
2081       gfloat scale;
2082
2083       settings = gtk_widget_get_settings (widget);
2084       gtk_icon_size_lookup_for_settings (settings,
2085                                          GTK_ICON_SIZE_DIALOG,
2086                                          &size,
2087                                          NULL);
2088       scale = size / 48.0;
2089
2090       gtk_widget_set_size_request (priv->collate_image,
2091                                    (50 + 20) * scale,
2092                                    (15 + 26) * scale);
2093     }
2094 }
2095
2096 static void
2097 update_entry_sensitivity (GtkWidget *button,
2098                           GtkWidget *range)
2099 {
2100   gboolean active;
2101
2102   active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
2103
2104   gtk_widget_set_sensitive (range, active);
2105
2106   if (active)
2107     gtk_widget_grab_focus (range);
2108 }
2109
2110 static void
2111 emit_ok_response (GtkTreeView       *tree_view,
2112                   GtkTreePath       *path,
2113                   GtkTreeViewColumn *column,
2114                   gpointer          *user_data)
2115 {
2116   GtkPrintUnixDialog *print_dialog;
2117
2118   print_dialog = (GtkPrintUnixDialog *) user_data;
2119
2120   gtk_dialog_response (GTK_DIALOG (print_dialog), GTK_RESPONSE_OK);
2121 }
2122
2123 static void
2124 create_main_page (GtkPrintUnixDialog *dialog)
2125 {
2126   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2127   GtkWidget *main_vbox, *label, *vbox, *hbox;
2128   GtkWidget *scrolled, *treeview, *frame, *table;
2129   GtkWidget *entry, *spinbutton;
2130   GtkWidget *radio, *check, *image;
2131   GtkCellRenderer *renderer;
2132   GtkTreeViewColumn *column;
2133   GtkTreeSelection *selection;
2134   GtkWidget *custom_input;
2135   const gchar *range_tooltip;
2136
2137   main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 18);
2138   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
2139   gtk_widget_show (main_vbox);
2140
2141   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
2142   gtk_box_pack_start (GTK_BOX (main_vbox), vbox, TRUE, TRUE, 0);
2143   gtk_widget_show (vbox);
2144
2145   scrolled = gtk_scrolled_window_new (NULL, NULL);
2146   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
2147                                   GTK_POLICY_AUTOMATIC,
2148                                   GTK_POLICY_AUTOMATIC);
2149   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
2150                                        GTK_SHADOW_IN);
2151   gtk_widget_show (scrolled);
2152   gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
2153
2154   treeview = gtk_tree_view_new_with_model ((GtkTreeModel *) priv->printer_list_filter);
2155   priv->printer_treeview = treeview;
2156   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), TRUE);
2157   gtk_tree_view_set_search_column (GTK_TREE_VIEW (treeview), PRINTER_LIST_COL_NAME);
2158   gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
2159   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
2160   gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
2161   g_signal_connect (selection, "changed", G_CALLBACK (selected_printer_changed), dialog);
2162
2163   renderer = gtk_cell_renderer_pixbuf_new ();
2164   column = gtk_tree_view_column_new_with_attributes ("",
2165                                                      renderer,
2166                                                      "icon-name",
2167                                                      PRINTER_LIST_COL_ICON,
2168                                                      NULL);
2169   gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, NULL, NULL);
2170   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
2171
2172   renderer = gtk_cell_renderer_text_new ();
2173   column = gtk_tree_view_column_new_with_attributes (_("Printer"),
2174                                                      renderer,
2175                                                      "text",
2176                                                      PRINTER_LIST_COL_NAME,
2177                                                      NULL);
2178   gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, NULL, NULL);
2179   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
2180
2181   renderer = gtk_cell_renderer_text_new ();
2182   /* Translators: this is the header for the location column in the print dialog */
2183   column = gtk_tree_view_column_new_with_attributes (_("Location"),
2184                                                      renderer,
2185                                                      "text",
2186                                                      PRINTER_LIST_COL_LOCATION,
2187                                                      NULL);
2188   gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, NULL, NULL);
2189   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
2190
2191   renderer = gtk_cell_renderer_text_new ();
2192   g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
2193   /* Translators: this is the header for the printer status column in the print dialog */
2194   column = gtk_tree_view_column_new_with_attributes (_("Status"),
2195                                                      renderer,
2196                                                      "text",
2197                                                      PRINTER_LIST_COL_STATE,
2198                                                      NULL);
2199   gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, NULL, NULL);
2200   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
2201
2202   g_signal_connect (GTK_TREE_VIEW (treeview), "row-activated", G_CALLBACK (emit_ok_response), dialog);
2203
2204   gtk_widget_show (treeview);
2205   gtk_container_add (GTK_CONTAINER (scrolled), treeview);
2206
2207   custom_input = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 18);
2208   gtk_widget_show (custom_input);
2209   gtk_box_pack_start (GTK_BOX (vbox), custom_input, FALSE, FALSE, 0);
2210   priv->extension_point = custom_input;
2211
2212   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 18);
2213   gtk_widget_show (hbox);
2214   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
2215
2216   table = gtk_grid_new ();
2217   priv->range_table = table;
2218   gtk_grid_set_row_spacing (GTK_GRID (table), 6);
2219   gtk_grid_set_column_spacing (GTK_GRID (table), 12);
2220   frame = wrap_in_frame (_("Range"), table);
2221   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
2222   gtk_widget_show (table);
2223
2224   radio = gtk_radio_button_new_with_mnemonic (NULL, _("_All Pages"));
2225   priv->all_pages_radio = radio;
2226   gtk_widget_show (radio);
2227   gtk_grid_attach (GTK_GRID (table), radio, 0, 0, 2, 1);
2228   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
2229                                               _("C_urrent Page"));
2230   if (priv->current_page == -1)
2231     gtk_widget_set_sensitive (radio, FALSE);
2232   priv->current_page_radio = radio;
2233   gtk_widget_show (radio);
2234   gtk_grid_attach (GTK_GRID (table), radio, 0, 1, 2, 1);
2235
2236   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
2237                                               _("Se_lection"));
2238
2239   gtk_widget_set_sensitive (radio, priv->has_selection);
2240   priv->selection_radio = radio;
2241   gtk_grid_attach (GTK_GRID (table), radio, 0, 2, 2, 1);
2242
2243   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)), _("Pag_es:"));
2244   range_tooltip = _("Specify one or more page ranges,\n e.g. 1-3,7,11");
2245   gtk_widget_set_tooltip_text (radio, range_tooltip);
2246
2247   priv->page_range_radio = radio;
2248   gtk_widget_show (radio);
2249   gtk_grid_attach (GTK_GRID (table), radio, 0, 3, 1, 1);
2250   entry = gtk_entry_new ();
2251   gtk_widget_set_tooltip_text (entry, range_tooltip);
2252   gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
2253   atk_object_set_name (gtk_widget_get_accessible (entry), _("Pages"));
2254   atk_object_set_description (gtk_widget_get_accessible (entry), range_tooltip);
2255   priv->page_range_entry = entry;
2256   gtk_widget_show (entry);
2257   gtk_grid_attach (GTK_GRID (table), entry, 1, 3, 1, 1);
2258   g_signal_connect (radio, "toggled", G_CALLBACK (update_entry_sensitivity), entry);
2259   update_entry_sensitivity (radio, entry);
2260
2261   table = gtk_grid_new ();
2262   gtk_grid_set_row_spacing (GTK_GRID (table), 6);
2263   gtk_grid_set_column_spacing (GTK_GRID (table), 12);
2264   frame = wrap_in_frame (_("Copies"), table);
2265   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
2266   gtk_widget_show (table);
2267
2268   /* FIXME chpe: too much space between Copies and spinbutton, put those 2 in a hbox and make it span 2 columns */
2269   label = gtk_label_new_with_mnemonic (_("Copie_s:"));
2270   gtk_widget_set_halign (label, GTK_ALIGN_START);
2271   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
2272   gtk_widget_show (label);
2273   gtk_grid_attach (GTK_GRID (table), label, 0, 0, 1, 1);
2274   spinbutton = gtk_spin_button_new_with_range (1.0, 100.0, 1.0);
2275   gtk_entry_set_activates_default (GTK_ENTRY (spinbutton), TRUE);
2276   priv->copies_spin = spinbutton;
2277   gtk_widget_show (spinbutton);
2278   gtk_grid_attach (GTK_GRID (table), spinbutton, 1, 0, 1, 1);
2279   gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
2280   g_signal_connect_swapped (spinbutton, "value-changed",
2281                             G_CALLBACK (update_dialog_from_capabilities), dialog);
2282   g_signal_connect_swapped (spinbutton, "changed",
2283                             G_CALLBACK (update_dialog_from_capabilities), dialog);
2284
2285   check = gtk_check_button_new_with_mnemonic (_("C_ollate"));
2286   priv->collate_check = check;
2287   g_signal_connect (check, "toggled", G_CALLBACK (update_collate_icon), dialog);
2288   gtk_widget_show (check);
2289   gtk_grid_attach (GTK_GRID (table), check, 0, 1, 1, 1);
2290
2291   check = gtk_check_button_new_with_mnemonic (_("_Reverse"));
2292   g_signal_connect (check, "toggled", G_CALLBACK (update_collate_icon), dialog);
2293   priv->reverse_check = check;
2294   gtk_widget_show (check);
2295   gtk_grid_attach (GTK_GRID (table), check, 0, 2, 1, 1);
2296
2297   image = gtk_drawing_area_new ();
2298   gtk_widget_set_has_window (image, FALSE);
2299
2300   priv->collate_image = image;
2301   gtk_widget_show (image);
2302   gtk_widget_set_size_request (image, 70, 90);
2303   gtk_grid_attach (GTK_GRID (table), image, 1, 1, 1, 2);
2304   g_signal_connect (image, "draw",
2305                     G_CALLBACK (draw_collate_cb), dialog);
2306
2307   label = gtk_label_new (_("General"));
2308   gtk_widget_show (label);
2309
2310   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), main_vbox, label);
2311 }
2312
2313 static gboolean
2314 is_range_separator (gchar c)
2315 {
2316   return (c == ',' || c == ';' || c == ':');
2317 }
2318
2319 static GtkPageRange *
2320 dialog_get_page_ranges (GtkPrintUnixDialog *dialog,
2321                         gint               *n_ranges_out)
2322 {
2323   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2324   gint i, n_ranges;
2325   const gchar *text, *p;
2326   gchar *next;
2327   GtkPageRange *ranges;
2328   gint start, end;
2329
2330   text = gtk_entry_get_text (GTK_ENTRY (priv->page_range_entry));
2331
2332   if (*text == 0)
2333     {
2334       *n_ranges_out = 0;
2335       return NULL;
2336     }
2337
2338   n_ranges = 1;
2339   p = text;
2340   while (*p)
2341     {
2342       if (is_range_separator (*p))
2343         n_ranges++;
2344       p++;
2345     }
2346
2347   ranges = g_new0 (GtkPageRange, n_ranges);
2348
2349   i = 0;
2350   p = text;
2351   while (*p)
2352     {
2353       while (isspace (*p)) p++;
2354
2355       if (*p == '-')
2356         {
2357           /* a half-open range like -2 */
2358           start = 1;
2359         }
2360       else
2361         {
2362           start = (int)strtol (p, &next, 10);
2363           if (start < 1)
2364             start = 1;
2365           p = next;
2366         }
2367
2368       end = start;
2369
2370       while (isspace (*p)) p++;
2371
2372       if (*p == '-')
2373         {
2374           p++;
2375           end = (int)strtol (p, &next, 10);
2376           if (next == p) /* a half-open range like 2- */
2377             end = 0;
2378           else if (end < start)
2379             end = start;
2380         }
2381
2382       ranges[i].start = start - 1;
2383       ranges[i].end = end - 1;
2384       i++;
2385
2386       /* Skip until end or separator */
2387       while (*p && !is_range_separator (*p))
2388         p++;
2389
2390       /* if not at end, skip separator */
2391       if (*p)
2392         p++;
2393     }
2394
2395   *n_ranges_out = i;
2396
2397   return ranges;
2398 }
2399
2400 static void
2401 dialog_set_page_ranges (GtkPrintUnixDialog *dialog,
2402                         GtkPageRange       *ranges,
2403                         gint                n_ranges)
2404 {
2405   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2406   gint i;
2407   GString *s = g_string_new (NULL);
2408
2409   for (i = 0; i < n_ranges; i++)
2410     {
2411       g_string_append_printf (s, "%d", ranges[i].start + 1);
2412       if (ranges[i].end > ranges[i].start)
2413         g_string_append_printf (s, "-%d", ranges[i].end + 1);
2414       else if (ranges[i].end == -1)
2415         g_string_append (s, "-");
2416
2417       if (i != n_ranges - 1)
2418         g_string_append (s, ",");
2419     }
2420
2421   gtk_entry_set_text (GTK_ENTRY (priv->page_range_entry), s->str);
2422
2423   g_string_free (s, TRUE);
2424 }
2425
2426 static GtkPrintPages
2427 dialog_get_print_pages (GtkPrintUnixDialog *dialog)
2428 {
2429   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2430
2431   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->all_pages_radio)))
2432     return GTK_PRINT_PAGES_ALL;
2433   else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->current_page_radio)))
2434     return GTK_PRINT_PAGES_CURRENT;
2435   else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->selection_radio)))
2436     return GTK_PRINT_PAGES_SELECTION;
2437   else
2438     return GTK_PRINT_PAGES_RANGES;
2439 }
2440
2441 static void
2442 dialog_set_print_pages (GtkPrintUnixDialog *dialog,
2443                         GtkPrintPages       pages)
2444 {
2445   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2446
2447   if (pages == GTK_PRINT_PAGES_RANGES)
2448     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->page_range_radio), TRUE);
2449   else if (pages == GTK_PRINT_PAGES_CURRENT)
2450     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->current_page_radio), TRUE);
2451   else if (pages == GTK_PRINT_PAGES_SELECTION)
2452     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->selection_radio), TRUE);
2453   else
2454     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->all_pages_radio), TRUE);
2455 }
2456
2457 static gdouble
2458 dialog_get_scale (GtkPrintUnixDialog *dialog)
2459 {
2460   if (gtk_widget_is_sensitive (dialog->priv->scale_spin))
2461     return gtk_spin_button_get_value (GTK_SPIN_BUTTON (dialog->priv->scale_spin));
2462   else
2463     return 100.0;
2464 }
2465
2466 static void
2467 dialog_set_scale (GtkPrintUnixDialog *dialog,
2468                   gdouble             val)
2469 {
2470   gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->scale_spin), val);
2471 }
2472
2473 static GtkPageSet
2474 dialog_get_page_set (GtkPrintUnixDialog *dialog)
2475 {
2476   if (gtk_widget_is_sensitive (dialog->priv->page_set_combo))
2477     return (GtkPageSet)gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->page_set_combo));
2478   else
2479     return GTK_PAGE_SET_ALL;
2480 }
2481
2482 static void
2483 dialog_set_page_set (GtkPrintUnixDialog *dialog,
2484                      GtkPageSet          val)
2485 {
2486   gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->priv->page_set_combo),
2487                             (int)val);
2488 }
2489
2490 static gint
2491 dialog_get_n_copies (GtkPrintUnixDialog *dialog)
2492 {
2493   if (gtk_widget_is_sensitive (dialog->priv->copies_spin))
2494     return gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->priv->copies_spin));
2495   return 1;
2496 }
2497
2498 static void
2499 dialog_set_n_copies (GtkPrintUnixDialog *dialog,
2500                      gint                n_copies)
2501 {
2502   gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->copies_spin),
2503                              n_copies);
2504 }
2505
2506 static gboolean
2507 dialog_get_collate (GtkPrintUnixDialog *dialog)
2508 {
2509   if (gtk_widget_is_sensitive (dialog->priv->collate_check))
2510     return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->collate_check));
2511   return FALSE;
2512 }
2513
2514 static void
2515 dialog_set_collate (GtkPrintUnixDialog *dialog,
2516                     gboolean            collate)
2517 {
2518   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->collate_check),
2519                                 collate);
2520 }
2521
2522 static gboolean
2523 dialog_get_reverse (GtkPrintUnixDialog *dialog)
2524 {
2525   if (gtk_widget_is_sensitive (dialog->priv->reverse_check))
2526     return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->reverse_check));
2527   return FALSE;
2528 }
2529
2530 static void
2531 dialog_set_reverse (GtkPrintUnixDialog *dialog,
2532                     gboolean            reverse)
2533 {
2534   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->reverse_check),
2535                                 reverse);
2536 }
2537
2538 static gint
2539 dialog_get_pages_per_sheet (GtkPrintUnixDialog *dialog)
2540 {
2541   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2542   const gchar *val;
2543   gint num;
2544
2545   val = gtk_printer_option_widget_get_value (priv->pages_per_sheet);
2546
2547   num = 1;
2548
2549   if (val)
2550     {
2551       num = atoi(val);
2552       if (num < 1)
2553         num = 1;
2554     }
2555
2556   return num;
2557 }
2558
2559 static GtkNumberUpLayout
2560 dialog_get_number_up_layout (GtkPrintUnixDialog *dialog)
2561 {
2562   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2563   GtkPrintCapabilities       caps;
2564   GtkNumberUpLayout          layout;
2565   const gchar               *val;
2566   GEnumClass                *enum_class;
2567   GEnumValue                *enum_value;
2568
2569   val = gtk_printer_option_widget_get_value (priv->number_up_layout);
2570
2571   caps = priv->manual_capabilities | priv->printer_capabilities;
2572
2573   if ((caps & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT) == 0)
2574     return GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
2575
2576   if (gtk_widget_get_direction (GTK_WIDGET (dialog)) == GTK_TEXT_DIR_LTR)
2577     layout = GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
2578   else
2579     layout = GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM;
2580
2581   if (val == NULL)
2582     return layout;
2583
2584   if (val[0] == '\0' && priv->options)
2585     {
2586       GtkPrinterOption *option = gtk_printer_option_set_lookup (priv->options, "gtk-n-up-layout");
2587       if (option)
2588         val = option->value;
2589     }
2590
2591   enum_class = g_type_class_ref (GTK_TYPE_NUMBER_UP_LAYOUT);
2592   enum_value = g_enum_get_value_by_nick (enum_class, val);
2593   if (enum_value)
2594     layout = enum_value->value;
2595   g_type_class_unref (enum_class);
2596
2597   return layout;
2598 }
2599
2600 static gboolean
2601 draw_page_cb (GtkWidget          *widget,
2602               cairo_t            *cr,
2603               GtkPrintUnixDialog *dialog)
2604 {
2605   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2606   GtkStyleContext *context;
2607   gdouble ratio;
2608   gint w, h, tmp, shadow_offset;
2609   gint pages_x, pages_y, i, x, y, layout_w, layout_h;
2610   gdouble page_width, page_height;
2611   GtkPageOrientation orientation;
2612   gboolean landscape;
2613   PangoLayout *layout;
2614   PangoFontDescription *font;
2615   gchar *text;
2616   GdkRGBA color;
2617   GtkNumberUpLayout number_up_layout;
2618   gint start_x, end_x, start_y, end_y;
2619   gint dx, dy;
2620   gint width, height;
2621   gboolean horizontal;
2622   GtkPageSetup *page_setup;
2623   gdouble paper_width, paper_height;
2624   gdouble pos_x, pos_y;
2625   gint pages_per_sheet;
2626   gboolean ltr = TRUE;
2627
2628   orientation = gtk_page_setup_get_orientation (priv->page_setup);
2629   landscape =
2630     (orientation == GTK_PAGE_ORIENTATION_LANDSCAPE) ||
2631     (orientation == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE);
2632
2633   number_up_layout = dialog_get_number_up_layout (dialog);
2634   width = gtk_widget_get_allocated_width (widget);
2635   height = gtk_widget_get_allocated_height (widget);
2636
2637   cairo_save (cr);
2638
2639   page_setup = gtk_print_unix_dialog_get_page_setup (dialog);
2640
2641   if (page_setup != NULL)
2642     {
2643       if (!landscape)
2644         {
2645           paper_width = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM);
2646           paper_height = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM);
2647         }
2648       else
2649         {
2650           paper_width = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM);
2651           paper_height = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM);
2652         }
2653
2654       if (paper_width < paper_height)
2655         {
2656           h = EXAMPLE_PAGE_AREA_SIZE - 3;
2657           w = (paper_height != 0) ? h * paper_width / paper_height : 0;
2658         }
2659       else
2660         {
2661           w = EXAMPLE_PAGE_AREA_SIZE - 3;
2662           h = (paper_width != 0) ? w * paper_height / paper_width : 0;
2663         }
2664
2665       if (paper_width == 0)
2666         w = 0;
2667
2668       if (paper_height == 0)
2669         h = 0;
2670     }
2671   else
2672     {
2673       ratio = G_SQRT2;
2674       w = (EXAMPLE_PAGE_AREA_SIZE - 3) / ratio;
2675       h = EXAMPLE_PAGE_AREA_SIZE - 3;
2676     }
2677
2678   pages_per_sheet = dialog_get_pages_per_sheet (dialog);
2679   switch (pages_per_sheet)
2680     {
2681     default:
2682     case 1:
2683       pages_x = 1; pages_y = 1;
2684       break;
2685     case 2:
2686       landscape = !landscape;
2687       pages_x = 1; pages_y = 2;
2688       break;
2689     case 4:
2690       pages_x = 2; pages_y = 2;
2691       break;
2692     case 6:
2693       landscape = !landscape;
2694       pages_x = 2; pages_y = 3;
2695       break;
2696     case 9:
2697       pages_x = 3; pages_y = 3;
2698       break;
2699     case 16:
2700       pages_x = 4; pages_y = 4;
2701       break;
2702     }
2703
2704   if (landscape)
2705     {
2706       tmp = w;
2707       w = h;
2708       h = tmp;
2709
2710       tmp = pages_x;
2711       pages_x = pages_y;
2712       pages_y = tmp;
2713     }
2714
2715   context = gtk_widget_get_style_context (widget);
2716
2717   gtk_style_context_save (context);
2718   gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
2719
2720   pos_x = (width - w) / 2;
2721   pos_y = (height - h) / 2 - 10;
2722   cairo_translate (cr, pos_x, pos_y);
2723
2724   shadow_offset = 3;
2725
2726   gtk_style_context_get_color (context, 0, &color);
2727   cairo_set_source_rgba (cr, color.red, color.green, color.blue, 0.5);
2728   cairo_rectangle (cr, shadow_offset + 1, shadow_offset + 1, w, h);
2729   cairo_fill (cr);
2730
2731   gtk_style_context_get_background_color (context, 0, &color);
2732   gdk_cairo_set_source_rgba (cr, &color);
2733   cairo_rectangle (cr, 1, 1, w, h);
2734   cairo_fill (cr);
2735   cairo_set_line_width (cr, 1.0);
2736   cairo_rectangle (cr, 0.5, 0.5, w + 1, h + 1);
2737
2738   gtk_style_context_get_color (context, 0, &color);
2739   gdk_cairo_set_source_rgba (cr, &color);
2740   cairo_stroke (cr);
2741
2742   i = 1;
2743
2744   page_width = (gdouble)w / pages_x;
2745   page_height = (gdouble)h / pages_y;
2746
2747   layout  = pango_cairo_create_layout (cr);
2748
2749   font = pango_font_description_new ();
2750   pango_font_description_set_family (font, "sans");
2751
2752   if (page_height > 0)
2753     pango_font_description_set_absolute_size (font, page_height * 0.4 * PANGO_SCALE);
2754   else
2755     pango_font_description_set_absolute_size (font, 1);
2756
2757   pango_layout_set_font_description (layout, font);
2758   pango_font_description_free (font);
2759
2760   pango_layout_set_width (layout, page_width * PANGO_SCALE);
2761   pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
2762
2763   switch (number_up_layout)
2764     {
2765       default:
2766       case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM:
2767         start_x = 0;
2768         end_x = pages_x - 1;
2769         start_y = 0;
2770         end_y = pages_y - 1;
2771         dx = 1;
2772         dy = 1;
2773         horizontal = TRUE;
2774         break;
2775       case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP:
2776         start_x = 0;
2777         end_x = pages_x - 1;
2778         start_y = pages_y - 1;
2779         end_y = 0;
2780         dx = 1;
2781         dy = - 1;
2782         horizontal = TRUE;
2783         break;
2784       case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM:
2785         start_x = pages_x - 1;
2786         end_x = 0;
2787         start_y = 0;
2788         end_y = pages_y - 1;
2789         dx = - 1;
2790         dy = 1;
2791         horizontal = TRUE;
2792         break;
2793       case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP:
2794         start_x = pages_x - 1;
2795         end_x = 0;
2796         start_y = pages_y - 1;
2797         end_y = 0;
2798         dx = - 1;
2799         dy = - 1;
2800         horizontal = TRUE;
2801         break;
2802       case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT:
2803         start_x = 0;
2804         end_x = pages_x - 1;
2805         start_y = 0;
2806         end_y = pages_y - 1;
2807         dx = 1;
2808         dy = 1;
2809         horizontal = FALSE;
2810         break;
2811       case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_RIGHT_TO_LEFT:
2812         start_x = pages_x - 1;
2813         end_x = 0;
2814         start_y = 0;
2815         end_y = pages_y - 1;
2816         dx = - 1;
2817         dy = 1;
2818         horizontal = FALSE;
2819         break;
2820       case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT:
2821         start_x = 0;
2822         end_x = pages_x - 1;
2823         start_y = pages_y - 1;
2824         end_y = 0;
2825         dx = 1;
2826         dy = - 1;
2827         horizontal = FALSE;
2828         break;
2829       case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_RIGHT_TO_LEFT:
2830         start_x = pages_x - 1;
2831         end_x = 0;
2832         start_y = pages_y - 1;
2833         end_y = 0;
2834         dx = - 1;
2835         dy = - 1;
2836         horizontal = FALSE;
2837         break;
2838     }
2839
2840   if (horizontal)
2841     for (y = start_y; y != end_y + dy; y += dy)
2842       {
2843         for (x = start_x; x != end_x + dx; x += dx)
2844           {
2845             text = g_strdup_printf ("%d", i++);
2846             pango_layout_set_text (layout, text, -1);
2847             g_free (text);
2848             pango_layout_get_size (layout, &layout_w, &layout_h);
2849             cairo_save (cr);
2850             cairo_translate (cr,
2851                              x * page_width,
2852                              y * page_height + (page_height - layout_h / 1024.0) / 2);
2853
2854             pango_cairo_show_layout (cr, layout);
2855             cairo_restore (cr);
2856           }
2857       }
2858   else
2859     for (x = start_x; x != end_x + dx; x += dx)
2860       {
2861         for (y = start_y; y != end_y + dy; y += dy)
2862           {
2863             text = g_strdup_printf ("%d", i++);
2864             pango_layout_set_text (layout, text, -1);
2865             g_free (text);
2866             pango_layout_get_size (layout, &layout_w, &layout_h);
2867             cairo_save (cr);
2868             cairo_translate (cr,
2869                              x * page_width,
2870                              y * page_height + (page_height - layout_h / 1024.0) / 2);
2871
2872             pango_cairo_show_layout (cr, layout);
2873             cairo_restore (cr);
2874           }
2875       }
2876
2877   g_object_unref (layout);
2878
2879   if (page_setup != NULL)
2880     {
2881       pos_x += 1;
2882       pos_y += 1;
2883
2884       if (pages_per_sheet == 2 || pages_per_sheet == 6)
2885         {
2886           paper_width = gtk_page_setup_get_paper_height (page_setup, _gtk_print_get_default_user_units ());
2887           paper_height = gtk_page_setup_get_paper_width (page_setup, _gtk_print_get_default_user_units ());
2888         }
2889       else
2890         {
2891           paper_width = gtk_page_setup_get_paper_width (page_setup, _gtk_print_get_default_user_units ());
2892           paper_height = gtk_page_setup_get_paper_height (page_setup, _gtk_print_get_default_user_units ());
2893         }
2894
2895       cairo_restore (cr);
2896       cairo_save (cr);
2897
2898       layout  = pango_cairo_create_layout (cr);
2899
2900       font = pango_font_description_new ();
2901       pango_font_description_set_family (font, "sans");
2902
2903       PangoContext *pango_c = NULL;
2904       PangoFontDescription *pango_f = NULL;
2905       gint font_size = 12 * PANGO_SCALE;
2906
2907       pango_c = gtk_widget_get_pango_context (widget);
2908       if (pango_c != NULL)
2909         {
2910           pango_f = pango_context_get_font_description (pango_c);
2911           if (pango_f != NULL)
2912             font_size = pango_font_description_get_size (pango_f);
2913         }
2914
2915       pango_font_description_set_size (font, font_size);
2916       pango_layout_set_font_description (layout, font);
2917       pango_font_description_free (font);
2918
2919       pango_layout_set_width (layout, -1);
2920       pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
2921
2922       if (_gtk_print_get_default_user_units () == GTK_UNIT_MM)
2923         text = g_strdup_printf ("%.1f mm", paper_height);
2924       else
2925         text = g_strdup_printf ("%.2f inch", paper_height);
2926
2927       pango_layout_set_text (layout, text, -1);
2928       g_free (text);
2929       pango_layout_get_size (layout, &layout_w, &layout_h);
2930
2931       ltr = gtk_widget_get_direction (GTK_WIDGET (dialog)) == GTK_TEXT_DIR_LTR;
2932
2933       if (ltr)
2934         cairo_translate (cr, pos_x - layout_w / PANGO_SCALE - 2 * RULER_DISTANCE,
2935                              (height - layout_h / PANGO_SCALE) / 2);
2936       else
2937         cairo_translate (cr, pos_x + w + shadow_offset + 2 * RULER_DISTANCE,
2938                              (height - layout_h / PANGO_SCALE) / 2);
2939
2940       pango_cairo_show_layout (cr, layout);
2941
2942       cairo_restore (cr);
2943       cairo_save (cr);
2944
2945       if (_gtk_print_get_default_user_units () == GTK_UNIT_MM)
2946         text = g_strdup_printf ("%.1f mm", paper_width);
2947       else
2948         text = g_strdup_printf ("%.2f inch", paper_width);
2949
2950       pango_layout_set_text (layout, text, -1);
2951       g_free (text);
2952       pango_layout_get_size (layout, &layout_w, &layout_h);
2953
2954       cairo_translate (cr, (width - layout_w / PANGO_SCALE) / 2,
2955                            pos_y + h + shadow_offset + 2 * RULER_DISTANCE);
2956
2957       pango_cairo_show_layout (cr, layout);
2958
2959       g_object_unref (layout);
2960
2961       cairo_restore (cr);
2962
2963       cairo_set_line_width (cr, 1);
2964
2965       if (ltr)
2966         {
2967           cairo_move_to (cr, pos_x - RULER_DISTANCE, pos_y);
2968           cairo_line_to (cr, pos_x - RULER_DISTANCE, pos_y + h);
2969           cairo_stroke (cr);
2970
2971           cairo_move_to (cr, pos_x - RULER_DISTANCE - RULER_RADIUS, pos_y - 0.5);
2972           cairo_line_to (cr, pos_x - RULER_DISTANCE + RULER_RADIUS, pos_y - 0.5);
2973           cairo_stroke (cr);
2974
2975           cairo_move_to (cr, pos_x - RULER_DISTANCE - RULER_RADIUS, pos_y + h + 0.5);
2976           cairo_line_to (cr, pos_x - RULER_DISTANCE + RULER_RADIUS, pos_y + h + 0.5);
2977           cairo_stroke (cr);
2978         }
2979       else
2980         {
2981           cairo_move_to (cr, pos_x + w + shadow_offset + RULER_DISTANCE, pos_y);
2982           cairo_line_to (cr, pos_x + w + shadow_offset + RULER_DISTANCE, pos_y + h);
2983           cairo_stroke (cr);
2984
2985           cairo_move_to (cr, pos_x + w + shadow_offset + RULER_DISTANCE - RULER_RADIUS, pos_y - 0.5);
2986           cairo_line_to (cr, pos_x + w + shadow_offset + RULER_DISTANCE + RULER_RADIUS, pos_y - 0.5);
2987           cairo_stroke (cr);
2988
2989           cairo_move_to (cr, pos_x + w + shadow_offset + RULER_DISTANCE - RULER_RADIUS, pos_y + h + 0.5);
2990           cairo_line_to (cr, pos_x + w + shadow_offset + RULER_DISTANCE + RULER_RADIUS, pos_y + h + 0.5);
2991           cairo_stroke (cr);
2992         }
2993
2994       cairo_move_to (cr, pos_x, pos_y + h + shadow_offset + RULER_DISTANCE);
2995       cairo_line_to (cr, pos_x + w, pos_y + h + shadow_offset + RULER_DISTANCE);
2996       cairo_stroke (cr);
2997
2998       cairo_move_to (cr, pos_x - 0.5, pos_y + h + shadow_offset + RULER_DISTANCE - RULER_RADIUS);
2999       cairo_line_to (cr, pos_x - 0.5, pos_y + h + shadow_offset + RULER_DISTANCE + RULER_RADIUS);
3000       cairo_stroke (cr);
3001
3002       cairo_move_to (cr, pos_x + w + 0.5, pos_y + h + shadow_offset + RULER_DISTANCE - RULER_RADIUS);
3003       cairo_line_to (cr, pos_x + w + 0.5, pos_y + h + shadow_offset + RULER_DISTANCE + RULER_RADIUS);
3004       cairo_stroke (cr);
3005     }
3006
3007   gtk_style_context_restore (context);
3008
3009   return TRUE;
3010 }
3011
3012 static void
3013 redraw_page_layout_preview (GtkPrintUnixDialog *dialog)
3014 {
3015   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3016
3017   if (priv->page_layout_preview)
3018     gtk_widget_queue_draw (priv->page_layout_preview);
3019 }
3020
3021 static void
3022 update_number_up_layout (GtkPrintUnixDialog *dialog)
3023 {
3024   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3025   GtkPrintCapabilities       caps;
3026   GtkPrinterOptionSet       *set;
3027   GtkNumberUpLayout          layout;
3028   GtkPrinterOption          *option;
3029   GtkPrinterOption          *old_option;
3030   GtkPageOrientation         page_orientation;
3031
3032   set = priv->options;
3033
3034   caps = priv->manual_capabilities | priv->printer_capabilities;
3035
3036   if (caps & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT)
3037     {
3038       if (priv->number_up_layout_n_option == NULL)
3039         {
3040           priv->number_up_layout_n_option = gtk_printer_option_set_lookup (set, "gtk-n-up-layout");
3041           if (priv->number_up_layout_n_option == NULL)
3042             {
3043               char *n_up_layout[] = { "lrtb", "lrbt", "rltb", "rlbt", "tblr", "tbrl", "btlr", "btrl" };
3044                /* Translators: These strings name the possible arrangements of
3045                 * multiple pages on a sheet when printing (same as in gtkprintbackendcups.c)
3046                 */
3047               char *n_up_layout_display[] = { N_("Left to right, top to bottom"), N_("Left to right, bottom to top"),
3048                                               N_("Right to left, top to bottom"), N_("Right to left, bottom to top"),
3049                                               N_("Top to bottom, left to right"), N_("Top to bottom, right to left"),
3050                                               N_("Bottom to top, left to right"), N_("Bottom to top, right to left") };
3051               int i;
3052
3053               priv->number_up_layout_n_option = gtk_printer_option_new ("gtk-n-up-layout",
3054                                                                         _("Page Ordering"),
3055                                                                         GTK_PRINTER_OPTION_TYPE_PICKONE);
3056               gtk_printer_option_allocate_choices (priv->number_up_layout_n_option, 8);
3057
3058               for (i = 0; i < G_N_ELEMENTS (n_up_layout_display); i++)
3059                 {
3060                   priv->number_up_layout_n_option->choices[i] = g_strdup (n_up_layout[i]);
3061                   priv->number_up_layout_n_option->choices_display[i] = g_strdup (_(n_up_layout_display[i]));
3062                 }
3063             }
3064           g_object_ref (priv->number_up_layout_n_option);
3065
3066           priv->number_up_layout_2_option = gtk_printer_option_new ("gtk-n-up-layout",
3067                                                                     _("Page Ordering"),
3068                                                                     GTK_PRINTER_OPTION_TYPE_PICKONE);
3069           gtk_printer_option_allocate_choices (priv->number_up_layout_2_option, 2);
3070         }
3071
3072       page_orientation = gtk_page_setup_get_orientation (priv->page_setup);
3073       if (page_orientation == GTK_PAGE_ORIENTATION_PORTRAIT ||
3074           page_orientation == GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT)
3075         {
3076           if (! (priv->number_up_layout_2_option->choices[0] == priv->number_up_layout_n_option->choices[0] &&
3077                  priv->number_up_layout_2_option->choices[1] == priv->number_up_layout_n_option->choices[2]))
3078             {
3079               g_free (priv->number_up_layout_2_option->choices_display[0]);
3080               g_free (priv->number_up_layout_2_option->choices_display[1]);
3081               priv->number_up_layout_2_option->choices[0] = priv->number_up_layout_n_option->choices[0];
3082               priv->number_up_layout_2_option->choices[1] = priv->number_up_layout_n_option->choices[2];
3083               priv->number_up_layout_2_option->choices_display[0] = g_strdup ( _("Left to right"));
3084               priv->number_up_layout_2_option->choices_display[1] = g_strdup ( _("Right to left"));
3085             }
3086         }
3087       else
3088         {
3089           if (! (priv->number_up_layout_2_option->choices[0] == priv->number_up_layout_n_option->choices[0] &&
3090                  priv->number_up_layout_2_option->choices[1] == priv->number_up_layout_n_option->choices[1]))
3091             {
3092               g_free (priv->number_up_layout_2_option->choices_display[0]);
3093               g_free (priv->number_up_layout_2_option->choices_display[1]);
3094               priv->number_up_layout_2_option->choices[0] = priv->number_up_layout_n_option->choices[0];
3095               priv->number_up_layout_2_option->choices[1] = priv->number_up_layout_n_option->choices[1];
3096               priv->number_up_layout_2_option->choices_display[0] = g_strdup ( _("Top to bottom"));
3097               priv->number_up_layout_2_option->choices_display[1] = g_strdup ( _("Bottom to top"));
3098             }
3099         }
3100
3101       layout = dialog_get_number_up_layout (dialog);
3102
3103       old_option = gtk_printer_option_set_lookup (set, "gtk-n-up-layout");
3104       if (old_option != NULL)
3105         gtk_printer_option_set_remove (set, old_option);
3106
3107       if (dialog_get_pages_per_sheet (dialog) != 1)
3108         {
3109           GEnumClass *enum_class;
3110           GEnumValue *enum_value;
3111           enum_class = g_type_class_ref (GTK_TYPE_NUMBER_UP_LAYOUT);
3112
3113           if (dialog_get_pages_per_sheet (dialog) == 2)
3114             {
3115               option = priv->number_up_layout_2_option;
3116
3117               switch (layout)
3118                 {
3119                 case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM:
3120                 case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT:
3121                   enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM);
3122                   break;
3123
3124                 case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP:
3125                 case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT:
3126                   enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP);
3127                   break;
3128
3129                 case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM:
3130                 case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_RIGHT_TO_LEFT:
3131                   enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM);
3132                   break;
3133
3134                 case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP:
3135                 case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_RIGHT_TO_LEFT:
3136                   enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP);
3137                   break;
3138
3139                 default:
3140                   g_assert_not_reached();
3141                   enum_value = NULL;
3142                 }
3143             }
3144           else
3145             {
3146               option = priv->number_up_layout_n_option;
3147
3148               enum_value = g_enum_get_value (enum_class, layout);
3149             }
3150
3151           g_assert (enum_value != NULL);
3152           gtk_printer_option_set (option, enum_value->value_nick);
3153           g_type_class_unref (enum_class);
3154
3155           gtk_printer_option_set_add (set, option);
3156         }
3157     }
3158
3159   setup_option (dialog, "gtk-n-up-layout", priv->number_up_layout);
3160
3161   if (priv->number_up_layout != NULL)
3162     gtk_widget_set_sensitive (GTK_WIDGET (priv->number_up_layout),
3163                               (caps & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT) &&
3164                               (dialog_get_pages_per_sheet (dialog) > 1));
3165 }
3166
3167 static void
3168 custom_paper_dialog_response_cb (GtkDialog *custom_paper_dialog,
3169                                  gint       response_id,
3170                                  gpointer   user_data)
3171 {
3172   GtkPrintUnixDialog        *print_dialog = GTK_PRINT_UNIX_DIALOG (user_data);
3173   GtkPrintUnixDialogPrivate *priv = print_dialog->priv;
3174   GtkTreeModel              *model;
3175   GtkTreeIter                iter;
3176
3177   _gtk_print_load_custom_papers (priv->custom_paper_list);
3178
3179   priv->internal_page_setup_change = TRUE;
3180   update_paper_sizes (print_dialog);
3181   priv->internal_page_setup_change = FALSE;
3182
3183   if (priv->page_setup_set)
3184     {
3185       model = GTK_TREE_MODEL (priv->custom_paper_list);
3186       if (gtk_tree_model_get_iter_first (model, &iter))
3187         {
3188           do
3189             {
3190               GtkPageSetup *page_setup;
3191               gtk_tree_model_get (model, &iter, 0, &page_setup, -1);
3192
3193               if (page_setup &&
3194                   g_strcmp0 (gtk_paper_size_get_display_name (gtk_page_setup_get_paper_size (page_setup)),
3195                              gtk_paper_size_get_display_name (gtk_page_setup_get_paper_size (priv->page_setup))) == 0)
3196                 gtk_print_unix_dialog_set_page_setup (print_dialog, page_setup);
3197
3198               g_object_unref (page_setup);
3199             } while (gtk_tree_model_iter_next (model, &iter));
3200         }
3201     }
3202
3203   gtk_widget_destroy (GTK_WIDGET (custom_paper_dialog));
3204 }
3205
3206 static void
3207 orientation_changed (GtkComboBox        *combo_box,
3208                      GtkPrintUnixDialog *dialog)
3209 {
3210   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3211   GtkPageOrientation         orientation;
3212   GtkPageSetup              *page_setup;
3213
3214   if (priv->internal_page_setup_change)
3215     return;
3216
3217   orientation = (GtkPageOrientation) gtk_combo_box_get_active (GTK_COMBO_BOX (priv->orientation_combo));
3218
3219   if (priv->page_setup)
3220     {
3221       page_setup = gtk_page_setup_copy (priv->page_setup);
3222       if (page_setup)
3223         gtk_page_setup_set_orientation (page_setup, orientation);
3224
3225       gtk_print_unix_dialog_set_page_setup (dialog, page_setup);
3226     }
3227
3228   redraw_page_layout_preview (dialog);
3229 }
3230
3231 static void
3232 paper_size_changed (GtkComboBox        *combo_box,
3233                     GtkPrintUnixDialog *dialog)
3234 {
3235   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3236   GtkTreeIter iter;
3237   GtkPageSetup *page_setup, *last_page_setup;
3238   GtkPageOrientation orientation;
3239
3240   if (priv->internal_page_setup_change)
3241     return;
3242
3243   if (gtk_combo_box_get_active_iter (combo_box, &iter))
3244     {
3245       gtk_tree_model_get (gtk_combo_box_get_model (combo_box),
3246                           &iter, PAGE_SETUP_LIST_COL_PAGE_SETUP, &page_setup,
3247                           -1);
3248
3249       if (page_setup == NULL)
3250         {
3251           GtkWidget *custom_paper_dialog;
3252
3253           /* Change from "manage" menu item to last value */
3254           if (priv->page_setup)
3255             last_page_setup = g_object_ref (priv->page_setup);
3256           else
3257             last_page_setup = gtk_page_setup_new (); /* "good" default */
3258
3259           if (!set_paper_size (dialog, last_page_setup, FALSE, FALSE))
3260             set_paper_size (dialog, last_page_setup, TRUE, TRUE);
3261           g_object_unref (last_page_setup);
3262
3263           /* And show the custom paper dialog */
3264           custom_paper_dialog = _gtk_custom_paper_unix_dialog_new (GTK_WINDOW (dialog), _("Manage Custom Sizes"));
3265           g_signal_connect (custom_paper_dialog, "response", G_CALLBACK (custom_paper_dialog_response_cb), dialog);
3266           gtk_window_present (GTK_WINDOW (custom_paper_dialog));
3267
3268           return;
3269         }
3270
3271       if (priv->page_setup)
3272         orientation = gtk_page_setup_get_orientation (priv->page_setup);
3273       else
3274         orientation = GTK_PAGE_ORIENTATION_PORTRAIT;
3275
3276       gtk_page_setup_set_orientation (page_setup, orientation);
3277       gtk_print_unix_dialog_set_page_setup (dialog, page_setup);
3278
3279       g_object_unref (page_setup);
3280     }
3281
3282   redraw_page_layout_preview (dialog);
3283 }
3284
3285 static gboolean
3286 paper_size_row_is_separator (GtkTreeModel *model,
3287                              GtkTreeIter  *iter,
3288                              gpointer      data)
3289 {
3290   gboolean separator;
3291
3292   gtk_tree_model_get (model, iter,
3293                       PAGE_SETUP_LIST_COL_IS_SEPARATOR, &separator,
3294                       -1);
3295   return separator;
3296 }
3297
3298 static void
3299 page_name_func (GtkCellLayout   *cell_layout,
3300                 GtkCellRenderer *cell,
3301                 GtkTreeModel    *tree_model,
3302                 GtkTreeIter     *iter,
3303                 gpointer         data)
3304 {
3305   GtkPageSetup *page_setup;
3306   GtkPaperSize *paper_size;
3307
3308   gtk_tree_model_get (tree_model, iter,
3309                       PAGE_SETUP_LIST_COL_PAGE_SETUP, &page_setup,
3310                       -1);
3311   if (page_setup)
3312     {
3313       paper_size = gtk_page_setup_get_paper_size (page_setup);
3314       g_object_set (cell, "text",  gtk_paper_size_get_display_name (paper_size), NULL);
3315       g_object_unref (page_setup);
3316     }
3317   else
3318     g_object_set (cell, "text",  _("Manage Custom Sizes..."), NULL);
3319 }
3320
3321 static void
3322 create_page_setup_page (GtkPrintUnixDialog *dialog)
3323 {
3324   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3325   GtkWidget *main_vbox, *label, *hbox, *hbox2;
3326   GtkWidget *frame, *table, *widget;
3327   GtkWidget *combo, *spinbutton, *draw;
3328   GtkCellRenderer *cell;
3329
3330   main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 18);
3331   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
3332   gtk_widget_show (main_vbox);
3333
3334   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 18);
3335   gtk_widget_show (hbox);
3336   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
3337
3338   table = gtk_grid_new ();
3339   gtk_grid_set_row_spacing (GTK_GRID (table), 6);
3340   gtk_grid_set_column_spacing (GTK_GRID (table), 12);
3341   frame = wrap_in_frame (_("Layout"), table);
3342   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
3343   gtk_widget_show (table);
3344
3345   label = gtk_label_new_with_mnemonic (_("T_wo-sided:"));
3346   gtk_widget_set_halign (label, GTK_ALIGN_START);
3347   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3348   gtk_widget_show (label);
3349   gtk_grid_attach (GTK_GRID (table), label, 0, 0, 1, 1);
3350
3351   widget = gtk_printer_option_widget_new (NULL);
3352   priv->duplex = GTK_PRINTER_OPTION_WIDGET (widget);
3353   gtk_widget_show (widget);
3354   gtk_grid_attach (GTK_GRID (table), widget, 1, 0, 1, 1);
3355   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3356
3357   label = gtk_label_new_with_mnemonic (_("Pages per _side:"));
3358   gtk_widget_set_halign (label, GTK_ALIGN_START);
3359   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3360   gtk_widget_show (label);
3361   gtk_grid_attach (GTK_GRID (table), label, 0, 1, 1, 1);
3362
3363   widget = gtk_printer_option_widget_new (NULL);
3364   g_signal_connect_swapped (widget, "changed", G_CALLBACK (redraw_page_layout_preview), dialog);
3365   g_signal_connect_swapped (widget, "changed", G_CALLBACK (update_number_up_layout), dialog);
3366   priv->pages_per_sheet = GTK_PRINTER_OPTION_WIDGET (widget);
3367   gtk_widget_show (widget);
3368   gtk_grid_attach (GTK_GRID (table), widget, 1, 1, 1, 1);
3369   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3370
3371   label = gtk_label_new_with_mnemonic (_("Page or_dering:"));
3372   gtk_widget_set_halign (label, GTK_ALIGN_START);
3373   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3374   gtk_widget_show (label);
3375   gtk_grid_attach (GTK_GRID (table), label, 0, 2, 1, 1);
3376
3377   widget = gtk_printer_option_widget_new (NULL);
3378   g_signal_connect_swapped (widget, "changed", G_CALLBACK (redraw_page_layout_preview), dialog);
3379   priv->number_up_layout = GTK_PRINTER_OPTION_WIDGET (widget);
3380   gtk_widget_show (widget);
3381   gtk_grid_attach (GTK_GRID (table), widget, 1, 2, 1, 1);
3382   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3383
3384   label = gtk_label_new_with_mnemonic (_("_Only print:"));
3385   gtk_widget_set_halign (label, GTK_ALIGN_START);
3386   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3387   gtk_widget_show (label);
3388   gtk_grid_attach (GTK_GRID (table), label, 0, 3, 1, 1);
3389
3390   combo = gtk_combo_box_text_new ();
3391   priv->page_set_combo = combo;
3392   gtk_widget_show (combo);
3393   gtk_grid_attach (GTK_GRID (table), combo, 1, 3, 1, 1);
3394   gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
3395   /* In enum order */
3396   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("All sheets"));
3397   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Even sheets"));
3398   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Odd sheets"));
3399   gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
3400
3401   label = gtk_label_new_with_mnemonic (_("Sc_ale:"));
3402   gtk_widget_set_halign (label, GTK_ALIGN_START);
3403   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3404   gtk_widget_show (label);
3405   gtk_grid_attach (GTK_GRID (table), label, 0, 4, 1, 1);
3406
3407   hbox2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
3408   gtk_widget_show (hbox2);
3409   gtk_grid_attach (GTK_GRID (table), hbox2, 1, 4, 1, 1);
3410
3411   spinbutton = gtk_spin_button_new_with_range (1.0, 1000.0, 1.0);
3412   priv->scale_spin = spinbutton;
3413   gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinbutton), 1);
3414   gtk_spin_button_set_value (GTK_SPIN_BUTTON (spinbutton), 100.0);
3415   gtk_box_pack_start (GTK_BOX (hbox2), spinbutton, FALSE, FALSE, 0);
3416   gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
3417   gtk_widget_show (spinbutton);
3418   label = gtk_label_new ("%"); /* FIXMEchpe does there exist any language where % needs to be translated? */
3419   gtk_widget_show (label);
3420   gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0);
3421
3422   table = gtk_grid_new ();
3423   gtk_grid_set_row_spacing (GTK_GRID (table), 6);
3424   gtk_grid_set_column_spacing (GTK_GRID (table), 12);
3425   frame = wrap_in_frame (_("Paper"), table);
3426   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 6);
3427   gtk_widget_show (table);
3428
3429   label = gtk_label_new_with_mnemonic (_("Paper _type:"));
3430   gtk_widget_set_halign (label, GTK_ALIGN_START);
3431   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3432   gtk_widget_show (label);
3433   gtk_grid_attach (GTK_GRID (table), label, 0, 0, 1, 1);
3434
3435   widget = gtk_printer_option_widget_new (NULL);
3436   priv->paper_type = GTK_PRINTER_OPTION_WIDGET (widget);
3437   gtk_widget_show (widget);
3438   gtk_grid_attach (GTK_GRID (table), widget, 1, 0, 1, 1);
3439   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3440
3441   label = gtk_label_new_with_mnemonic (_("Paper _source:"));
3442   gtk_widget_set_halign (label, GTK_ALIGN_START);
3443   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3444   gtk_widget_show (label);
3445   gtk_grid_attach (GTK_GRID (table), label, 0, 1, 1, 1);
3446
3447   widget = gtk_printer_option_widget_new (NULL);
3448   priv->paper_source = GTK_PRINTER_OPTION_WIDGET (widget);
3449   gtk_widget_show (widget);
3450   gtk_grid_attach (GTK_GRID (table), widget, 1, 1, 1, 1);
3451   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3452
3453   label = gtk_label_new_with_mnemonic (_("Output t_ray:"));
3454   gtk_widget_set_halign (label, GTK_ALIGN_START);
3455   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3456   gtk_widget_show (label);
3457   gtk_grid_attach (GTK_GRID (table), label, 0, 2, 1, 1);
3458
3459   widget = gtk_printer_option_widget_new (NULL);
3460   priv->output_tray = GTK_PRINTER_OPTION_WIDGET (widget);
3461   gtk_widget_show (widget);
3462   gtk_grid_attach (GTK_GRID (table), widget, 1, 2, 1, 1);
3463   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3464
3465
3466   label = gtk_label_new_with_mnemonic (_("_Paper size:"));
3467   priv->paper_size_combo_label = GTK_WIDGET (label);
3468   gtk_widget_set_halign (label, GTK_ALIGN_START);
3469   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3470   gtk_widget_show (label);
3471   gtk_grid_attach (GTK_GRID (table), label, 0, 3, 1, 1);
3472
3473   combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (priv->page_setup_list));
3474   priv->paper_size_combo = GTK_WIDGET (combo);
3475   gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo),
3476                                         paper_size_row_is_separator, NULL, NULL);
3477   cell = gtk_cell_renderer_text_new ();
3478   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
3479   gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo), cell,
3480                                       page_name_func, NULL, NULL);
3481   gtk_grid_attach (GTK_GRID (table), combo, 1, 3, 1, 1);
3482   gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
3483   gtk_widget_set_sensitive (combo, FALSE);
3484   gtk_widget_show (combo);
3485
3486   label = gtk_label_new_with_mnemonic (_("Or_ientation:"));
3487   priv->orientation_combo_label = GTK_WIDGET (label);
3488   gtk_widget_set_halign (label, GTK_ALIGN_START);
3489   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3490   gtk_widget_show (label);
3491   gtk_grid_attach (GTK_GRID (table), label, 0, 4, 1, 1);
3492
3493   combo = gtk_combo_box_text_new ();
3494   priv->orientation_combo = GTK_WIDGET (combo);
3495   gtk_grid_attach (GTK_GRID (table), combo, 1, 4, 1, 1);
3496   gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
3497   /* In enum order */
3498   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Portrait"));
3499   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Landscape"));
3500   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Reverse portrait"));
3501   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Reverse landscape"));
3502   gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
3503   gtk_widget_set_sensitive (combo, FALSE);
3504   gtk_widget_show (combo);
3505
3506   /* Add the page layout preview */
3507   hbox2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
3508   gtk_widget_show (hbox2);
3509   gtk_box_pack_start (GTK_BOX (main_vbox), hbox2, TRUE, TRUE, 0);
3510
3511   draw = gtk_drawing_area_new ();
3512   gtk_widget_set_has_window (draw, FALSE);
3513   priv->page_layout_preview = draw;
3514   gtk_widget_set_size_request (draw, 280, 160);
3515   g_signal_connect (draw, "draw", G_CALLBACK (draw_page_cb), dialog);
3516   gtk_widget_show (draw);
3517
3518   gtk_box_pack_start (GTK_BOX (hbox2), draw, TRUE, FALSE, 0);
3519
3520   label = gtk_label_new (_("Page Setup"));
3521   gtk_widget_show (label);
3522
3523   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
3524                             main_vbox, label);
3525 }
3526
3527 static void
3528 create_job_page (GtkPrintUnixDialog *dialog)
3529 {
3530   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3531   GtkWidget *main_table, *label;
3532   GtkWidget *frame, *table, *radio;
3533   GtkWidget *entry, *widget;
3534   const gchar *at_tooltip;
3535   const gchar *on_hold_tooltip;
3536
3537   main_table = gtk_grid_new ();
3538   gtk_container_set_border_width (GTK_CONTAINER (main_table), 12);
3539   gtk_grid_set_row_spacing (GTK_GRID (main_table), 18);
3540   gtk_grid_set_column_spacing (GTK_GRID (main_table), 18);
3541
3542   table = gtk_grid_new ();
3543   gtk_grid_set_row_spacing (GTK_GRID (table), 6);
3544   gtk_grid_set_column_spacing (GTK_GRID (table), 12);
3545   frame = wrap_in_frame (_("Job Details"), table);
3546   gtk_grid_attach (GTK_GRID (main_table), frame, 0, 0, 1, 1);
3547   gtk_widget_show (table);
3548
3549   label = gtk_label_new_with_mnemonic (_("Pri_ority:"));
3550   gtk_widget_set_halign (label, GTK_ALIGN_START);
3551   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3552   gtk_widget_show (label);
3553   gtk_grid_attach (GTK_GRID (table), label, 0, 0, 1, 1);
3554
3555   widget = gtk_printer_option_widget_new (NULL);
3556   priv->job_prio = GTK_PRINTER_OPTION_WIDGET (widget);
3557   gtk_widget_show (widget);
3558   gtk_grid_attach (GTK_GRID (table), widget, 1, 0, 1, 1);
3559   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3560
3561   label = gtk_label_new_with_mnemonic (_("_Billing info:"));
3562   gtk_widget_set_halign (label, GTK_ALIGN_START);
3563   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3564   gtk_widget_show (label);
3565   gtk_grid_attach (GTK_GRID (table), label, 0, 1, 1, 1);
3566
3567   widget = gtk_printer_option_widget_new (NULL);
3568   priv->billing_info = GTK_PRINTER_OPTION_WIDGET (widget);
3569   gtk_widget_show (widget);
3570   gtk_grid_attach (GTK_GRID (table), widget, 1, 1, 1, 1);
3571   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3572
3573   table = gtk_grid_new ();
3574   gtk_grid_set_row_spacing (GTK_GRID (table), 6);
3575   gtk_grid_set_column_spacing (GTK_GRID (table), 12);
3576   frame = wrap_in_frame (_("Print Document"), table);
3577   gtk_grid_attach (GTK_GRID (main_table), frame, 0, 1, 1, 1);
3578   gtk_widget_show (table);
3579
3580   /* Translators: this is one of the choices for the print at option
3581    * in the print dialog
3582    */
3583   radio = gtk_radio_button_new_with_mnemonic (NULL, _("_Now"));
3584   priv->print_now_radio = radio;
3585   gtk_widget_show (radio);
3586   gtk_grid_attach (GTK_GRID (table), radio, 0, 0, 2, 1);
3587   /* Translators: this is one of the choices for the print at option
3588    * in the print dialog. It also serves as the label for an entry that
3589    * allows the user to enter a time.
3590    */
3591   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
3592                                               _("A_t:"));
3593
3594   /* Translators: Ability to parse the am/pm format depends on actual locale.
3595    * You can remove the am/pm values below for your locale if they are not
3596    * supported.
3597    */
3598   at_tooltip = _("Specify the time of print,\n e.g. 15:30, 2:35 pm, 14:15:20, 11:46:30 am, 4 pm");
3599   gtk_widget_set_tooltip_text (radio, at_tooltip);
3600   priv->print_at_radio = radio;
3601   gtk_widget_show (radio);
3602   gtk_grid_attach (GTK_GRID (table), radio, 0, 1, 1, 1);
3603
3604   entry = gtk_entry_new ();
3605   gtk_widget_set_tooltip_text (entry, at_tooltip);
3606   atk_object_set_name (gtk_widget_get_accessible (entry), _("Time of print"));
3607   atk_object_set_description (gtk_widget_get_accessible (entry), at_tooltip);
3608   priv->print_at_entry = entry;
3609   gtk_widget_show (entry);
3610   gtk_grid_attach (GTK_GRID (table), entry, 1, 1, 1, 1);
3611
3612   g_signal_connect (radio, "toggled", G_CALLBACK (update_entry_sensitivity), entry);
3613   update_entry_sensitivity (radio, entry);
3614
3615   /* Translators: this is one of the choices for the print at option
3616    * in the print dialog. It means that the print job will not be
3617    * printed until it explicitly gets 'released'.
3618    */
3619   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
3620                                               _("On _hold"));
3621   on_hold_tooltip = _("Hold the job until it is explicitly released");
3622   gtk_widget_set_tooltip_text (radio, on_hold_tooltip);
3623   priv->print_hold_radio = radio;
3624   gtk_widget_show (radio);
3625   gtk_grid_attach (GTK_GRID (table), radio, 0, 2, 2, 1);
3626
3627   g_signal_connect_swapped (priv->print_now_radio, "toggled",
3628                             G_CALLBACK (update_print_at_option), dialog);
3629   g_signal_connect_swapped (priv->print_at_radio, "toggled",
3630                             G_CALLBACK (update_print_at_option), dialog);
3631   g_signal_connect_swapped (priv->print_at_entry, "changed",
3632                             G_CALLBACK (update_print_at_option), dialog);
3633   g_signal_connect_swapped (priv->print_hold_radio, "toggled",
3634                             G_CALLBACK (update_print_at_option), dialog);
3635
3636   table = gtk_grid_new ();
3637   gtk_grid_set_row_spacing (GTK_GRID (table), 6);
3638   gtk_grid_set_column_spacing (GTK_GRID (table), 12);
3639   frame = wrap_in_frame (_("Add Cover Page"), table);
3640   gtk_grid_attach (GTK_GRID (main_table), frame, 1, 0, 1, 1);
3641   gtk_widget_show (table);
3642
3643   /* Translators, this is the label used for the option in the print
3644    * dialog that controls the front cover page.
3645    */
3646   label = gtk_label_new_with_mnemonic (_("Be_fore:"));
3647   gtk_widget_set_halign (label, GTK_ALIGN_START);
3648   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3649   gtk_widget_show (label);
3650   gtk_grid_attach (GTK_GRID (table), label, 0, 0, 1, 1);
3651
3652   widget = gtk_printer_option_widget_new (NULL);
3653   priv->cover_before = GTK_PRINTER_OPTION_WIDGET (widget);
3654   gtk_widget_show (widget);
3655   gtk_grid_attach (GTK_GRID (table), widget, 1, 0, 1, 1);
3656   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3657
3658   /* Translators, this is the label used for the option in the print
3659    * dialog that controls the back cover page.
3660    */
3661   label = gtk_label_new_with_mnemonic (_("_After:"));
3662   gtk_widget_set_halign (label, GTK_ALIGN_START);
3663   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3664   gtk_widget_show (label);
3665   gtk_grid_attach (GTK_GRID (table), label, 0, 1, 1, 1);
3666
3667   widget = gtk_printer_option_widget_new (NULL);
3668   priv->cover_after = GTK_PRINTER_OPTION_WIDGET (widget);
3669   gtk_widget_show (widget);
3670   gtk_grid_attach (GTK_GRID (table), widget, 1, 1, 1, 1);
3671   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3672
3673   /* Translators: this is the tab label for the notebook tab containing
3674    * job-specific options in the print dialog
3675    */
3676   label = gtk_label_new (_("Job"));
3677   gtk_widget_show (label);
3678
3679   priv->job_page = main_table;
3680   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
3681                             main_table, label);
3682 }
3683
3684 static void
3685 create_optional_page (GtkPrintUnixDialog  *dialog,
3686                       const gchar         *text,
3687                       GtkWidget          **table_out,
3688                       GtkWidget          **page_out)
3689 {
3690   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3691   GtkWidget *table, *label, *scrolled;
3692
3693   scrolled = gtk_scrolled_window_new (NULL, NULL);
3694   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
3695                                   GTK_POLICY_NEVER,
3696                                   GTK_POLICY_AUTOMATIC);
3697
3698   table = gtk_grid_new ();
3699   gtk_grid_set_row_spacing (GTK_GRID (table), 6);
3700   gtk_grid_set_column_spacing (GTK_GRID (table), 12);
3701   gtk_container_set_border_width (GTK_CONTAINER (table), 12);
3702   gtk_widget_show (table);
3703
3704   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
3705                                          table);
3706   gtk_viewport_set_shadow_type (GTK_VIEWPORT (gtk_bin_get_child (GTK_BIN (scrolled))),
3707                                 GTK_SHADOW_NONE);
3708
3709   label = gtk_label_new (text);
3710   gtk_widget_show (label);
3711
3712   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
3713                             scrolled, label);
3714
3715   *table_out = table;
3716   *page_out = scrolled;
3717 }
3718
3719 static void
3720 create_advanced_page (GtkPrintUnixDialog *dialog)
3721 {
3722   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3723   GtkWidget *main_vbox, *label, *scrolled;
3724
3725   scrolled = gtk_scrolled_window_new (NULL, NULL);
3726   priv->advanced_page = scrolled;
3727   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
3728                                   GTK_POLICY_NEVER,
3729                                   GTK_POLICY_AUTOMATIC);
3730
3731   main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 18);
3732   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
3733   gtk_widget_show (main_vbox);
3734
3735   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
3736                                          main_vbox);
3737   gtk_viewport_set_shadow_type (GTK_VIEWPORT (gtk_bin_get_child (GTK_BIN (scrolled))),
3738                                 GTK_SHADOW_NONE);
3739
3740   priv->advanced_vbox = main_vbox;
3741
3742   label = gtk_label_new (_("Advanced"));
3743   gtk_widget_show (label);
3744
3745   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
3746                             scrolled, label);
3747 }
3748
3749 static void
3750 populate_dialog (GtkPrintUnixDialog *print_dialog)
3751 {
3752   GtkPrintUnixDialogPrivate *priv = print_dialog->priv;
3753   GtkDialog *dialog = GTK_DIALOG (print_dialog);
3754   GtkWidget *vbox, *conflict_hbox, *image, *label;
3755   GtkWidget *action_area, *content_area;
3756
3757   content_area = gtk_dialog_get_content_area (dialog);
3758   action_area = gtk_dialog_get_action_area (dialog);
3759
3760   gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
3761   gtk_box_set_spacing (GTK_BOX (content_area), 2); /* 2 * 5 + 2 = 12 */
3762   gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
3763   gtk_box_set_spacing (GTK_BOX (action_area), 6);
3764
3765   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
3766   gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
3767   gtk_box_pack_start (GTK_BOX (content_area), vbox, TRUE, TRUE, 0);
3768   gtk_widget_show (vbox);
3769
3770   priv->notebook = gtk_notebook_new ();
3771   gtk_box_pack_start (GTK_BOX (vbox), priv->notebook, TRUE, TRUE, 0);
3772   gtk_widget_show (priv->notebook);
3773
3774   create_printer_list_model (print_dialog);
3775
3776   create_main_page (print_dialog);
3777   create_page_setup_page (print_dialog);
3778   create_job_page (print_dialog);
3779   /* Translators: this will appear as tab label in print dialog. */
3780   create_optional_page (print_dialog, _("Image Quality"),
3781                         &priv->image_quality_table,
3782                         &priv->image_quality_page);
3783   /* Translators: this will appear as tab label in print dialog. */
3784   create_optional_page (print_dialog, _("Color"),
3785                         &priv->color_table,
3786                         &priv->color_page);
3787   /* Translators: this will appear as tab label in print dialog. */
3788   /* It's a typographical term, as in "Binding and finishing" */
3789   create_optional_page (print_dialog, _("Finishing"),
3790                         &priv->finishing_table,
3791                         &priv->finishing_page);
3792   create_advanced_page (print_dialog);
3793
3794   priv->conflicts_widget = conflict_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
3795   gtk_box_pack_end (GTK_BOX (vbox), conflict_hbox, FALSE, FALSE, 0);
3796   image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_MENU);
3797   gtk_widget_show (image);
3798   gtk_box_pack_start (GTK_BOX (conflict_hbox), image, FALSE, TRUE, 0);
3799   label = gtk_label_new (_("Some of the settings in the dialog conflict"));
3800   gtk_widget_show (label);
3801   gtk_box_pack_start (GTK_BOX (conflict_hbox), label, FALSE, TRUE, 0);
3802
3803   load_print_backends (print_dialog);
3804 }
3805
3806 /**
3807  * gtk_print_unix_dialog_new:
3808  * @title: (allow-none): Title of the dialog, or %NULL
3809  * @parent: (allow-none): Transient parent of the dialog, or %NULL
3810  *
3811  * Creates a new #GtkPrintUnixDialog.
3812  *
3813  * Return value: a new #GtkPrintUnixDialog
3814  *
3815  * Since: 2.10
3816  */
3817 GtkWidget *
3818 gtk_print_unix_dialog_new (const gchar *title,
3819                            GtkWindow   *parent)
3820 {
3821   GtkWidget *result;
3822
3823   result = g_object_new (GTK_TYPE_PRINT_UNIX_DIALOG,
3824                          "transient-for", parent,
3825                          "title", title ? title : _("Print"),
3826                          NULL);
3827
3828   return result;
3829 }
3830
3831 /**
3832  * gtk_print_unix_dialog_get_selected_printer:
3833  * @dialog: a #GtkPrintUnixDialog
3834  *
3835  * Gets the currently selected printer.
3836  *
3837  * Returns: (transfer none): the currently selected printer
3838  *
3839  * Since: 2.10
3840  */
3841 GtkPrinter *
3842 gtk_print_unix_dialog_get_selected_printer (GtkPrintUnixDialog *dialog)
3843 {
3844   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
3845
3846   return dialog->priv->current_printer;
3847 }
3848
3849 /**
3850  * gtk_print_unix_dialog_set_page_setup:
3851  * @dialog: a #GtkPrintUnixDialog
3852  * @page_setup: a #GtkPageSetup
3853  *
3854  * Sets the page setup of the #GtkPrintUnixDialog.
3855  *
3856  * Since: 2.10
3857  */
3858 void
3859 gtk_print_unix_dialog_set_page_setup (GtkPrintUnixDialog *dialog,
3860                                       GtkPageSetup       *page_setup)
3861 {
3862   GtkPrintUnixDialogPrivate *priv;
3863
3864   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
3865   g_return_if_fail (GTK_IS_PAGE_SETUP (page_setup));
3866
3867   priv = dialog->priv;
3868
3869   if (priv->page_setup != page_setup)
3870     {
3871       g_object_unref (priv->page_setup);
3872       priv->page_setup = g_object_ref (page_setup);
3873
3874       priv->page_setup_set = TRUE;
3875
3876       g_object_notify (G_OBJECT (dialog), "page-setup");
3877     }
3878 }
3879
3880 /**
3881  * gtk_print_unix_dialog_get_page_setup:
3882  * @dialog: a #GtkPrintUnixDialog
3883  *
3884  * Gets the page setup that is used by the #GtkPrintUnixDialog.
3885  *
3886  * Returns: (transfer none): the page setup of @dialog.
3887  *
3888  * Since: 2.10
3889  */
3890 GtkPageSetup *
3891 gtk_print_unix_dialog_get_page_setup (GtkPrintUnixDialog *dialog)
3892 {
3893   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
3894
3895   return dialog->priv->page_setup;
3896 }
3897
3898 /**
3899  * gtk_print_unix_dialog_get_page_setup_set:
3900  * @dialog: a #GtkPrintUnixDialog
3901  *
3902  * Gets the page setup that is used by the #GtkPrintUnixDialog.
3903  *
3904  * Returns: whether a page setup was set by user.
3905  *
3906  * Since: 2.18
3907  */
3908 gboolean
3909 gtk_print_unix_dialog_get_page_setup_set (GtkPrintUnixDialog *dialog)
3910 {
3911   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), FALSE);
3912
3913   return dialog->priv->page_setup_set;
3914 }
3915
3916 /**
3917  * gtk_print_unix_dialog_set_current_page:
3918  * @dialog: a #GtkPrintUnixDialog
3919  * @current_page: the current page number.
3920  *
3921  * Sets the current page number. If @current_page is not -1, this enables
3922  * the current page choice for the range of pages to print.
3923  *
3924  * Since: 2.10
3925  */
3926 void
3927 gtk_print_unix_dialog_set_current_page (GtkPrintUnixDialog *dialog,
3928                                         gint                current_page)
3929 {
3930   GtkPrintUnixDialogPrivate *priv;
3931
3932   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
3933
3934   priv = dialog->priv;
3935
3936   if (priv->current_page != current_page)
3937     {
3938       priv->current_page = current_page;
3939
3940       if (priv->current_page_radio)
3941         gtk_widget_set_sensitive (priv->current_page_radio, current_page != -1);
3942
3943       g_object_notify (G_OBJECT (dialog), "current-page");
3944     }
3945 }
3946
3947 /**
3948  * gtk_print_unix_dialog_get_current_page:
3949  * @dialog: a #GtkPrintUnixDialog
3950  *
3951  * Gets the current page of the #GtkPrintDialog.
3952  *
3953  * Returns: the current page of @dialog
3954  *
3955  * Since: 2.10
3956  */
3957 gint
3958 gtk_print_unix_dialog_get_current_page (GtkPrintUnixDialog *dialog)
3959 {
3960   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), -1);
3961
3962   return dialog->priv->current_page;
3963 }
3964
3965 static gboolean
3966 set_active_printer (GtkPrintUnixDialog *dialog,
3967                     const gchar        *printer_name)
3968 {
3969   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3970   GtkTreeModel *model;
3971   GtkTreeIter iter, filter_iter;
3972   GtkTreeSelection *selection;
3973   GtkPrinter *printer;
3974
3975   model = GTK_TREE_MODEL (priv->printer_list);
3976
3977   if (gtk_tree_model_get_iter_first (model, &iter))
3978     {
3979       do
3980         {
3981           gtk_tree_model_get (GTK_TREE_MODEL (priv->printer_list), &iter,
3982                               PRINTER_LIST_COL_PRINTER_OBJ, &printer,
3983                               -1);
3984           if (printer == NULL)
3985             continue;
3986
3987           if (strcmp (gtk_printer_get_name (printer), printer_name) == 0)
3988             {
3989               gtk_tree_model_filter_convert_child_iter_to_iter (priv->printer_list_filter,
3990                                                                 &filter_iter, &iter);
3991
3992               selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
3993               priv->internal_printer_change = TRUE;
3994               gtk_tree_selection_select_iter (selection, &filter_iter);
3995               priv->internal_printer_change = FALSE;
3996               g_free (priv->waiting_for_printer);
3997               priv->waiting_for_printer = NULL;
3998
3999               g_object_unref (printer);
4000               return TRUE;
4001             }
4002
4003           g_object_unref (printer);
4004
4005         } while (gtk_tree_model_iter_next (model, &iter));
4006     }
4007
4008   return FALSE;
4009 }
4010
4011 /**
4012  * gtk_print_unix_dialog_set_settings:
4013  * @dialog: a #GtkPrintUnixDialog
4014  * @settings: (allow-none): a #GtkPrintSettings, or %NULL
4015  *
4016  * Sets the #GtkPrintSettings for the #GtkPrintUnixDialog. Typically,
4017  * this is used to restore saved print settings from a previous print
4018  * operation before the print dialog is shown.
4019  *
4020  * Since: 2.10
4021  **/
4022 void
4023 gtk_print_unix_dialog_set_settings (GtkPrintUnixDialog *dialog,
4024                                     GtkPrintSettings   *settings)
4025 {
4026   GtkPrintUnixDialogPrivate *priv;
4027   const gchar *printer;
4028   GtkPageRange *ranges;
4029   gint num_ranges;
4030
4031   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
4032   g_return_if_fail (settings == NULL || GTK_IS_PRINT_SETTINGS (settings));
4033
4034   priv = dialog->priv;
4035
4036   if (settings != NULL)
4037     {
4038       dialog_set_collate (dialog, gtk_print_settings_get_collate (settings));
4039       dialog_set_reverse (dialog, gtk_print_settings_get_reverse (settings));
4040       dialog_set_n_copies (dialog, gtk_print_settings_get_n_copies (settings));
4041       dialog_set_scale (dialog, gtk_print_settings_get_scale (settings));
4042       dialog_set_page_set (dialog, gtk_print_settings_get_page_set (settings));
4043       dialog_set_print_pages (dialog, gtk_print_settings_get_print_pages (settings));
4044       ranges = gtk_print_settings_get_page_ranges (settings, &num_ranges);
4045       if (ranges)
4046         {
4047           dialog_set_page_ranges (dialog, ranges, num_ranges);
4048           g_free (ranges);
4049         }
4050
4051       priv->format_for_printer =
4052         g_strdup (gtk_print_settings_get (settings, "format-for-printer"));
4053     }
4054
4055   if (priv->initial_settings)
4056     g_object_unref (priv->initial_settings);
4057
4058   priv->initial_settings = settings;
4059
4060   g_free (priv->waiting_for_printer);
4061   priv->waiting_for_printer = NULL;
4062
4063   if (settings)
4064     {
4065       g_object_ref (settings);
4066
4067       printer = gtk_print_settings_get_printer (settings);
4068
4069       if (printer && !set_active_printer (dialog, printer))
4070         priv->waiting_for_printer = g_strdup (printer);
4071     }
4072
4073   g_object_notify (G_OBJECT (dialog), "print-settings");
4074 }
4075
4076 /**
4077  * gtk_print_unix_dialog_get_settings:
4078  * @dialog: a #GtkPrintUnixDialog
4079  *
4080  * Gets a new #GtkPrintSettings object that represents the
4081  * current values in the print dialog. Note that this creates a
4082  * <emphasis>new object</emphasis>, and you need to unref it
4083  * if don't want to keep it.
4084  *
4085  * Returns: a new #GtkPrintSettings object with the values from @dialog
4086  *
4087  * Since: 2.10
4088  */
4089 GtkPrintSettings *
4090 gtk_print_unix_dialog_get_settings (GtkPrintUnixDialog *dialog)
4091 {
4092   GtkPrintUnixDialogPrivate *priv;
4093   GtkPrintSettings *settings;
4094   GtkPrintPages print_pages;
4095   GtkPageRange *ranges;
4096   gint n_ranges;
4097
4098   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
4099
4100   priv = dialog->priv;
4101   settings = gtk_print_settings_new ();
4102
4103   if (priv->current_printer)
4104     gtk_print_settings_set_printer (settings,
4105                                     gtk_printer_get_name (priv->current_printer));
4106   else
4107     gtk_print_settings_set_printer (settings, "default");
4108
4109   gtk_print_settings_set (settings, "format-for-printer",
4110                           priv->format_for_printer);
4111
4112   gtk_print_settings_set_collate (settings,
4113                                   dialog_get_collate (dialog));
4114
4115   gtk_print_settings_set_reverse (settings,
4116                                   dialog_get_reverse (dialog));
4117
4118   gtk_print_settings_set_n_copies (settings,
4119                                    dialog_get_n_copies (dialog));
4120
4121   gtk_print_settings_set_scale (settings,
4122                                 dialog_get_scale (dialog));
4123
4124   gtk_print_settings_set_page_set (settings,
4125                                    dialog_get_page_set (dialog));
4126
4127   print_pages = dialog_get_print_pages (dialog);
4128   gtk_print_settings_set_print_pages (settings, print_pages);
4129
4130   ranges = dialog_get_page_ranges (dialog, &n_ranges);
4131   if (ranges)
4132     {
4133       gtk_print_settings_set_page_ranges (settings, ranges, n_ranges);
4134       g_free (ranges);
4135     }
4136
4137   /* TODO: print when. How to handle? */
4138
4139   if (priv->current_printer)
4140     _gtk_printer_get_settings_from_options (priv->current_printer,
4141                                             priv->options,
4142                                             settings);
4143
4144   return settings;
4145 }
4146
4147 /**
4148  * gtk_print_unix_dialog_add_custom_tab:
4149  * @dialog: a #GtkPrintUnixDialog
4150  * @child: the widget to put in the custom tab
4151  * @tab_label: the widget to use as tab label
4152  *
4153  * Adds a custom tab to the print dialog.
4154  *
4155  * Since: 2.10
4156  */
4157 void
4158 gtk_print_unix_dialog_add_custom_tab (GtkPrintUnixDialog *dialog,
4159                                       GtkWidget          *child,
4160                                       GtkWidget          *tab_label)
4161 {
4162   gtk_notebook_insert_page (GTK_NOTEBOOK (dialog->priv->notebook),
4163                             child, tab_label, 2);
4164   gtk_widget_show (child);
4165   gtk_widget_show (tab_label);
4166 }
4167
4168 /**
4169  * gtk_print_unix_dialog_set_manual_capabilities:
4170  * @dialog: a #GtkPrintUnixDialog
4171  * @capabilities: the printing capabilities of your application
4172  *
4173  * This lets you specify the printing capabilities your application
4174  * supports. For instance, if you can handle scaling the output then
4175  * you pass #GTK_PRINT_CAPABILITY_SCALE. If you don't pass that, then
4176  * the dialog will only let you select the scale if the printing
4177  * system automatically handles scaling.
4178  *
4179  * Since: 2.10
4180  */
4181 void
4182 gtk_print_unix_dialog_set_manual_capabilities (GtkPrintUnixDialog   *dialog,
4183                                                GtkPrintCapabilities  capabilities)
4184 {
4185   GtkPrintUnixDialogPrivate *priv = dialog->priv;
4186
4187   if (priv->manual_capabilities != capabilities)
4188     {
4189       priv->manual_capabilities = capabilities;
4190       update_dialog_from_capabilities (dialog);
4191
4192       if (priv->current_printer)
4193         {
4194           GtkTreeSelection *selection;
4195
4196           selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
4197           g_clear_object (&priv->current_printer);
4198           priv->internal_printer_change = TRUE;
4199           selected_printer_changed (selection, dialog);
4200           priv->internal_printer_change = FALSE;
4201        }
4202
4203       g_object_notify (G_OBJECT (dialog), "manual-capabilities");
4204     }
4205 }
4206
4207 /**
4208  * gtk_print_unix_dialog_get_manual_capabilities:
4209  * @dialog: a #GtkPrintUnixDialog
4210  *
4211  * Gets the value of #GtkPrintUnixDialog:manual-capabilities property.
4212  *
4213  * Returns: the printing capabilities
4214  *
4215  * Since: 2.18
4216  */
4217 GtkPrintCapabilities
4218 gtk_print_unix_dialog_get_manual_capabilities (GtkPrintUnixDialog *dialog)
4219 {
4220   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), FALSE);
4221
4222   return dialog->priv->manual_capabilities;
4223 }
4224
4225 /**
4226  * gtk_print_unix_dialog_set_support_selection:
4227  * @dialog: a #GtkPrintUnixDialog
4228  * @support_selection: %TRUE to allow print selection
4229  *
4230  * Sets whether the print dialog allows user to print a selection.
4231  *
4232  * Since: 2.18
4233  */
4234 void
4235 gtk_print_unix_dialog_set_support_selection (GtkPrintUnixDialog *dialog,
4236                                              gboolean            support_selection)
4237 {
4238   GtkPrintUnixDialogPrivate *priv;
4239
4240   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
4241
4242   priv = dialog->priv;
4243
4244   support_selection = support_selection != FALSE;
4245   if (priv->support_selection != support_selection)
4246     {
4247       priv->support_selection = support_selection;
4248
4249       if (priv->selection_radio)
4250         {
4251           if (support_selection)
4252             {
4253               gtk_widget_set_sensitive (priv->selection_radio, priv->has_selection);
4254               gtk_widget_show (priv->selection_radio);
4255             }
4256           else
4257             {
4258               gtk_widget_set_sensitive (priv->selection_radio, FALSE);
4259               gtk_widget_hide (priv->selection_radio);
4260             }
4261         }
4262
4263       g_object_notify (G_OBJECT (dialog), "support-selection");
4264     }
4265 }
4266
4267 /**
4268  * gtk_print_unix_dialog_get_support_selection:
4269  * @dialog: a #GtkPrintUnixDialog
4270  *
4271  * Gets the value of #GtkPrintUnixDialog:support-selection property.
4272  *
4273  * Returns: whether the application supports print of selection
4274  *
4275  * Since: 2.18
4276  */
4277 gboolean
4278 gtk_print_unix_dialog_get_support_selection (GtkPrintUnixDialog *dialog)
4279 {
4280   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), FALSE);
4281
4282   return dialog->priv->support_selection;
4283 }
4284
4285 /**
4286  * gtk_print_unix_dialog_set_has_selection:
4287  * @dialog: a #GtkPrintUnixDialog
4288  * @has_selection: %TRUE indicates that a selection exists
4289  *
4290  * Sets whether a selection exists.
4291  *
4292  * Since: 2.18
4293  */
4294 void
4295 gtk_print_unix_dialog_set_has_selection (GtkPrintUnixDialog *dialog,
4296                                          gboolean            has_selection)
4297 {
4298   GtkPrintUnixDialogPrivate *priv;
4299
4300   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
4301
4302   priv = dialog->priv;
4303
4304   has_selection = has_selection != FALSE;
4305   if (priv->has_selection != has_selection)
4306     {
4307       priv->has_selection = has_selection;
4308
4309       if (priv->selection_radio)
4310         {
4311           if (priv->support_selection)
4312             gtk_widget_set_sensitive (priv->selection_radio, has_selection);
4313           else
4314             gtk_widget_set_sensitive (priv->selection_radio, FALSE);
4315         }
4316
4317       g_object_notify (G_OBJECT (dialog), "has-selection");
4318     }
4319 }
4320
4321 /**
4322  * gtk_print_unix_dialog_get_has_selection:
4323  * @dialog: a #GtkPrintUnixDialog
4324  *
4325  * Gets the value of #GtkPrintUnixDialog:has-selection property.
4326  *
4327  * Returns: whether there is a selection
4328  *
4329  * Since: 2.18
4330  */
4331 gboolean
4332 gtk_print_unix_dialog_get_has_selection (GtkPrintUnixDialog *dialog)
4333 {
4334   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), FALSE);
4335
4336   return dialog->priv->has_selection;
4337 }
4338
4339 /**
4340  * gtk_print_unix_dialog_set_embed_page_setup
4341  * @dialog: a #GtkPrintUnixDialog
4342  * @embed: embed page setup selection
4343  *
4344  * Embed page size combo box and orientation combo box into page setup page.
4345  *
4346  * Since: 2.18
4347  */
4348 void
4349 gtk_print_unix_dialog_set_embed_page_setup (GtkPrintUnixDialog *dialog,
4350                                             gboolean            embed)
4351 {
4352   GtkPrintUnixDialogPrivate *priv;
4353
4354   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
4355
4356   priv = dialog->priv;
4357
4358   embed = embed != FALSE;
4359   if (priv->embed_page_setup != embed)
4360     {
4361       priv->embed_page_setup = embed;
4362
4363       gtk_widget_set_sensitive (priv->paper_size_combo, priv->embed_page_setup);
4364       gtk_widget_set_sensitive (priv->orientation_combo, priv->embed_page_setup);
4365
4366       if (priv->embed_page_setup)
4367         {
4368           if (priv->paper_size_combo != NULL)
4369             g_signal_connect (priv->paper_size_combo, "changed", G_CALLBACK (paper_size_changed), dialog);
4370
4371           if (priv->orientation_combo)
4372             g_signal_connect (priv->orientation_combo, "changed", G_CALLBACK (orientation_changed), dialog);
4373         }
4374       else
4375         {
4376           if (priv->paper_size_combo != NULL)
4377             g_signal_handlers_disconnect_by_func (priv->paper_size_combo, G_CALLBACK (paper_size_changed), dialog);
4378
4379           if (priv->orientation_combo)
4380             g_signal_handlers_disconnect_by_func (priv->orientation_combo, G_CALLBACK (orientation_changed), dialog);
4381         }
4382
4383       priv->internal_page_setup_change = TRUE;
4384       update_paper_sizes (dialog);
4385       priv->internal_page_setup_change = FALSE;
4386     }
4387 }
4388
4389 /**
4390  * gtk_print_unix_dialog_get_embed_page_setup:
4391  * @dialog: a #GtkPrintUnixDialog
4392  *
4393  * Gets the value of #GtkPrintUnixDialog:embed-page-setup property.
4394  *
4395  * Returns: whether there is a selection
4396  *
4397  * Since: 2.18
4398  */
4399 gboolean
4400 gtk_print_unix_dialog_get_embed_page_setup (GtkPrintUnixDialog *dialog)
4401 {
4402   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), FALSE);
4403
4404   return dialog->priv->embed_page_setup;
4405 }