]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintunixdialog.c
stylecontext: Do invalidation on first resize container
[~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, TRUE, TRUE, 0);
1210     }
1211   else
1212     gtk_box_pack_start (GTK_BOX (extension_point), widget, TRUE, TRUE, 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   GList *children;
1391
1392   if (priv->current_printer == NULL)
1393     {
1394        clear_per_printer_ui (dialog);
1395        gtk_widget_hide (priv->job_page);
1396        gtk_widget_hide (priv->advanced_page);
1397        gtk_widget_hide (priv->image_quality_page);
1398        gtk_widget_hide (priv->finishing_page);
1399        gtk_widget_hide (priv->color_page);
1400        gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
1401
1402        return;
1403     }
1404
1405   setup_option (dialog, "gtk-n-up", priv->pages_per_sheet);
1406   setup_option (dialog, "gtk-n-up-layout", priv->number_up_layout);
1407   setup_option (dialog, "gtk-duplex", priv->duplex);
1408   setup_option (dialog, "gtk-paper-type", priv->paper_type);
1409   setup_option (dialog, "gtk-paper-source", priv->paper_source);
1410   setup_option (dialog, "gtk-output-tray", priv->output_tray);
1411
1412   has_job = FALSE;
1413   has_job |= setup_option (dialog, "gtk-job-prio", priv->job_prio);
1414   has_job |= setup_option (dialog, "gtk-billing-info", priv->billing_info);
1415   has_job |= setup_option (dialog, "gtk-cover-before", priv->cover_before);
1416   has_job |= setup_option (dialog, "gtk-cover-after", priv->cover_after);
1417   has_job |= setup_print_at (dialog);
1418
1419   if (has_job)
1420     gtk_widget_show (priv->job_page);
1421   else
1422     gtk_widget_hide (priv->job_page);
1423
1424   setup_page_table (priv->options,
1425                     "ImageQualityPage",
1426                     priv->image_quality_table,
1427                     priv->image_quality_page);
1428
1429   setup_page_table (priv->options,
1430                     "FinishingPage",
1431                     priv->finishing_table,
1432                     priv->finishing_page);
1433
1434   setup_page_table (priv->options,
1435                     "ColorPage",
1436                     priv->color_table,
1437                     priv->color_page);
1438
1439   gtk_printer_option_set_foreach_in_group (priv->options,
1440                                            "GtkPrintDialogExtension",
1441                                            add_option_to_extension_point,
1442                                            priv->extension_point);
1443
1444   /* A bit of a hack, keep the last option flush right.
1445    * This keeps the file format radios from moving as the
1446    * filename changes.
1447    */
1448   children = gtk_container_get_children (GTK_CONTAINER (priv->extension_point));
1449   l = g_list_last (children);
1450   if (l && l != children)
1451     gtk_widget_set_halign (GTK_WIDGET (l->data), GTK_ALIGN_END);
1452   g_list_free (children);
1453
1454   /* Put the rest of the groups in the advanced page */
1455   groups = gtk_printer_option_set_get_groups (priv->options);
1456
1457   has_advanced = FALSE;
1458   for (l = groups; l != NULL; l = l->next)
1459     {
1460       group = l->data;
1461
1462       if (group == NULL)
1463         continue;
1464
1465       if (strcmp (group, "ImageQualityPage") == 0 ||
1466           strcmp (group, "ColorPage") == 0 ||
1467           strcmp (group, "FinishingPage") == 0 ||
1468           strcmp (group, "GtkPrintDialogExtension") == 0)
1469         continue;
1470
1471       table = gtk_grid_new ();
1472       gtk_grid_set_row_spacing (GTK_GRID (table), 6);
1473       gtk_grid_set_column_spacing (GTK_GRID (table), 12);
1474
1475       gtk_printer_option_set_foreach_in_group (priv->options,
1476                                                group,
1477                                                add_option_to_table,
1478                                                table);
1479
1480       nrows = grid_rows (GTK_GRID (table));
1481       if (nrows == 0)
1482         gtk_widget_destroy (table);
1483       else
1484         {
1485           has_advanced = TRUE;
1486           frame = wrap_in_frame (group, table);
1487           gtk_widget_show (table);
1488           gtk_widget_show (frame);
1489
1490           gtk_box_pack_start (GTK_BOX (priv->advanced_vbox),
1491                               frame, FALSE, FALSE, 0);
1492         }
1493     }
1494
1495   if (has_advanced)
1496     gtk_widget_show (priv->advanced_page);
1497   else
1498     gtk_widget_hide (priv->advanced_page);
1499
1500   g_list_free_full (groups, g_free);
1501 }
1502
1503 static void
1504 update_dialog_from_capabilities (GtkPrintUnixDialog *dialog)
1505 {
1506   GtkPrintCapabilities caps;
1507   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1508   gboolean can_collate;
1509   const gchar *copies;
1510
1511   copies = gtk_entry_get_text (GTK_ENTRY (priv->copies_spin));
1512   can_collate = (*copies != '\0' && atoi (copies) > 1);
1513
1514   caps = priv->manual_capabilities | priv->printer_capabilities;
1515
1516   gtk_widget_set_sensitive (priv->page_set_combo,
1517                             caps & GTK_PRINT_CAPABILITY_PAGE_SET);
1518   gtk_widget_set_sensitive (priv->copies_spin,
1519                             caps & GTK_PRINT_CAPABILITY_COPIES);
1520   gtk_widget_set_sensitive (priv->collate_check,
1521                             can_collate &&
1522                             (caps & GTK_PRINT_CAPABILITY_COLLATE));
1523   gtk_widget_set_sensitive (priv->reverse_check,
1524                             caps & GTK_PRINT_CAPABILITY_REVERSE);
1525   gtk_widget_set_sensitive (priv->scale_spin,
1526                             caps & GTK_PRINT_CAPABILITY_SCALE);
1527   gtk_widget_set_sensitive (GTK_WIDGET (priv->pages_per_sheet),
1528                             caps & GTK_PRINT_CAPABILITY_NUMBER_UP);
1529
1530   if (caps & GTK_PRINT_CAPABILITY_PREVIEW)
1531     gtk_widget_show (priv->preview_button);
1532   else
1533     gtk_widget_hide (priv->preview_button);
1534
1535   update_collate_icon (NULL, dialog);
1536
1537   gtk_tree_model_filter_refilter (priv->printer_list_filter);
1538 }
1539
1540 static gboolean
1541 page_setup_is_equal (GtkPageSetup *a,
1542                      GtkPageSetup *b)
1543 {
1544   return
1545     gtk_paper_size_is_equal (gtk_page_setup_get_paper_size (a),
1546                              gtk_page_setup_get_paper_size (b)) &&
1547     gtk_page_setup_get_top_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_top_margin (b, GTK_UNIT_MM) &&
1548     gtk_page_setup_get_bottom_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_bottom_margin (b, GTK_UNIT_MM) &&
1549     gtk_page_setup_get_left_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_left_margin (b, GTK_UNIT_MM) &&
1550     gtk_page_setup_get_right_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_right_margin (b, GTK_UNIT_MM);
1551 }
1552
1553 static gboolean
1554 page_setup_is_same_size (GtkPageSetup *a,
1555                          GtkPageSetup *b)
1556 {
1557   return gtk_paper_size_is_equal (gtk_page_setup_get_paper_size (a),
1558                                   gtk_page_setup_get_paper_size (b));
1559 }
1560
1561 static gboolean
1562 set_paper_size (GtkPrintUnixDialog *dialog,
1563                 GtkPageSetup       *page_setup,
1564                 gboolean            size_only,
1565                 gboolean            add_item)
1566 {
1567   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1568   GtkTreeModel *model;
1569   GtkTreeIter iter;
1570   GtkPageSetup *list_page_setup;
1571
1572   if (!priv->internal_page_setup_change)
1573     return TRUE;
1574
1575   if (page_setup == NULL)
1576     return FALSE;
1577
1578   model = GTK_TREE_MODEL (priv->page_setup_list);
1579
1580   if (gtk_tree_model_get_iter_first (model, &iter))
1581     {
1582       do
1583         {
1584           gtk_tree_model_get (GTK_TREE_MODEL (priv->page_setup_list), &iter,
1585                               PAGE_SETUP_LIST_COL_PAGE_SETUP, &list_page_setup,
1586                               -1);
1587           if (list_page_setup == NULL)
1588             continue;
1589
1590           if ((size_only && page_setup_is_same_size (page_setup, list_page_setup)) ||
1591               (!size_only && page_setup_is_equal (page_setup, list_page_setup)))
1592             {
1593               gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->paper_size_combo),
1594                                              &iter);
1595               gtk_combo_box_set_active (GTK_COMBO_BOX (priv->orientation_combo),
1596                                         gtk_page_setup_get_orientation (page_setup));
1597               g_object_unref (list_page_setup);
1598               return TRUE;
1599             }
1600
1601           g_object_unref (list_page_setup);
1602
1603         } while (gtk_tree_model_iter_next (model, &iter));
1604     }
1605
1606   if (add_item)
1607     {
1608       gtk_list_store_append (priv->page_setup_list, &iter);
1609       gtk_list_store_set (priv->page_setup_list, &iter,
1610                           PAGE_SETUP_LIST_COL_IS_SEPARATOR, TRUE,
1611                           -1);
1612       gtk_list_store_append (priv->page_setup_list, &iter);
1613       gtk_list_store_set (priv->page_setup_list, &iter,
1614                           PAGE_SETUP_LIST_COL_PAGE_SETUP, page_setup,
1615                           -1);
1616       gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->paper_size_combo),
1617                                      &iter);
1618       gtk_combo_box_set_active (GTK_COMBO_BOX (priv->orientation_combo),
1619                                 gtk_page_setup_get_orientation (page_setup));
1620       return TRUE;
1621     }
1622
1623   return FALSE;
1624 }
1625
1626 static void
1627 fill_custom_paper_sizes (GtkPrintUnixDialog *dialog)
1628 {
1629   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1630   GtkTreeIter iter, paper_iter;
1631   GtkTreeModel *model;
1632
1633   model = GTK_TREE_MODEL (priv->custom_paper_list);
1634   if (gtk_tree_model_get_iter_first (model, &iter))
1635     {
1636       gtk_list_store_append (priv->page_setup_list, &paper_iter);
1637       gtk_list_store_set (priv->page_setup_list, &paper_iter,
1638                           PAGE_SETUP_LIST_COL_IS_SEPARATOR, TRUE,
1639                           -1);
1640       do
1641         {
1642           GtkPageSetup *page_setup;
1643           gtk_tree_model_get (model, &iter, 0, &page_setup, -1);
1644
1645           gtk_list_store_append (priv->page_setup_list, &paper_iter);
1646           gtk_list_store_set (priv->page_setup_list, &paper_iter,
1647                               PAGE_SETUP_LIST_COL_PAGE_SETUP, page_setup,
1648                               -1);
1649
1650           g_object_unref (page_setup);
1651         } while (gtk_tree_model_iter_next (model, &iter));
1652     }
1653
1654   gtk_list_store_append (priv->page_setup_list, &paper_iter);
1655   gtk_list_store_set (priv->page_setup_list, &paper_iter,
1656                       PAGE_SETUP_LIST_COL_IS_SEPARATOR, TRUE,
1657                       -1);
1658   gtk_list_store_append (priv->page_setup_list, &paper_iter);
1659   gtk_list_store_set (priv->page_setup_list, &paper_iter,
1660                       PAGE_SETUP_LIST_COL_PAGE_SETUP, NULL,
1661                       -1);
1662 }
1663
1664 static void
1665 fill_paper_sizes (GtkPrintUnixDialog *dialog,
1666                   GtkPrinter         *printer)
1667 {
1668   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1669   GList *list, *l;
1670   GtkPageSetup *page_setup;
1671   GtkPaperSize *paper_size;
1672   GtkTreeIter iter;
1673   gint i;
1674
1675   gtk_list_store_clear (priv->page_setup_list);
1676
1677   if (printer == NULL || (list = gtk_printer_list_papers (printer)) == NULL)
1678     {
1679       for (i = 0; i < G_N_ELEMENTS (common_paper_sizes); i++)
1680         {
1681           page_setup = gtk_page_setup_new ();
1682           paper_size = gtk_paper_size_new (common_paper_sizes[i]);
1683           gtk_page_setup_set_paper_size_and_default_margins (page_setup, paper_size);
1684           gtk_paper_size_free (paper_size);
1685
1686           gtk_list_store_append (priv->page_setup_list, &iter);
1687           gtk_list_store_set (priv->page_setup_list, &iter,
1688                               PAGE_SETUP_LIST_COL_PAGE_SETUP, page_setup,
1689                               -1);
1690           g_object_unref (page_setup);
1691         }
1692     }
1693   else
1694     {
1695       for (l = list; l != NULL; l = l->next)
1696         {
1697           page_setup = l->data;
1698           gtk_list_store_append (priv->page_setup_list, &iter);
1699           gtk_list_store_set (priv->page_setup_list, &iter,
1700                               PAGE_SETUP_LIST_COL_PAGE_SETUP, page_setup,
1701                               -1);
1702           g_object_unref (page_setup);
1703         }
1704       g_list_free (list);
1705     }
1706
1707   fill_custom_paper_sizes (dialog);
1708 }
1709
1710 static void
1711 update_paper_sizes (GtkPrintUnixDialog *dialog)
1712 {
1713   GtkPageSetup *current_page_setup = NULL;
1714   GtkPrinter   *printer;
1715
1716   printer = gtk_print_unix_dialog_get_selected_printer (dialog);
1717
1718   fill_paper_sizes (dialog, printer);
1719
1720   current_page_setup = gtk_page_setup_copy (gtk_print_unix_dialog_get_page_setup (dialog));
1721
1722   if (current_page_setup)
1723     {
1724       if (!set_paper_size (dialog, current_page_setup, FALSE, FALSE))
1725         set_paper_size (dialog, current_page_setup, TRUE, TRUE);
1726
1727       g_object_unref (current_page_setup);
1728     }
1729 }
1730
1731 static void
1732 mark_conflicts (GtkPrintUnixDialog *dialog)
1733 {
1734   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1735   GtkPrinter *printer;
1736   gboolean have_conflict;
1737
1738   have_conflict = FALSE;
1739
1740   printer = priv->current_printer;
1741
1742   if (printer)
1743     {
1744
1745       g_signal_handler_block (priv->options,
1746                               priv->options_changed_handler);
1747
1748       gtk_printer_option_set_clear_conflicts (priv->options);
1749
1750       have_conflict = _gtk_printer_mark_conflicts (printer,
1751                                                    priv->options);
1752
1753       g_signal_handler_unblock (priv->options,
1754                                 priv->options_changed_handler);
1755     }
1756
1757   if (have_conflict)
1758     gtk_widget_show (priv->conflicts_widget);
1759   else
1760     gtk_widget_hide (priv->conflicts_widget);
1761 }
1762
1763 static gboolean
1764 mark_conflicts_callback (gpointer data)
1765 {
1766   GtkPrintUnixDialog *dialog = data;
1767   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1768
1769   priv->mark_conflicts_id = 0;
1770
1771   mark_conflicts (dialog);
1772
1773   return FALSE;
1774 }
1775
1776 static void
1777 unschedule_idle_mark_conflicts (GtkPrintUnixDialog *dialog)
1778 {
1779   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1780
1781   if (priv->mark_conflicts_id != 0)
1782     {
1783       g_source_remove (priv->mark_conflicts_id);
1784       priv->mark_conflicts_id = 0;
1785     }
1786 }
1787
1788 static void
1789 schedule_idle_mark_conflicts (GtkPrintUnixDialog *dialog)
1790 {
1791   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1792
1793   if (priv->mark_conflicts_id != 0)
1794     return;
1795
1796   priv->mark_conflicts_id = gdk_threads_add_idle (mark_conflicts_callback,
1797                                         dialog);
1798 }
1799
1800 static void
1801 options_changed_cb (GtkPrintUnixDialog *dialog)
1802 {
1803   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1804
1805   schedule_idle_mark_conflicts (dialog);
1806
1807   g_free (priv->waiting_for_printer);
1808   priv->waiting_for_printer = NULL;
1809 }
1810
1811 static void
1812 remove_custom_widget (GtkWidget    *widget,
1813                       GtkContainer *container)
1814 {
1815   gtk_container_remove (container, widget);
1816 }
1817
1818 static void
1819 extension_point_clear_children (GtkContainer *container)
1820 {
1821   gtk_container_foreach (container,
1822                          (GtkCallback)remove_custom_widget,
1823                          container);
1824 }
1825
1826 static void
1827 clear_per_printer_ui (GtkPrintUnixDialog *dialog)
1828 {
1829   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1830
1831   gtk_container_foreach (GTK_CONTAINER (priv->finishing_table),
1832                          (GtkCallback)gtk_widget_destroy, NULL);
1833   gtk_container_foreach (GTK_CONTAINER (priv->image_quality_table),
1834                          (GtkCallback)gtk_widget_destroy, NULL);
1835   gtk_container_foreach (GTK_CONTAINER (priv->color_table),
1836                          (GtkCallback)gtk_widget_destroy, NULL);
1837   gtk_container_foreach (GTK_CONTAINER (priv->advanced_vbox),
1838                          (GtkCallback)gtk_widget_destroy, NULL);
1839   extension_point_clear_children (GTK_CONTAINER (priv->extension_point));
1840 }
1841
1842 static void
1843 printer_details_acquired (GtkPrinter         *printer,
1844                           gboolean            success,
1845                           GtkPrintUnixDialog *dialog)
1846 {
1847   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1848
1849   disconnect_printer_details_request (dialog, !success);
1850
1851   if (success)
1852     {
1853       GtkTreeSelection *selection;
1854       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
1855
1856       selected_printer_changed (selection, dialog);
1857     }
1858 }
1859
1860 static void
1861 selected_printer_changed (GtkTreeSelection   *selection,
1862                           GtkPrintUnixDialog *dialog)
1863 {
1864   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1865   GtkPrinter *printer;
1866   GtkTreeIter iter, filter_iter;
1867
1868   /* Whenever the user selects a printer we stop looking for
1869    * the printer specified in the initial settings
1870    */
1871   if (priv->waiting_for_printer &&
1872       !priv->internal_printer_change)
1873     {
1874       g_free (priv->waiting_for_printer);
1875       priv->waiting_for_printer = NULL;
1876     }
1877
1878   disconnect_printer_details_request (dialog, FALSE);
1879
1880   printer = NULL;
1881   if (gtk_tree_selection_get_selected (selection, NULL, &filter_iter))
1882     {
1883       gtk_tree_model_filter_convert_iter_to_child_iter (priv->printer_list_filter,
1884                                                         &iter,
1885                                                         &filter_iter);
1886
1887       gtk_tree_model_get (priv->printer_list, &iter,
1888                           PRINTER_LIST_COL_PRINTER_OBJ, &printer,
1889                           -1);
1890     }
1891
1892   /* sets GTK_RESPONSE_OK button sensitivity depending on whether the printer
1893    * accepts/rejects jobs
1894    */
1895   if (printer != NULL)
1896     {
1897       if (!gtk_printer_is_accepting_jobs (printer))
1898         gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
1899       else if (priv->current_printer == printer && gtk_printer_has_details (printer))
1900
1901         gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
1902     }
1903
1904   if (printer != NULL && !gtk_printer_has_details (printer))
1905     {
1906       gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
1907       priv->request_details_tag =
1908         g_signal_connect (printer, "details-acquired",
1909                           G_CALLBACK (printer_details_acquired), dialog);
1910       /* take the reference */
1911       priv->request_details_printer = printer;
1912       gtk_printer_request_details (printer);
1913       set_busy_cursor (dialog, TRUE);
1914       gtk_list_store_set (GTK_LIST_STORE (priv->printer_list),
1915                           g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter"),
1916                           PRINTER_LIST_COL_STATE, _("Getting printer information…"),
1917                           -1);
1918       return;
1919     }
1920
1921   if (printer == priv->current_printer)
1922     {
1923       if (printer)
1924         g_object_unref (printer);
1925       return;
1926     }
1927
1928   if (priv->options)
1929     {
1930       g_clear_object (&priv->options);
1931       clear_per_printer_ui (dialog);
1932     }
1933
1934   g_clear_object (&priv->current_printer);
1935   priv->printer_capabilities = 0;
1936
1937   if (printer != NULL && gtk_printer_is_accepting_jobs (printer))
1938     gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
1939   priv->current_printer = printer;
1940
1941   if (printer != NULL)
1942     {
1943       if (!priv->page_setup_set)
1944         {
1945           /* if no explicit page setup has been set, use the printer default */
1946           GtkPageSetup *page_setup;
1947
1948           page_setup = gtk_printer_get_default_page_size (printer);
1949
1950           if (!page_setup)
1951             page_setup = gtk_page_setup_new ();
1952
1953           if (page_setup && priv->page_setup)
1954             gtk_page_setup_set_orientation (page_setup, gtk_page_setup_get_orientation (priv->page_setup));
1955
1956           g_object_unref (priv->page_setup);
1957           priv->page_setup = page_setup;
1958         }
1959
1960       priv->printer_capabilities = gtk_printer_get_capabilities (printer);
1961       priv->options = _gtk_printer_get_options (printer,
1962                                                 priv->initial_settings,
1963                                                 priv->page_setup,
1964                                                 priv->manual_capabilities);
1965
1966       priv->options_changed_handler =
1967         g_signal_connect_swapped (priv->options, "changed", G_CALLBACK (options_changed_cb), dialog);
1968       schedule_idle_mark_conflicts (dialog);
1969     }
1970
1971   update_dialog_from_settings (dialog);
1972   update_dialog_from_capabilities (dialog);
1973
1974   priv->internal_page_setup_change = TRUE;
1975   update_paper_sizes (dialog);
1976   priv->internal_page_setup_change = FALSE;
1977
1978   g_object_notify ( G_OBJECT(dialog), "selected-printer");
1979 }
1980
1981 static void
1982 update_collate_icon (GtkToggleButton    *toggle_button,
1983                      GtkPrintUnixDialog *dialog)
1984 {
1985   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1986
1987   gtk_widget_queue_draw (priv->collate_image);
1988 }
1989
1990 static void
1991 paint_page (GtkWidget *widget,
1992             cairo_t   *cr,
1993             gfloat     scale,
1994             gint       x_offset,
1995             gint       y_offset,
1996             gchar     *text,
1997             gint       text_x)
1998 {
1999   GtkStyleContext *context;
2000   gint x, y, width, height;
2001   gint text_y, linewidth;
2002   GdkRGBA color;
2003
2004   x = x_offset * scale;
2005   y = y_offset * scale;
2006   width = 20 * scale;
2007   height = 26 * scale;
2008
2009   linewidth = 2;
2010   text_y = 21;
2011
2012   context = gtk_widget_get_style_context (widget);
2013
2014   gtk_style_context_save (context);
2015   gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
2016
2017   gtk_style_context_get_background_color (context, 0, &color);
2018   gdk_cairo_set_source_rgba (cr, &color);
2019   cairo_rectangle (cr, x, y, width, height);
2020   cairo_fill (cr);
2021
2022   gtk_style_context_get_color (context, 0, &color);
2023   gdk_cairo_set_source_rgba (cr, &color);
2024   cairo_set_line_width (cr, linewidth);
2025   cairo_rectangle (cr, x + linewidth/2.0, y + linewidth/2.0, width - linewidth, height - linewidth);
2026   cairo_stroke (cr);
2027
2028   cairo_select_font_face (cr, "Sans",
2029                           CAIRO_FONT_SLANT_NORMAL,
2030                           CAIRO_FONT_WEIGHT_NORMAL);
2031   cairo_set_font_size (cr, (gint)(9 * scale));
2032   cairo_move_to (cr, x + (gint)(text_x * scale), y + (gint)(text_y * scale));
2033   cairo_show_text (cr, text);
2034
2035   gtk_style_context_restore (context);
2036 }
2037
2038 static gboolean
2039 draw_collate_cb (GtkWidget          *widget,
2040                  cairo_t            *cr,
2041                  GtkPrintUnixDialog *dialog)
2042 {
2043   GtkSettings *settings;
2044   gint size;
2045   gfloat scale;
2046   gboolean collate, reverse, rtl;
2047   gint copies;
2048   gint text_x;
2049
2050   collate = dialog_get_collate (dialog);
2051   reverse = dialog_get_reverse (dialog);
2052   copies = dialog_get_n_copies (dialog);
2053
2054   rtl = (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_RTL);
2055
2056   settings = gtk_widget_get_settings (widget);
2057   gtk_icon_size_lookup_for_settings (settings,
2058                                      GTK_ICON_SIZE_DIALOG,
2059                                      &size,
2060                                      NULL);
2061   scale = size / 48.0;
2062   text_x = rtl ? 4 : 11;
2063
2064   if (copies == 1)
2065     {
2066       paint_page (widget, cr, scale, rtl ? 40: 15, 5, reverse ? "1" : "2", text_x);
2067       paint_page (widget, cr, scale, rtl ? 50: 5, 15, reverse ? "2" : "1", text_x);
2068     }
2069   else
2070     {
2071       paint_page (widget, cr, scale, rtl ? 40: 15, 5, collate == reverse ? "1" : "2", text_x);
2072       paint_page (widget, cr, scale, rtl ? 50: 5, 15, reverse ? "2" : "1", text_x);
2073
2074       paint_page (widget, cr, scale, rtl ? 5 : 50, 5, reverse ? "1" : "2", text_x);
2075       paint_page (widget, cr, scale, rtl ? 15 : 40, 15, collate == reverse ? "2" : "1", text_x);
2076     }
2077
2078   return TRUE;
2079 }
2080
2081 static void
2082 gtk_print_unix_dialog_style_updated (GtkWidget *widget)
2083 {
2084   GTK_WIDGET_CLASS (gtk_print_unix_dialog_parent_class)->style_updated (widget);
2085
2086   if (gtk_widget_has_screen (widget))
2087     {
2088       GtkPrintUnixDialog *dialog = (GtkPrintUnixDialog *)widget;
2089       GtkPrintUnixDialogPrivate *priv = dialog->priv;
2090       GtkSettings *settings;
2091       gint size;
2092       gfloat scale;
2093
2094       settings = gtk_widget_get_settings (widget);
2095       gtk_icon_size_lookup_for_settings (settings,
2096                                          GTK_ICON_SIZE_DIALOG,
2097                                          &size,
2098                                          NULL);
2099       scale = size / 48.0;
2100
2101       gtk_widget_set_size_request (priv->collate_image,
2102                                    (50 + 20) * scale,
2103                                    (15 + 26) * scale);
2104     }
2105 }
2106
2107 static void
2108 update_entry_sensitivity (GtkWidget *button,
2109                           GtkWidget *range)
2110 {
2111   gboolean active;
2112
2113   active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
2114
2115   gtk_widget_set_sensitive (range, active);
2116
2117   if (active)
2118     gtk_widget_grab_focus (range);
2119 }
2120
2121 static void
2122 emit_ok_response (GtkTreeView       *tree_view,
2123                   GtkTreePath       *path,
2124                   GtkTreeViewColumn *column,
2125                   gpointer          *user_data)
2126 {
2127   GtkPrintUnixDialog *print_dialog;
2128
2129   print_dialog = (GtkPrintUnixDialog *) user_data;
2130
2131   gtk_dialog_response (GTK_DIALOG (print_dialog), GTK_RESPONSE_OK);
2132 }
2133
2134 static void
2135 create_main_page (GtkPrintUnixDialog *dialog)
2136 {
2137   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2138   GtkWidget *main_vbox, *label, *vbox, *hbox;
2139   GtkWidget *scrolled, *treeview, *frame, *table;
2140   GtkWidget *entry, *spinbutton;
2141   GtkWidget *radio, *check, *image;
2142   GtkCellRenderer *renderer;
2143   GtkTreeViewColumn *column;
2144   GtkTreeSelection *selection;
2145   GtkWidget *custom_input;
2146   const gchar *range_tooltip;
2147
2148   main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 18);
2149   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
2150   gtk_widget_show (main_vbox);
2151
2152   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
2153   gtk_box_pack_start (GTK_BOX (main_vbox), vbox, TRUE, TRUE, 0);
2154   gtk_widget_show (vbox);
2155
2156   scrolled = gtk_scrolled_window_new (NULL, NULL);
2157   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
2158                                   GTK_POLICY_AUTOMATIC,
2159                                   GTK_POLICY_AUTOMATIC);
2160   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
2161                                        GTK_SHADOW_IN);
2162   gtk_widget_show (scrolled);
2163   gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
2164
2165   treeview = gtk_tree_view_new_with_model ((GtkTreeModel *) priv->printer_list_filter);
2166   priv->printer_treeview = treeview;
2167   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), TRUE);
2168   gtk_tree_view_set_search_column (GTK_TREE_VIEW (treeview), PRINTER_LIST_COL_NAME);
2169   gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
2170   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
2171   gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
2172   g_signal_connect (selection, "changed", G_CALLBACK (selected_printer_changed), dialog);
2173
2174   renderer = gtk_cell_renderer_pixbuf_new ();
2175   column = gtk_tree_view_column_new_with_attributes ("",
2176                                                      renderer,
2177                                                      "icon-name",
2178                                                      PRINTER_LIST_COL_ICON,
2179                                                      NULL);
2180   gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, NULL, NULL);
2181   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
2182
2183   renderer = gtk_cell_renderer_text_new ();
2184   column = gtk_tree_view_column_new_with_attributes (_("Printer"),
2185                                                      renderer,
2186                                                      "text",
2187                                                      PRINTER_LIST_COL_NAME,
2188                                                      NULL);
2189   gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, NULL, NULL);
2190   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
2191
2192   renderer = gtk_cell_renderer_text_new ();
2193   /* Translators: this is the header for the location column in the print dialog */
2194   column = gtk_tree_view_column_new_with_attributes (_("Location"),
2195                                                      renderer,
2196                                                      "text",
2197                                                      PRINTER_LIST_COL_LOCATION,
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   renderer = gtk_cell_renderer_text_new ();
2203   g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
2204   /* Translators: this is the header for the printer status column in the print dialog */
2205   column = gtk_tree_view_column_new_with_attributes (_("Status"),
2206                                                      renderer,
2207                                                      "text",
2208                                                      PRINTER_LIST_COL_STATE,
2209                                                      NULL);
2210   gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, NULL, NULL);
2211   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
2212
2213   g_signal_connect (GTK_TREE_VIEW (treeview), "row-activated", G_CALLBACK (emit_ok_response), dialog);
2214
2215   gtk_widget_show (treeview);
2216   gtk_container_add (GTK_CONTAINER (scrolled), treeview);
2217
2218   custom_input = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 18);
2219   gtk_widget_show (custom_input);
2220   gtk_box_pack_start (GTK_BOX (vbox), custom_input, FALSE, FALSE, 0);
2221   priv->extension_point = custom_input;
2222
2223   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 18);
2224   gtk_widget_show (hbox);
2225   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
2226
2227   table = gtk_grid_new ();
2228   priv->range_table = table;
2229   gtk_grid_set_row_spacing (GTK_GRID (table), 6);
2230   gtk_grid_set_column_spacing (GTK_GRID (table), 12);
2231   frame = wrap_in_frame (_("Range"), table);
2232   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
2233   gtk_widget_show (table);
2234
2235   radio = gtk_radio_button_new_with_mnemonic (NULL, _("_All Pages"));
2236   priv->all_pages_radio = radio;
2237   gtk_widget_show (radio);
2238   gtk_grid_attach (GTK_GRID (table), radio, 0, 0, 2, 1);
2239   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
2240                                               _("C_urrent Page"));
2241   if (priv->current_page == -1)
2242     gtk_widget_set_sensitive (radio, FALSE);
2243   priv->current_page_radio = radio;
2244   gtk_widget_show (radio);
2245   gtk_grid_attach (GTK_GRID (table), radio, 0, 1, 2, 1);
2246
2247   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
2248                                               _("Se_lection"));
2249
2250   gtk_widget_set_sensitive (radio, priv->has_selection);
2251   priv->selection_radio = radio;
2252   gtk_grid_attach (GTK_GRID (table), radio, 0, 2, 2, 1);
2253
2254   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)), _("Pag_es:"));
2255   range_tooltip = _("Specify one or more page ranges,\n e.g. 1-3,7,11");
2256   gtk_widget_set_tooltip_text (radio, range_tooltip);
2257
2258   priv->page_range_radio = radio;
2259   gtk_widget_show (radio);
2260   gtk_grid_attach (GTK_GRID (table), radio, 0, 3, 1, 1);
2261   entry = gtk_entry_new ();
2262   gtk_widget_set_tooltip_text (entry, range_tooltip);
2263   gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
2264   atk_object_set_name (gtk_widget_get_accessible (entry), _("Pages"));
2265   atk_object_set_description (gtk_widget_get_accessible (entry), range_tooltip);
2266   priv->page_range_entry = entry;
2267   gtk_widget_show (entry);
2268   gtk_grid_attach (GTK_GRID (table), entry, 1, 3, 1, 1);
2269   g_signal_connect (radio, "toggled", G_CALLBACK (update_entry_sensitivity), entry);
2270   update_entry_sensitivity (radio, entry);
2271
2272   table = gtk_grid_new ();
2273   gtk_grid_set_row_spacing (GTK_GRID (table), 6);
2274   gtk_grid_set_column_spacing (GTK_GRID (table), 12);
2275   frame = wrap_in_frame (_("Copies"), table);
2276   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
2277   gtk_widget_show (table);
2278
2279   /* FIXME chpe: too much space between Copies and spinbutton, put those 2 in a hbox and make it span 2 columns */
2280   label = gtk_label_new_with_mnemonic (_("Copie_s:"));
2281   gtk_widget_set_halign (label, GTK_ALIGN_START);
2282   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
2283   gtk_widget_show (label);
2284   gtk_grid_attach (GTK_GRID (table), label, 0, 0, 1, 1);
2285   spinbutton = gtk_spin_button_new_with_range (1.0, 100.0, 1.0);
2286   gtk_entry_set_activates_default (GTK_ENTRY (spinbutton), TRUE);
2287   priv->copies_spin = spinbutton;
2288   gtk_widget_show (spinbutton);
2289   gtk_grid_attach (GTK_GRID (table), spinbutton, 1, 0, 1, 1);
2290   gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
2291   g_signal_connect_swapped (spinbutton, "value-changed",
2292                             G_CALLBACK (update_dialog_from_capabilities), dialog);
2293   g_signal_connect_swapped (spinbutton, "changed",
2294                             G_CALLBACK (update_dialog_from_capabilities), dialog);
2295
2296   check = gtk_check_button_new_with_mnemonic (_("C_ollate"));
2297   priv->collate_check = check;
2298   g_signal_connect (check, "toggled", G_CALLBACK (update_collate_icon), dialog);
2299   gtk_widget_show (check);
2300   gtk_grid_attach (GTK_GRID (table), check, 0, 1, 1, 1);
2301
2302   check = gtk_check_button_new_with_mnemonic (_("_Reverse"));
2303   g_signal_connect (check, "toggled", G_CALLBACK (update_collate_icon), dialog);
2304   priv->reverse_check = check;
2305   gtk_widget_show (check);
2306   gtk_grid_attach (GTK_GRID (table), check, 0, 2, 1, 1);
2307
2308   image = gtk_drawing_area_new ();
2309   gtk_widget_set_has_window (image, FALSE);
2310
2311   priv->collate_image = image;
2312   gtk_widget_show (image);
2313   gtk_widget_set_size_request (image, 70, 90);
2314   gtk_grid_attach (GTK_GRID (table), image, 1, 1, 1, 2);
2315   g_signal_connect (image, "draw",
2316                     G_CALLBACK (draw_collate_cb), dialog);
2317
2318   label = gtk_label_new (_("General"));
2319   gtk_widget_show (label);
2320
2321   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), main_vbox, label);
2322 }
2323
2324 static gboolean
2325 is_range_separator (gchar c)
2326 {
2327   return (c == ',' || c == ';' || c == ':');
2328 }
2329
2330 static GtkPageRange *
2331 dialog_get_page_ranges (GtkPrintUnixDialog *dialog,
2332                         gint               *n_ranges_out)
2333 {
2334   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2335   gint i, n_ranges;
2336   const gchar *text, *p;
2337   gchar *next;
2338   GtkPageRange *ranges;
2339   gint start, end;
2340
2341   text = gtk_entry_get_text (GTK_ENTRY (priv->page_range_entry));
2342
2343   if (*text == 0)
2344     {
2345       *n_ranges_out = 0;
2346       return NULL;
2347     }
2348
2349   n_ranges = 1;
2350   p = text;
2351   while (*p)
2352     {
2353       if (is_range_separator (*p))
2354         n_ranges++;
2355       p++;
2356     }
2357
2358   ranges = g_new0 (GtkPageRange, n_ranges);
2359
2360   i = 0;
2361   p = text;
2362   while (*p)
2363     {
2364       while (isspace (*p)) p++;
2365
2366       if (*p == '-')
2367         {
2368           /* a half-open range like -2 */
2369           start = 1;
2370         }
2371       else
2372         {
2373           start = (int)strtol (p, &next, 10);
2374           if (start < 1)
2375             start = 1;
2376           p = next;
2377         }
2378
2379       end = start;
2380
2381       while (isspace (*p)) p++;
2382
2383       if (*p == '-')
2384         {
2385           p++;
2386           end = (int)strtol (p, &next, 10);
2387           if (next == p) /* a half-open range like 2- */
2388             end = 0;
2389           else if (end < start)
2390             end = start;
2391         }
2392
2393       ranges[i].start = start - 1;
2394       ranges[i].end = end - 1;
2395       i++;
2396
2397       /* Skip until end or separator */
2398       while (*p && !is_range_separator (*p))
2399         p++;
2400
2401       /* if not at end, skip separator */
2402       if (*p)
2403         p++;
2404     }
2405
2406   *n_ranges_out = i;
2407
2408   return ranges;
2409 }
2410
2411 static void
2412 dialog_set_page_ranges (GtkPrintUnixDialog *dialog,
2413                         GtkPageRange       *ranges,
2414                         gint                n_ranges)
2415 {
2416   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2417   gint i;
2418   GString *s = g_string_new (NULL);
2419
2420   for (i = 0; i < n_ranges; i++)
2421     {
2422       g_string_append_printf (s, "%d", ranges[i].start + 1);
2423       if (ranges[i].end > ranges[i].start)
2424         g_string_append_printf (s, "-%d", ranges[i].end + 1);
2425       else if (ranges[i].end == -1)
2426         g_string_append (s, "-");
2427
2428       if (i != n_ranges - 1)
2429         g_string_append (s, ",");
2430     }
2431
2432   gtk_entry_set_text (GTK_ENTRY (priv->page_range_entry), s->str);
2433
2434   g_string_free (s, TRUE);
2435 }
2436
2437 static GtkPrintPages
2438 dialog_get_print_pages (GtkPrintUnixDialog *dialog)
2439 {
2440   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2441
2442   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->all_pages_radio)))
2443     return GTK_PRINT_PAGES_ALL;
2444   else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->current_page_radio)))
2445     return GTK_PRINT_PAGES_CURRENT;
2446   else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->selection_radio)))
2447     return GTK_PRINT_PAGES_SELECTION;
2448   else
2449     return GTK_PRINT_PAGES_RANGES;
2450 }
2451
2452 static void
2453 dialog_set_print_pages (GtkPrintUnixDialog *dialog,
2454                         GtkPrintPages       pages)
2455 {
2456   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2457
2458   if (pages == GTK_PRINT_PAGES_RANGES)
2459     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->page_range_radio), TRUE);
2460   else if (pages == GTK_PRINT_PAGES_CURRENT)
2461     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->current_page_radio), TRUE);
2462   else if (pages == GTK_PRINT_PAGES_SELECTION)
2463     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->selection_radio), TRUE);
2464   else
2465     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->all_pages_radio), TRUE);
2466 }
2467
2468 static gdouble
2469 dialog_get_scale (GtkPrintUnixDialog *dialog)
2470 {
2471   if (gtk_widget_is_sensitive (dialog->priv->scale_spin))
2472     return gtk_spin_button_get_value (GTK_SPIN_BUTTON (dialog->priv->scale_spin));
2473   else
2474     return 100.0;
2475 }
2476
2477 static void
2478 dialog_set_scale (GtkPrintUnixDialog *dialog,
2479                   gdouble             val)
2480 {
2481   gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->scale_spin), val);
2482 }
2483
2484 static GtkPageSet
2485 dialog_get_page_set (GtkPrintUnixDialog *dialog)
2486 {
2487   if (gtk_widget_is_sensitive (dialog->priv->page_set_combo))
2488     return (GtkPageSet)gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->page_set_combo));
2489   else
2490     return GTK_PAGE_SET_ALL;
2491 }
2492
2493 static void
2494 dialog_set_page_set (GtkPrintUnixDialog *dialog,
2495                      GtkPageSet          val)
2496 {
2497   gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->priv->page_set_combo),
2498                             (int)val);
2499 }
2500
2501 static gint
2502 dialog_get_n_copies (GtkPrintUnixDialog *dialog)
2503 {
2504   if (gtk_widget_is_sensitive (dialog->priv->copies_spin))
2505     return gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->priv->copies_spin));
2506   return 1;
2507 }
2508
2509 static void
2510 dialog_set_n_copies (GtkPrintUnixDialog *dialog,
2511                      gint                n_copies)
2512 {
2513   gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->copies_spin),
2514                              n_copies);
2515 }
2516
2517 static gboolean
2518 dialog_get_collate (GtkPrintUnixDialog *dialog)
2519 {
2520   if (gtk_widget_is_sensitive (dialog->priv->collate_check))
2521     return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->collate_check));
2522   return FALSE;
2523 }
2524
2525 static void
2526 dialog_set_collate (GtkPrintUnixDialog *dialog,
2527                     gboolean            collate)
2528 {
2529   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->collate_check),
2530                                 collate);
2531 }
2532
2533 static gboolean
2534 dialog_get_reverse (GtkPrintUnixDialog *dialog)
2535 {
2536   if (gtk_widget_is_sensitive (dialog->priv->reverse_check))
2537     return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->reverse_check));
2538   return FALSE;
2539 }
2540
2541 static void
2542 dialog_set_reverse (GtkPrintUnixDialog *dialog,
2543                     gboolean            reverse)
2544 {
2545   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->reverse_check),
2546                                 reverse);
2547 }
2548
2549 static gint
2550 dialog_get_pages_per_sheet (GtkPrintUnixDialog *dialog)
2551 {
2552   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2553   const gchar *val;
2554   gint num;
2555
2556   val = gtk_printer_option_widget_get_value (priv->pages_per_sheet);
2557
2558   num = 1;
2559
2560   if (val)
2561     {
2562       num = atoi(val);
2563       if (num < 1)
2564         num = 1;
2565     }
2566
2567   return num;
2568 }
2569
2570 static GtkNumberUpLayout
2571 dialog_get_number_up_layout (GtkPrintUnixDialog *dialog)
2572 {
2573   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2574   GtkPrintCapabilities       caps;
2575   GtkNumberUpLayout          layout;
2576   const gchar               *val;
2577   GEnumClass                *enum_class;
2578   GEnumValue                *enum_value;
2579
2580   val = gtk_printer_option_widget_get_value (priv->number_up_layout);
2581
2582   caps = priv->manual_capabilities | priv->printer_capabilities;
2583
2584   if ((caps & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT) == 0)
2585     return GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
2586
2587   if (gtk_widget_get_direction (GTK_WIDGET (dialog)) == GTK_TEXT_DIR_LTR)
2588     layout = GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
2589   else
2590     layout = GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM;
2591
2592   if (val == NULL)
2593     return layout;
2594
2595   if (val[0] == '\0' && priv->options)
2596     {
2597       GtkPrinterOption *option = gtk_printer_option_set_lookup (priv->options, "gtk-n-up-layout");
2598       if (option)
2599         val = option->value;
2600     }
2601
2602   enum_class = g_type_class_ref (GTK_TYPE_NUMBER_UP_LAYOUT);
2603   enum_value = g_enum_get_value_by_nick (enum_class, val);
2604   if (enum_value)
2605     layout = enum_value->value;
2606   g_type_class_unref (enum_class);
2607
2608   return layout;
2609 }
2610
2611 static gboolean
2612 draw_page_cb (GtkWidget          *widget,
2613               cairo_t            *cr,
2614               GtkPrintUnixDialog *dialog)
2615 {
2616   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2617   GtkStyleContext *context;
2618   gdouble ratio;
2619   gint w, h, tmp, shadow_offset;
2620   gint pages_x, pages_y, i, x, y, layout_w, layout_h;
2621   gdouble page_width, page_height;
2622   GtkPageOrientation orientation;
2623   gboolean landscape;
2624   PangoLayout *layout;
2625   PangoFontDescription *font;
2626   gchar *text;
2627   GdkRGBA color;
2628   GtkNumberUpLayout number_up_layout;
2629   gint start_x, end_x, start_y, end_y;
2630   gint dx, dy;
2631   gint width, height;
2632   gboolean horizontal;
2633   GtkPageSetup *page_setup;
2634   gdouble paper_width, paper_height;
2635   gdouble pos_x, pos_y;
2636   gint pages_per_sheet;
2637   gboolean ltr = TRUE;
2638
2639   orientation = gtk_page_setup_get_orientation (priv->page_setup);
2640   landscape =
2641     (orientation == GTK_PAGE_ORIENTATION_LANDSCAPE) ||
2642     (orientation == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE);
2643
2644   number_up_layout = dialog_get_number_up_layout (dialog);
2645   width = gtk_widget_get_allocated_width (widget);
2646   height = gtk_widget_get_allocated_height (widget);
2647
2648   cairo_save (cr);
2649
2650   page_setup = gtk_print_unix_dialog_get_page_setup (dialog);
2651
2652   if (page_setup != NULL)
2653     {
2654       if (!landscape)
2655         {
2656           paper_width = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM);
2657           paper_height = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM);
2658         }
2659       else
2660         {
2661           paper_width = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM);
2662           paper_height = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM);
2663         }
2664
2665       if (paper_width < paper_height)
2666         {
2667           h = EXAMPLE_PAGE_AREA_SIZE - 3;
2668           w = (paper_height != 0) ? h * paper_width / paper_height : 0;
2669         }
2670       else
2671         {
2672           w = EXAMPLE_PAGE_AREA_SIZE - 3;
2673           h = (paper_width != 0) ? w * paper_height / paper_width : 0;
2674         }
2675
2676       if (paper_width == 0)
2677         w = 0;
2678
2679       if (paper_height == 0)
2680         h = 0;
2681     }
2682   else
2683     {
2684       ratio = G_SQRT2;
2685       w = (EXAMPLE_PAGE_AREA_SIZE - 3) / ratio;
2686       h = EXAMPLE_PAGE_AREA_SIZE - 3;
2687     }
2688
2689   pages_per_sheet = dialog_get_pages_per_sheet (dialog);
2690   switch (pages_per_sheet)
2691     {
2692     default:
2693     case 1:
2694       pages_x = 1; pages_y = 1;
2695       break;
2696     case 2:
2697       landscape = !landscape;
2698       pages_x = 1; pages_y = 2;
2699       break;
2700     case 4:
2701       pages_x = 2; pages_y = 2;
2702       break;
2703     case 6:
2704       landscape = !landscape;
2705       pages_x = 2; pages_y = 3;
2706       break;
2707     case 9:
2708       pages_x = 3; pages_y = 3;
2709       break;
2710     case 16:
2711       pages_x = 4; pages_y = 4;
2712       break;
2713     }
2714
2715   if (landscape)
2716     {
2717       tmp = w;
2718       w = h;
2719       h = tmp;
2720
2721       tmp = pages_x;
2722       pages_x = pages_y;
2723       pages_y = tmp;
2724     }
2725
2726   context = gtk_widget_get_style_context (widget);
2727
2728   gtk_style_context_save (context);
2729   gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
2730
2731   pos_x = (width - w) / 2;
2732   pos_y = (height - h) / 2 - 10;
2733   cairo_translate (cr, pos_x, pos_y);
2734
2735   shadow_offset = 3;
2736
2737   gtk_style_context_get_color (context, 0, &color);
2738   cairo_set_source_rgba (cr, color.red, color.green, color.blue, 0.5);
2739   cairo_rectangle (cr, shadow_offset + 1, shadow_offset + 1, w, h);
2740   cairo_fill (cr);
2741
2742   gtk_style_context_get_background_color (context, 0, &color);
2743   gdk_cairo_set_source_rgba (cr, &color);
2744   cairo_rectangle (cr, 1, 1, w, h);
2745   cairo_fill (cr);
2746   cairo_set_line_width (cr, 1.0);
2747   cairo_rectangle (cr, 0.5, 0.5, w + 1, h + 1);
2748
2749   gtk_style_context_get_color (context, 0, &color);
2750   gdk_cairo_set_source_rgba (cr, &color);
2751   cairo_stroke (cr);
2752
2753   i = 1;
2754
2755   page_width = (gdouble)w / pages_x;
2756   page_height = (gdouble)h / pages_y;
2757
2758   layout  = pango_cairo_create_layout (cr);
2759
2760   font = pango_font_description_new ();
2761   pango_font_description_set_family (font, "sans");
2762
2763   if (page_height > 0)
2764     pango_font_description_set_absolute_size (font, page_height * 0.4 * PANGO_SCALE);
2765   else
2766     pango_font_description_set_absolute_size (font, 1);
2767
2768   pango_layout_set_font_description (layout, font);
2769   pango_font_description_free (font);
2770
2771   pango_layout_set_width (layout, page_width * PANGO_SCALE);
2772   pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
2773
2774   switch (number_up_layout)
2775     {
2776       default:
2777       case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM:
2778         start_x = 0;
2779         end_x = pages_x - 1;
2780         start_y = 0;
2781         end_y = pages_y - 1;
2782         dx = 1;
2783         dy = 1;
2784         horizontal = TRUE;
2785         break;
2786       case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP:
2787         start_x = 0;
2788         end_x = pages_x - 1;
2789         start_y = pages_y - 1;
2790         end_y = 0;
2791         dx = 1;
2792         dy = - 1;
2793         horizontal = TRUE;
2794         break;
2795       case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM:
2796         start_x = pages_x - 1;
2797         end_x = 0;
2798         start_y = 0;
2799         end_y = pages_y - 1;
2800         dx = - 1;
2801         dy = 1;
2802         horizontal = TRUE;
2803         break;
2804       case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP:
2805         start_x = pages_x - 1;
2806         end_x = 0;
2807         start_y = pages_y - 1;
2808         end_y = 0;
2809         dx = - 1;
2810         dy = - 1;
2811         horizontal = TRUE;
2812         break;
2813       case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT:
2814         start_x = 0;
2815         end_x = pages_x - 1;
2816         start_y = 0;
2817         end_y = pages_y - 1;
2818         dx = 1;
2819         dy = 1;
2820         horizontal = FALSE;
2821         break;
2822       case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_RIGHT_TO_LEFT:
2823         start_x = pages_x - 1;
2824         end_x = 0;
2825         start_y = 0;
2826         end_y = pages_y - 1;
2827         dx = - 1;
2828         dy = 1;
2829         horizontal = FALSE;
2830         break;
2831       case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT:
2832         start_x = 0;
2833         end_x = pages_x - 1;
2834         start_y = pages_y - 1;
2835         end_y = 0;
2836         dx = 1;
2837         dy = - 1;
2838         horizontal = FALSE;
2839         break;
2840       case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_RIGHT_TO_LEFT:
2841         start_x = pages_x - 1;
2842         end_x = 0;
2843         start_y = pages_y - 1;
2844         end_y = 0;
2845         dx = - 1;
2846         dy = - 1;
2847         horizontal = FALSE;
2848         break;
2849     }
2850
2851   if (horizontal)
2852     for (y = start_y; y != end_y + dy; y += dy)
2853       {
2854         for (x = start_x; x != end_x + dx; x += dx)
2855           {
2856             text = g_strdup_printf ("%d", i++);
2857             pango_layout_set_text (layout, text, -1);
2858             g_free (text);
2859             pango_layout_get_size (layout, &layout_w, &layout_h);
2860             cairo_save (cr);
2861             cairo_translate (cr,
2862                              x * page_width,
2863                              y * page_height + (page_height - layout_h / 1024.0) / 2);
2864
2865             pango_cairo_show_layout (cr, layout);
2866             cairo_restore (cr);
2867           }
2868       }
2869   else
2870     for (x = start_x; x != end_x + dx; x += dx)
2871       {
2872         for (y = start_y; y != end_y + dy; y += dy)
2873           {
2874             text = g_strdup_printf ("%d", i++);
2875             pango_layout_set_text (layout, text, -1);
2876             g_free (text);
2877             pango_layout_get_size (layout, &layout_w, &layout_h);
2878             cairo_save (cr);
2879             cairo_translate (cr,
2880                              x * page_width,
2881                              y * page_height + (page_height - layout_h / 1024.0) / 2);
2882
2883             pango_cairo_show_layout (cr, layout);
2884             cairo_restore (cr);
2885           }
2886       }
2887
2888   g_object_unref (layout);
2889
2890   if (page_setup != NULL)
2891     {
2892       pos_x += 1;
2893       pos_y += 1;
2894
2895       if (pages_per_sheet == 2 || pages_per_sheet == 6)
2896         {
2897           paper_width = gtk_page_setup_get_paper_height (page_setup, _gtk_print_get_default_user_units ());
2898           paper_height = gtk_page_setup_get_paper_width (page_setup, _gtk_print_get_default_user_units ());
2899         }
2900       else
2901         {
2902           paper_width = gtk_page_setup_get_paper_width (page_setup, _gtk_print_get_default_user_units ());
2903           paper_height = gtk_page_setup_get_paper_height (page_setup, _gtk_print_get_default_user_units ());
2904         }
2905
2906       cairo_restore (cr);
2907       cairo_save (cr);
2908
2909       layout  = pango_cairo_create_layout (cr);
2910
2911       font = pango_font_description_new ();
2912       pango_font_description_set_family (font, "sans");
2913
2914       PangoContext *pango_c = NULL;
2915       PangoFontDescription *pango_f = NULL;
2916       gint font_size = 12 * PANGO_SCALE;
2917
2918       pango_c = gtk_widget_get_pango_context (widget);
2919       if (pango_c != NULL)
2920         {
2921           pango_f = pango_context_get_font_description (pango_c);
2922           if (pango_f != NULL)
2923             font_size = pango_font_description_get_size (pango_f);
2924         }
2925
2926       pango_font_description_set_size (font, font_size);
2927       pango_layout_set_font_description (layout, font);
2928       pango_font_description_free (font);
2929
2930       pango_layout_set_width (layout, -1);
2931       pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
2932
2933       if (_gtk_print_get_default_user_units () == GTK_UNIT_MM)
2934         text = g_strdup_printf ("%.1f mm", paper_height);
2935       else
2936         text = g_strdup_printf ("%.2f inch", paper_height);
2937
2938       pango_layout_set_text (layout, text, -1);
2939       g_free (text);
2940       pango_layout_get_size (layout, &layout_w, &layout_h);
2941
2942       ltr = gtk_widget_get_direction (GTK_WIDGET (dialog)) == GTK_TEXT_DIR_LTR;
2943
2944       if (ltr)
2945         cairo_translate (cr, pos_x - layout_w / PANGO_SCALE - 2 * RULER_DISTANCE,
2946                              (height - layout_h / PANGO_SCALE) / 2);
2947       else
2948         cairo_translate (cr, pos_x + w + shadow_offset + 2 * RULER_DISTANCE,
2949                              (height - layout_h / PANGO_SCALE) / 2);
2950
2951       pango_cairo_show_layout (cr, layout);
2952
2953       cairo_restore (cr);
2954       cairo_save (cr);
2955
2956       if (_gtk_print_get_default_user_units () == GTK_UNIT_MM)
2957         text = g_strdup_printf ("%.1f mm", paper_width);
2958       else
2959         text = g_strdup_printf ("%.2f inch", paper_width);
2960
2961       pango_layout_set_text (layout, text, -1);
2962       g_free (text);
2963       pango_layout_get_size (layout, &layout_w, &layout_h);
2964
2965       cairo_translate (cr, (width - layout_w / PANGO_SCALE) / 2,
2966                            pos_y + h + shadow_offset + 2 * RULER_DISTANCE);
2967
2968       pango_cairo_show_layout (cr, layout);
2969
2970       g_object_unref (layout);
2971
2972       cairo_restore (cr);
2973
2974       cairo_set_line_width (cr, 1);
2975
2976       if (ltr)
2977         {
2978           cairo_move_to (cr, pos_x - RULER_DISTANCE, pos_y);
2979           cairo_line_to (cr, pos_x - RULER_DISTANCE, pos_y + h);
2980           cairo_stroke (cr);
2981
2982           cairo_move_to (cr, pos_x - RULER_DISTANCE - RULER_RADIUS, pos_y - 0.5);
2983           cairo_line_to (cr, pos_x - RULER_DISTANCE + RULER_RADIUS, pos_y - 0.5);
2984           cairo_stroke (cr);
2985
2986           cairo_move_to (cr, pos_x - RULER_DISTANCE - RULER_RADIUS, pos_y + h + 0.5);
2987           cairo_line_to (cr, pos_x - RULER_DISTANCE + RULER_RADIUS, pos_y + h + 0.5);
2988           cairo_stroke (cr);
2989         }
2990       else
2991         {
2992           cairo_move_to (cr, pos_x + w + shadow_offset + RULER_DISTANCE, pos_y);
2993           cairo_line_to (cr, pos_x + w + shadow_offset + RULER_DISTANCE, pos_y + h);
2994           cairo_stroke (cr);
2995
2996           cairo_move_to (cr, pos_x + w + shadow_offset + RULER_DISTANCE - RULER_RADIUS, pos_y - 0.5);
2997           cairo_line_to (cr, pos_x + w + shadow_offset + RULER_DISTANCE + RULER_RADIUS, pos_y - 0.5);
2998           cairo_stroke (cr);
2999
3000           cairo_move_to (cr, pos_x + w + shadow_offset + RULER_DISTANCE - RULER_RADIUS, pos_y + h + 0.5);
3001           cairo_line_to (cr, pos_x + w + shadow_offset + RULER_DISTANCE + RULER_RADIUS, pos_y + h + 0.5);
3002           cairo_stroke (cr);
3003         }
3004
3005       cairo_move_to (cr, pos_x, pos_y + h + shadow_offset + RULER_DISTANCE);
3006       cairo_line_to (cr, pos_x + w, pos_y + h + shadow_offset + RULER_DISTANCE);
3007       cairo_stroke (cr);
3008
3009       cairo_move_to (cr, pos_x - 0.5, pos_y + h + shadow_offset + RULER_DISTANCE - RULER_RADIUS);
3010       cairo_line_to (cr, pos_x - 0.5, pos_y + h + shadow_offset + RULER_DISTANCE + RULER_RADIUS);
3011       cairo_stroke (cr);
3012
3013       cairo_move_to (cr, pos_x + w + 0.5, pos_y + h + shadow_offset + RULER_DISTANCE - RULER_RADIUS);
3014       cairo_line_to (cr, pos_x + w + 0.5, pos_y + h + shadow_offset + RULER_DISTANCE + RULER_RADIUS);
3015       cairo_stroke (cr);
3016     }
3017
3018   gtk_style_context_restore (context);
3019
3020   return TRUE;
3021 }
3022
3023 static void
3024 redraw_page_layout_preview (GtkPrintUnixDialog *dialog)
3025 {
3026   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3027
3028   if (priv->page_layout_preview)
3029     gtk_widget_queue_draw (priv->page_layout_preview);
3030 }
3031
3032 static void
3033 update_number_up_layout (GtkPrintUnixDialog *dialog)
3034 {
3035   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3036   GtkPrintCapabilities       caps;
3037   GtkPrinterOptionSet       *set;
3038   GtkNumberUpLayout          layout;
3039   GtkPrinterOption          *option;
3040   GtkPrinterOption          *old_option;
3041   GtkPageOrientation         page_orientation;
3042
3043   set = priv->options;
3044
3045   caps = priv->manual_capabilities | priv->printer_capabilities;
3046
3047   if (caps & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT)
3048     {
3049       if (priv->number_up_layout_n_option == NULL)
3050         {
3051           priv->number_up_layout_n_option = gtk_printer_option_set_lookup (set, "gtk-n-up-layout");
3052           if (priv->number_up_layout_n_option == NULL)
3053             {
3054               char *n_up_layout[] = { "lrtb", "lrbt", "rltb", "rlbt", "tblr", "tbrl", "btlr", "btrl" };
3055                /* Translators: These strings name the possible arrangements of
3056                 * multiple pages on a sheet when printing (same as in gtkprintbackendcups.c)
3057                 */
3058               char *n_up_layout_display[] = { N_("Left to right, top to bottom"), N_("Left to right, bottom to top"),
3059                                               N_("Right to left, top to bottom"), N_("Right to left, bottom to top"),
3060                                               N_("Top to bottom, left to right"), N_("Top to bottom, right to left"),
3061                                               N_("Bottom to top, left to right"), N_("Bottom to top, right to left") };
3062               int i;
3063
3064               priv->number_up_layout_n_option = gtk_printer_option_new ("gtk-n-up-layout",
3065                                                                         _("Page Ordering"),
3066                                                                         GTK_PRINTER_OPTION_TYPE_PICKONE);
3067               gtk_printer_option_allocate_choices (priv->number_up_layout_n_option, 8);
3068
3069               for (i = 0; i < G_N_ELEMENTS (n_up_layout_display); i++)
3070                 {
3071                   priv->number_up_layout_n_option->choices[i] = g_strdup (n_up_layout[i]);
3072                   priv->number_up_layout_n_option->choices_display[i] = g_strdup (_(n_up_layout_display[i]));
3073                 }
3074             }
3075           g_object_ref (priv->number_up_layout_n_option);
3076
3077           priv->number_up_layout_2_option = gtk_printer_option_new ("gtk-n-up-layout",
3078                                                                     _("Page Ordering"),
3079                                                                     GTK_PRINTER_OPTION_TYPE_PICKONE);
3080           gtk_printer_option_allocate_choices (priv->number_up_layout_2_option, 2);
3081         }
3082
3083       page_orientation = gtk_page_setup_get_orientation (priv->page_setup);
3084       if (page_orientation == GTK_PAGE_ORIENTATION_PORTRAIT ||
3085           page_orientation == GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT)
3086         {
3087           if (! (priv->number_up_layout_2_option->choices[0] == priv->number_up_layout_n_option->choices[0] &&
3088                  priv->number_up_layout_2_option->choices[1] == priv->number_up_layout_n_option->choices[2]))
3089             {
3090               g_free (priv->number_up_layout_2_option->choices_display[0]);
3091               g_free (priv->number_up_layout_2_option->choices_display[1]);
3092               priv->number_up_layout_2_option->choices[0] = priv->number_up_layout_n_option->choices[0];
3093               priv->number_up_layout_2_option->choices[1] = priv->number_up_layout_n_option->choices[2];
3094               priv->number_up_layout_2_option->choices_display[0] = g_strdup ( _("Left to right"));
3095               priv->number_up_layout_2_option->choices_display[1] = g_strdup ( _("Right to left"));
3096             }
3097         }
3098       else
3099         {
3100           if (! (priv->number_up_layout_2_option->choices[0] == priv->number_up_layout_n_option->choices[0] &&
3101                  priv->number_up_layout_2_option->choices[1] == priv->number_up_layout_n_option->choices[1]))
3102             {
3103               g_free (priv->number_up_layout_2_option->choices_display[0]);
3104               g_free (priv->number_up_layout_2_option->choices_display[1]);
3105               priv->number_up_layout_2_option->choices[0] = priv->number_up_layout_n_option->choices[0];
3106               priv->number_up_layout_2_option->choices[1] = priv->number_up_layout_n_option->choices[1];
3107               priv->number_up_layout_2_option->choices_display[0] = g_strdup ( _("Top to bottom"));
3108               priv->number_up_layout_2_option->choices_display[1] = g_strdup ( _("Bottom to top"));
3109             }
3110         }
3111
3112       layout = dialog_get_number_up_layout (dialog);
3113
3114       old_option = gtk_printer_option_set_lookup (set, "gtk-n-up-layout");
3115       if (old_option != NULL)
3116         gtk_printer_option_set_remove (set, old_option);
3117
3118       if (dialog_get_pages_per_sheet (dialog) != 1)
3119         {
3120           GEnumClass *enum_class;
3121           GEnumValue *enum_value;
3122           enum_class = g_type_class_ref (GTK_TYPE_NUMBER_UP_LAYOUT);
3123
3124           if (dialog_get_pages_per_sheet (dialog) == 2)
3125             {
3126               option = priv->number_up_layout_2_option;
3127
3128               switch (layout)
3129                 {
3130                 case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM:
3131                 case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT:
3132                   enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM);
3133                   break;
3134
3135                 case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP:
3136                 case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT:
3137                   enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP);
3138                   break;
3139
3140                 case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM:
3141                 case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_RIGHT_TO_LEFT:
3142                   enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM);
3143                   break;
3144
3145                 case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP:
3146                 case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_RIGHT_TO_LEFT:
3147                   enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP);
3148                   break;
3149
3150                 default:
3151                   g_assert_not_reached();
3152                   enum_value = NULL;
3153                 }
3154             }
3155           else
3156             {
3157               option = priv->number_up_layout_n_option;
3158
3159               enum_value = g_enum_get_value (enum_class, layout);
3160             }
3161
3162           g_assert (enum_value != NULL);
3163           gtk_printer_option_set (option, enum_value->value_nick);
3164           g_type_class_unref (enum_class);
3165
3166           gtk_printer_option_set_add (set, option);
3167         }
3168     }
3169
3170   setup_option (dialog, "gtk-n-up-layout", priv->number_up_layout);
3171
3172   if (priv->number_up_layout != NULL)
3173     gtk_widget_set_sensitive (GTK_WIDGET (priv->number_up_layout),
3174                               (caps & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT) &&
3175                               (dialog_get_pages_per_sheet (dialog) > 1));
3176 }
3177
3178 static void
3179 custom_paper_dialog_response_cb (GtkDialog *custom_paper_dialog,
3180                                  gint       response_id,
3181                                  gpointer   user_data)
3182 {
3183   GtkPrintUnixDialog        *print_dialog = GTK_PRINT_UNIX_DIALOG (user_data);
3184   GtkPrintUnixDialogPrivate *priv = print_dialog->priv;
3185   GtkTreeModel              *model;
3186   GtkTreeIter                iter;
3187
3188   _gtk_print_load_custom_papers (priv->custom_paper_list);
3189
3190   priv->internal_page_setup_change = TRUE;
3191   update_paper_sizes (print_dialog);
3192   priv->internal_page_setup_change = FALSE;
3193
3194   if (priv->page_setup_set)
3195     {
3196       model = GTK_TREE_MODEL (priv->custom_paper_list);
3197       if (gtk_tree_model_get_iter_first (model, &iter))
3198         {
3199           do
3200             {
3201               GtkPageSetup *page_setup;
3202               gtk_tree_model_get (model, &iter, 0, &page_setup, -1);
3203
3204               if (page_setup &&
3205                   g_strcmp0 (gtk_paper_size_get_display_name (gtk_page_setup_get_paper_size (page_setup)),
3206                              gtk_paper_size_get_display_name (gtk_page_setup_get_paper_size (priv->page_setup))) == 0)
3207                 gtk_print_unix_dialog_set_page_setup (print_dialog, page_setup);
3208
3209               g_object_unref (page_setup);
3210             } while (gtk_tree_model_iter_next (model, &iter));
3211         }
3212     }
3213
3214   gtk_widget_destroy (GTK_WIDGET (custom_paper_dialog));
3215 }
3216
3217 static void
3218 orientation_changed (GtkComboBox        *combo_box,
3219                      GtkPrintUnixDialog *dialog)
3220 {
3221   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3222   GtkPageOrientation         orientation;
3223   GtkPageSetup              *page_setup;
3224
3225   if (priv->internal_page_setup_change)
3226     return;
3227
3228   orientation = (GtkPageOrientation) gtk_combo_box_get_active (GTK_COMBO_BOX (priv->orientation_combo));
3229
3230   if (priv->page_setup)
3231     {
3232       page_setup = gtk_page_setup_copy (priv->page_setup);
3233       if (page_setup)
3234         gtk_page_setup_set_orientation (page_setup, orientation);
3235
3236       gtk_print_unix_dialog_set_page_setup (dialog, page_setup);
3237     }
3238
3239   redraw_page_layout_preview (dialog);
3240 }
3241
3242 static void
3243 paper_size_changed (GtkComboBox        *combo_box,
3244                     GtkPrintUnixDialog *dialog)
3245 {
3246   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3247   GtkTreeIter iter;
3248   GtkPageSetup *page_setup, *last_page_setup;
3249   GtkPageOrientation orientation;
3250
3251   if (priv->internal_page_setup_change)
3252     return;
3253
3254   if (gtk_combo_box_get_active_iter (combo_box, &iter))
3255     {
3256       gtk_tree_model_get (gtk_combo_box_get_model (combo_box),
3257                           &iter, PAGE_SETUP_LIST_COL_PAGE_SETUP, &page_setup,
3258                           -1);
3259
3260       if (page_setup == NULL)
3261         {
3262           GtkWidget *custom_paper_dialog;
3263
3264           /* Change from "manage" menu item to last value */
3265           if (priv->page_setup)
3266             last_page_setup = g_object_ref (priv->page_setup);
3267           else
3268             last_page_setup = gtk_page_setup_new (); /* "good" default */
3269
3270           if (!set_paper_size (dialog, last_page_setup, FALSE, FALSE))
3271             set_paper_size (dialog, last_page_setup, TRUE, TRUE);
3272           g_object_unref (last_page_setup);
3273
3274           /* And show the custom paper dialog */
3275           custom_paper_dialog = _gtk_custom_paper_unix_dialog_new (GTK_WINDOW (dialog), _("Manage Custom Sizes"));
3276           g_signal_connect (custom_paper_dialog, "response", G_CALLBACK (custom_paper_dialog_response_cb), dialog);
3277           gtk_window_present (GTK_WINDOW (custom_paper_dialog));
3278
3279           return;
3280         }
3281
3282       if (priv->page_setup)
3283         orientation = gtk_page_setup_get_orientation (priv->page_setup);
3284       else
3285         orientation = GTK_PAGE_ORIENTATION_PORTRAIT;
3286
3287       gtk_page_setup_set_orientation (page_setup, orientation);
3288       gtk_print_unix_dialog_set_page_setup (dialog, page_setup);
3289
3290       g_object_unref (page_setup);
3291     }
3292
3293   redraw_page_layout_preview (dialog);
3294 }
3295
3296 static gboolean
3297 paper_size_row_is_separator (GtkTreeModel *model,
3298                              GtkTreeIter  *iter,
3299                              gpointer      data)
3300 {
3301   gboolean separator;
3302
3303   gtk_tree_model_get (model, iter,
3304                       PAGE_SETUP_LIST_COL_IS_SEPARATOR, &separator,
3305                       -1);
3306   return separator;
3307 }
3308
3309 static void
3310 page_name_func (GtkCellLayout   *cell_layout,
3311                 GtkCellRenderer *cell,
3312                 GtkTreeModel    *tree_model,
3313                 GtkTreeIter     *iter,
3314                 gpointer         data)
3315 {
3316   GtkPageSetup *page_setup;
3317   GtkPaperSize *paper_size;
3318
3319   gtk_tree_model_get (tree_model, iter,
3320                       PAGE_SETUP_LIST_COL_PAGE_SETUP, &page_setup,
3321                       -1);
3322   if (page_setup)
3323     {
3324       paper_size = gtk_page_setup_get_paper_size (page_setup);
3325       g_object_set (cell, "text",  gtk_paper_size_get_display_name (paper_size), NULL);
3326       g_object_unref (page_setup);
3327     }
3328   else
3329     g_object_set (cell, "text",  _("Manage Custom Sizes…"), NULL);
3330 }
3331
3332 static void
3333 create_page_setup_page (GtkPrintUnixDialog *dialog)
3334 {
3335   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3336   GtkWidget *main_vbox, *label, *hbox, *hbox2;
3337   GtkWidget *frame, *table, *widget;
3338   GtkWidget *combo, *spinbutton, *draw;
3339   GtkCellRenderer *cell;
3340
3341   main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 18);
3342   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
3343   gtk_widget_show (main_vbox);
3344
3345   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 18);
3346   gtk_widget_show (hbox);
3347   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
3348
3349   table = gtk_grid_new ();
3350   gtk_grid_set_row_spacing (GTK_GRID (table), 6);
3351   gtk_grid_set_column_spacing (GTK_GRID (table), 12);
3352   frame = wrap_in_frame (_("Layout"), table);
3353   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
3354   gtk_widget_show (table);
3355
3356   label = gtk_label_new_with_mnemonic (_("T_wo-sided:"));
3357   gtk_widget_set_halign (label, GTK_ALIGN_START);
3358   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3359   gtk_widget_show (label);
3360   gtk_grid_attach (GTK_GRID (table), label, 0, 0, 1, 1);
3361
3362   widget = gtk_printer_option_widget_new (NULL);
3363   priv->duplex = GTK_PRINTER_OPTION_WIDGET (widget);
3364   gtk_widget_show (widget);
3365   gtk_grid_attach (GTK_GRID (table), widget, 1, 0, 1, 1);
3366   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3367
3368   label = gtk_label_new_with_mnemonic (_("Pages per _side:"));
3369   gtk_widget_set_halign (label, GTK_ALIGN_START);
3370   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3371   gtk_widget_show (label);
3372   gtk_grid_attach (GTK_GRID (table), label, 0, 1, 1, 1);
3373
3374   widget = gtk_printer_option_widget_new (NULL);
3375   g_signal_connect_swapped (widget, "changed", G_CALLBACK (redraw_page_layout_preview), dialog);
3376   g_signal_connect_swapped (widget, "changed", G_CALLBACK (update_number_up_layout), dialog);
3377   priv->pages_per_sheet = GTK_PRINTER_OPTION_WIDGET (widget);
3378   gtk_widget_show (widget);
3379   gtk_grid_attach (GTK_GRID (table), widget, 1, 1, 1, 1);
3380   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3381
3382   label = gtk_label_new_with_mnemonic (_("Page or_dering:"));
3383   gtk_widget_set_halign (label, GTK_ALIGN_START);
3384   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3385   gtk_widget_show (label);
3386   gtk_grid_attach (GTK_GRID (table), label, 0, 2, 1, 1);
3387
3388   widget = gtk_printer_option_widget_new (NULL);
3389   g_signal_connect_swapped (widget, "changed", G_CALLBACK (redraw_page_layout_preview), dialog);
3390   priv->number_up_layout = GTK_PRINTER_OPTION_WIDGET (widget);
3391   gtk_widget_show (widget);
3392   gtk_grid_attach (GTK_GRID (table), widget, 1, 2, 1, 1);
3393   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3394
3395   label = gtk_label_new_with_mnemonic (_("_Only print:"));
3396   gtk_widget_set_halign (label, GTK_ALIGN_START);
3397   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3398   gtk_widget_show (label);
3399   gtk_grid_attach (GTK_GRID (table), label, 0, 3, 1, 1);
3400
3401   combo = gtk_combo_box_text_new ();
3402   priv->page_set_combo = combo;
3403   gtk_widget_show (combo);
3404   gtk_grid_attach (GTK_GRID (table), combo, 1, 3, 1, 1);
3405   gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
3406   /* In enum order */
3407   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("All sheets"));
3408   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Even sheets"));
3409   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Odd sheets"));
3410   gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
3411
3412   label = gtk_label_new_with_mnemonic (_("Sc_ale:"));
3413   gtk_widget_set_halign (label, GTK_ALIGN_START);
3414   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3415   gtk_widget_show (label);
3416   gtk_grid_attach (GTK_GRID (table), label, 0, 4, 1, 1);
3417
3418   hbox2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
3419   gtk_widget_show (hbox2);
3420   gtk_grid_attach (GTK_GRID (table), hbox2, 1, 4, 1, 1);
3421
3422   spinbutton = gtk_spin_button_new_with_range (1.0, 1000.0, 1.0);
3423   priv->scale_spin = spinbutton;
3424   gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinbutton), 1);
3425   gtk_spin_button_set_value (GTK_SPIN_BUTTON (spinbutton), 100.0);
3426   gtk_box_pack_start (GTK_BOX (hbox2), spinbutton, FALSE, FALSE, 0);
3427   gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
3428   gtk_widget_show (spinbutton);
3429   label = gtk_label_new ("%"); /* FIXMEchpe does there exist any language where % needs to be translated? */
3430   gtk_widget_show (label);
3431   gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0);
3432
3433   table = gtk_grid_new ();
3434   gtk_grid_set_row_spacing (GTK_GRID (table), 6);
3435   gtk_grid_set_column_spacing (GTK_GRID (table), 12);
3436   frame = wrap_in_frame (_("Paper"), table);
3437   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 6);
3438   gtk_widget_show (table);
3439
3440   label = gtk_label_new_with_mnemonic (_("Paper _type:"));
3441   gtk_widget_set_halign (label, GTK_ALIGN_START);
3442   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3443   gtk_widget_show (label);
3444   gtk_grid_attach (GTK_GRID (table), label, 0, 0, 1, 1);
3445
3446   widget = gtk_printer_option_widget_new (NULL);
3447   priv->paper_type = GTK_PRINTER_OPTION_WIDGET (widget);
3448   gtk_widget_show (widget);
3449   gtk_grid_attach (GTK_GRID (table), widget, 1, 0, 1, 1);
3450   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3451
3452   label = gtk_label_new_with_mnemonic (_("Paper _source:"));
3453   gtk_widget_set_halign (label, GTK_ALIGN_START);
3454   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3455   gtk_widget_show (label);
3456   gtk_grid_attach (GTK_GRID (table), label, 0, 1, 1, 1);
3457
3458   widget = gtk_printer_option_widget_new (NULL);
3459   priv->paper_source = GTK_PRINTER_OPTION_WIDGET (widget);
3460   gtk_widget_show (widget);
3461   gtk_grid_attach (GTK_GRID (table), widget, 1, 1, 1, 1);
3462   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3463
3464   label = gtk_label_new_with_mnemonic (_("Output t_ray:"));
3465   gtk_widget_set_halign (label, GTK_ALIGN_START);
3466   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3467   gtk_widget_show (label);
3468   gtk_grid_attach (GTK_GRID (table), label, 0, 2, 1, 1);
3469
3470   widget = gtk_printer_option_widget_new (NULL);
3471   priv->output_tray = GTK_PRINTER_OPTION_WIDGET (widget);
3472   gtk_widget_show (widget);
3473   gtk_grid_attach (GTK_GRID (table), widget, 1, 2, 1, 1);
3474   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3475
3476
3477   label = gtk_label_new_with_mnemonic (_("_Paper size:"));
3478   priv->paper_size_combo_label = GTK_WIDGET (label);
3479   gtk_widget_set_halign (label, GTK_ALIGN_START);
3480   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3481   gtk_widget_show (label);
3482   gtk_grid_attach (GTK_GRID (table), label, 0, 3, 1, 1);
3483
3484   combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (priv->page_setup_list));
3485   priv->paper_size_combo = GTK_WIDGET (combo);
3486   gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo),
3487                                         paper_size_row_is_separator, NULL, NULL);
3488   cell = gtk_cell_renderer_text_new ();
3489   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
3490   gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo), cell,
3491                                       page_name_func, NULL, NULL);
3492   gtk_grid_attach (GTK_GRID (table), combo, 1, 3, 1, 1);
3493   gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
3494   gtk_widget_set_sensitive (combo, FALSE);
3495   gtk_widget_show (combo);
3496
3497   label = gtk_label_new_with_mnemonic (_("Or_ientation:"));
3498   priv->orientation_combo_label = GTK_WIDGET (label);
3499   gtk_widget_set_halign (label, GTK_ALIGN_START);
3500   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3501   gtk_widget_show (label);
3502   gtk_grid_attach (GTK_GRID (table), label, 0, 4, 1, 1);
3503
3504   combo = gtk_combo_box_text_new ();
3505   priv->orientation_combo = GTK_WIDGET (combo);
3506   gtk_grid_attach (GTK_GRID (table), combo, 1, 4, 1, 1);
3507   gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
3508   /* In enum order */
3509   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Portrait"));
3510   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Landscape"));
3511   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Reverse portrait"));
3512   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Reverse landscape"));
3513   gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
3514   gtk_widget_set_sensitive (combo, FALSE);
3515   gtk_widget_show (combo);
3516
3517   /* Add the page layout preview */
3518   hbox2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
3519   gtk_widget_show (hbox2);
3520   gtk_box_pack_start (GTK_BOX (main_vbox), hbox2, TRUE, TRUE, 0);
3521
3522   draw = gtk_drawing_area_new ();
3523   gtk_widget_set_has_window (draw, FALSE);
3524   priv->page_layout_preview = draw;
3525   gtk_widget_set_size_request (draw, 280, 160);
3526   g_signal_connect (draw, "draw", G_CALLBACK (draw_page_cb), dialog);
3527   gtk_widget_show (draw);
3528
3529   gtk_box_pack_start (GTK_BOX (hbox2), draw, TRUE, FALSE, 0);
3530
3531   label = gtk_label_new (_("Page Setup"));
3532   gtk_widget_show (label);
3533
3534   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
3535                             main_vbox, label);
3536 }
3537
3538 static void
3539 create_job_page (GtkPrintUnixDialog *dialog)
3540 {
3541   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3542   GtkWidget *main_table, *label;
3543   GtkWidget *frame, *table, *radio;
3544   GtkWidget *entry, *widget;
3545   const gchar *at_tooltip;
3546   const gchar *on_hold_tooltip;
3547
3548   main_table = gtk_grid_new ();
3549   gtk_container_set_border_width (GTK_CONTAINER (main_table), 12);
3550   gtk_grid_set_row_spacing (GTK_GRID (main_table), 18);
3551   gtk_grid_set_column_spacing (GTK_GRID (main_table), 18);
3552
3553   table = gtk_grid_new ();
3554   gtk_grid_set_row_spacing (GTK_GRID (table), 6);
3555   gtk_grid_set_column_spacing (GTK_GRID (table), 12);
3556   frame = wrap_in_frame (_("Job Details"), table);
3557   gtk_grid_attach (GTK_GRID (main_table), frame, 0, 0, 1, 1);
3558   gtk_widget_show (table);
3559
3560   label = gtk_label_new_with_mnemonic (_("Pri_ority:"));
3561   gtk_widget_set_halign (label, GTK_ALIGN_START);
3562   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3563   gtk_widget_show (label);
3564   gtk_grid_attach (GTK_GRID (table), label, 0, 0, 1, 1);
3565
3566   widget = gtk_printer_option_widget_new (NULL);
3567   priv->job_prio = GTK_PRINTER_OPTION_WIDGET (widget);
3568   gtk_widget_show (widget);
3569   gtk_grid_attach (GTK_GRID (table), widget, 1, 0, 1, 1);
3570   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3571
3572   label = gtk_label_new_with_mnemonic (_("_Billing info:"));
3573   gtk_widget_set_halign (label, GTK_ALIGN_START);
3574   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3575   gtk_widget_show (label);
3576   gtk_grid_attach (GTK_GRID (table), label, 0, 1, 1, 1);
3577
3578   widget = gtk_printer_option_widget_new (NULL);
3579   priv->billing_info = GTK_PRINTER_OPTION_WIDGET (widget);
3580   gtk_widget_show (widget);
3581   gtk_grid_attach (GTK_GRID (table), widget, 1, 1, 1, 1);
3582   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3583
3584   table = gtk_grid_new ();
3585   gtk_grid_set_row_spacing (GTK_GRID (table), 6);
3586   gtk_grid_set_column_spacing (GTK_GRID (table), 12);
3587   frame = wrap_in_frame (_("Print Document"), table);
3588   gtk_grid_attach (GTK_GRID (main_table), frame, 0, 1, 1, 1);
3589   gtk_widget_show (table);
3590
3591   /* Translators: this is one of the choices for the print at option
3592    * in the print dialog
3593    */
3594   radio = gtk_radio_button_new_with_mnemonic (NULL, _("_Now"));
3595   priv->print_now_radio = radio;
3596   gtk_widget_show (radio);
3597   gtk_grid_attach (GTK_GRID (table), radio, 0, 0, 2, 1);
3598   /* Translators: this is one of the choices for the print at option
3599    * in the print dialog. It also serves as the label for an entry that
3600    * allows the user to enter a time.
3601    */
3602   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
3603                                               _("A_t:"));
3604
3605   /* Translators: Ability to parse the am/pm format depends on actual locale.
3606    * You can remove the am/pm values below for your locale if they are not
3607    * supported.
3608    */
3609   at_tooltip = _("Specify the time of print,\n e.g. 15:30, 2:35 pm, 14:15:20, 11:46:30 am, 4 pm");
3610   gtk_widget_set_tooltip_text (radio, at_tooltip);
3611   priv->print_at_radio = radio;
3612   gtk_widget_show (radio);
3613   gtk_grid_attach (GTK_GRID (table), radio, 0, 1, 1, 1);
3614
3615   entry = gtk_entry_new ();
3616   gtk_widget_set_tooltip_text (entry, at_tooltip);
3617   atk_object_set_name (gtk_widget_get_accessible (entry), _("Time of print"));
3618   atk_object_set_description (gtk_widget_get_accessible (entry), at_tooltip);
3619   priv->print_at_entry = entry;
3620   gtk_widget_show (entry);
3621   gtk_grid_attach (GTK_GRID (table), entry, 1, 1, 1, 1);
3622
3623   g_signal_connect (radio, "toggled", G_CALLBACK (update_entry_sensitivity), entry);
3624   update_entry_sensitivity (radio, entry);
3625
3626   /* Translators: this is one of the choices for the print at option
3627    * in the print dialog. It means that the print job will not be
3628    * printed until it explicitly gets 'released'.
3629    */
3630   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
3631                                               _("On _hold"));
3632   on_hold_tooltip = _("Hold the job until it is explicitly released");
3633   gtk_widget_set_tooltip_text (radio, on_hold_tooltip);
3634   priv->print_hold_radio = radio;
3635   gtk_widget_show (radio);
3636   gtk_grid_attach (GTK_GRID (table), radio, 0, 2, 2, 1);
3637
3638   g_signal_connect_swapped (priv->print_now_radio, "toggled",
3639                             G_CALLBACK (update_print_at_option), dialog);
3640   g_signal_connect_swapped (priv->print_at_radio, "toggled",
3641                             G_CALLBACK (update_print_at_option), dialog);
3642   g_signal_connect_swapped (priv->print_at_entry, "changed",
3643                             G_CALLBACK (update_print_at_option), dialog);
3644   g_signal_connect_swapped (priv->print_hold_radio, "toggled",
3645                             G_CALLBACK (update_print_at_option), dialog);
3646
3647   table = gtk_grid_new ();
3648   gtk_grid_set_row_spacing (GTK_GRID (table), 6);
3649   gtk_grid_set_column_spacing (GTK_GRID (table), 12);
3650   frame = wrap_in_frame (_("Add Cover Page"), table);
3651   gtk_grid_attach (GTK_GRID (main_table), frame, 1, 0, 1, 1);
3652   gtk_widget_show (table);
3653
3654   /* Translators, this is the label used for the option in the print
3655    * dialog that controls the front cover page.
3656    */
3657   label = gtk_label_new_with_mnemonic (_("Be_fore:"));
3658   gtk_widget_set_halign (label, GTK_ALIGN_START);
3659   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3660   gtk_widget_show (label);
3661   gtk_grid_attach (GTK_GRID (table), label, 0, 0, 1, 1);
3662
3663   widget = gtk_printer_option_widget_new (NULL);
3664   priv->cover_before = GTK_PRINTER_OPTION_WIDGET (widget);
3665   gtk_widget_show (widget);
3666   gtk_grid_attach (GTK_GRID (table), widget, 1, 0, 1, 1);
3667   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3668
3669   /* Translators, this is the label used for the option in the print
3670    * dialog that controls the back cover page.
3671    */
3672   label = gtk_label_new_with_mnemonic (_("_After:"));
3673   gtk_widget_set_halign (label, GTK_ALIGN_START);
3674   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
3675   gtk_widget_show (label);
3676   gtk_grid_attach (GTK_GRID (table), label, 0, 1, 1, 1);
3677
3678   widget = gtk_printer_option_widget_new (NULL);
3679   priv->cover_after = GTK_PRINTER_OPTION_WIDGET (widget);
3680   gtk_widget_show (widget);
3681   gtk_grid_attach (GTK_GRID (table), widget, 1, 1, 1, 1);
3682   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
3683
3684   /* Translators: this is the tab label for the notebook tab containing
3685    * job-specific options in the print dialog
3686    */
3687   label = gtk_label_new (_("Job"));
3688   gtk_widget_show (label);
3689
3690   priv->job_page = main_table;
3691   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
3692                             main_table, label);
3693 }
3694
3695 static void
3696 create_optional_page (GtkPrintUnixDialog  *dialog,
3697                       const gchar         *text,
3698                       GtkWidget          **table_out,
3699                       GtkWidget          **page_out)
3700 {
3701   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3702   GtkWidget *table, *label, *scrolled;
3703
3704   scrolled = gtk_scrolled_window_new (NULL, NULL);
3705   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
3706                                   GTK_POLICY_NEVER,
3707                                   GTK_POLICY_AUTOMATIC);
3708
3709   table = gtk_grid_new ();
3710   gtk_grid_set_row_spacing (GTK_GRID (table), 6);
3711   gtk_grid_set_column_spacing (GTK_GRID (table), 12);
3712   gtk_container_set_border_width (GTK_CONTAINER (table), 12);
3713   gtk_widget_show (table);
3714
3715   gtk_container_add (GTK_CONTAINER (scrolled), table);
3716   gtk_viewport_set_shadow_type (GTK_VIEWPORT (gtk_bin_get_child (GTK_BIN (scrolled))),
3717                                 GTK_SHADOW_NONE);
3718
3719   label = gtk_label_new (text);
3720   gtk_widget_show (label);
3721
3722   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
3723                             scrolled, label);
3724
3725   *table_out = table;
3726   *page_out = scrolled;
3727 }
3728
3729 static void
3730 create_advanced_page (GtkPrintUnixDialog *dialog)
3731 {
3732   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3733   GtkWidget *main_vbox, *label, *scrolled;
3734
3735   scrolled = gtk_scrolled_window_new (NULL, NULL);
3736   priv->advanced_page = scrolled;
3737   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
3738                                   GTK_POLICY_NEVER,
3739                                   GTK_POLICY_AUTOMATIC);
3740
3741   main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 18);
3742   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
3743   gtk_widget_show (main_vbox);
3744
3745   gtk_container_add (GTK_CONTAINER (scrolled), main_vbox);
3746   gtk_viewport_set_shadow_type (GTK_VIEWPORT (gtk_bin_get_child (GTK_BIN (scrolled))),
3747                                 GTK_SHADOW_NONE);
3748
3749   priv->advanced_vbox = main_vbox;
3750
3751   label = gtk_label_new (_("Advanced"));
3752   gtk_widget_show (label);
3753
3754   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
3755                             scrolled, label);
3756 }
3757
3758 static void
3759 populate_dialog (GtkPrintUnixDialog *print_dialog)
3760 {
3761   GtkPrintUnixDialogPrivate *priv = print_dialog->priv;
3762   GtkDialog *dialog = GTK_DIALOG (print_dialog);
3763   GtkWidget *vbox, *conflict_hbox, *image, *label;
3764   GtkWidget *action_area, *content_area;
3765
3766   content_area = gtk_dialog_get_content_area (dialog);
3767   action_area = gtk_dialog_get_action_area (dialog);
3768
3769   gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
3770   gtk_box_set_spacing (GTK_BOX (content_area), 2); /* 2 * 5 + 2 = 12 */
3771   gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
3772   gtk_box_set_spacing (GTK_BOX (action_area), 6);
3773
3774   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
3775   gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
3776   gtk_box_pack_start (GTK_BOX (content_area), vbox, TRUE, TRUE, 0);
3777   gtk_widget_show (vbox);
3778
3779   priv->notebook = gtk_notebook_new ();
3780   gtk_box_pack_start (GTK_BOX (vbox), priv->notebook, TRUE, TRUE, 0);
3781   gtk_widget_show (priv->notebook);
3782
3783   create_printer_list_model (print_dialog);
3784
3785   create_main_page (print_dialog);
3786   create_page_setup_page (print_dialog);
3787   create_job_page (print_dialog);
3788   /* Translators: this will appear as tab label in print dialog. */
3789   create_optional_page (print_dialog, _("Image Quality"),
3790                         &priv->image_quality_table,
3791                         &priv->image_quality_page);
3792   /* Translators: this will appear as tab label in print dialog. */
3793   create_optional_page (print_dialog, _("Color"),
3794                         &priv->color_table,
3795                         &priv->color_page);
3796   /* Translators: this will appear as tab label in print dialog. */
3797   /* It's a typographical term, as in "Binding and finishing" */
3798   create_optional_page (print_dialog, _("Finishing"),
3799                         &priv->finishing_table,
3800                         &priv->finishing_page);
3801   create_advanced_page (print_dialog);
3802
3803   priv->conflicts_widget = conflict_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
3804   gtk_box_pack_end (GTK_BOX (vbox), conflict_hbox, FALSE, FALSE, 0);
3805   image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_MENU);
3806   gtk_widget_show (image);
3807   gtk_box_pack_start (GTK_BOX (conflict_hbox), image, FALSE, TRUE, 0);
3808   label = gtk_label_new (_("Some of the settings in the dialog conflict"));
3809   gtk_widget_show (label);
3810   gtk_box_pack_start (GTK_BOX (conflict_hbox), label, FALSE, TRUE, 0);
3811
3812   load_print_backends (print_dialog);
3813 }
3814
3815 /**
3816  * gtk_print_unix_dialog_new:
3817  * @title: (allow-none): Title of the dialog, or %NULL
3818  * @parent: (allow-none): Transient parent of the dialog, or %NULL
3819  *
3820  * Creates a new #GtkPrintUnixDialog.
3821  *
3822  * Return value: a new #GtkPrintUnixDialog
3823  *
3824  * Since: 2.10
3825  */
3826 GtkWidget *
3827 gtk_print_unix_dialog_new (const gchar *title,
3828                            GtkWindow   *parent)
3829 {
3830   GtkWidget *result;
3831
3832   result = g_object_new (GTK_TYPE_PRINT_UNIX_DIALOG,
3833                          "transient-for", parent,
3834                          "title", title ? title : _("Print"),
3835                          NULL);
3836
3837   return result;
3838 }
3839
3840 /**
3841  * gtk_print_unix_dialog_get_selected_printer:
3842  * @dialog: a #GtkPrintUnixDialog
3843  *
3844  * Gets the currently selected printer.
3845  *
3846  * Returns: (transfer none): the currently selected printer
3847  *
3848  * Since: 2.10
3849  */
3850 GtkPrinter *
3851 gtk_print_unix_dialog_get_selected_printer (GtkPrintUnixDialog *dialog)
3852 {
3853   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
3854
3855   return dialog->priv->current_printer;
3856 }
3857
3858 /**
3859  * gtk_print_unix_dialog_set_page_setup:
3860  * @dialog: a #GtkPrintUnixDialog
3861  * @page_setup: a #GtkPageSetup
3862  *
3863  * Sets the page setup of the #GtkPrintUnixDialog.
3864  *
3865  * Since: 2.10
3866  */
3867 void
3868 gtk_print_unix_dialog_set_page_setup (GtkPrintUnixDialog *dialog,
3869                                       GtkPageSetup       *page_setup)
3870 {
3871   GtkPrintUnixDialogPrivate *priv;
3872
3873   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
3874   g_return_if_fail (GTK_IS_PAGE_SETUP (page_setup));
3875
3876   priv = dialog->priv;
3877
3878   if (priv->page_setup != page_setup)
3879     {
3880       g_object_unref (priv->page_setup);
3881       priv->page_setup = g_object_ref (page_setup);
3882
3883       priv->page_setup_set = TRUE;
3884
3885       g_object_notify (G_OBJECT (dialog), "page-setup");
3886     }
3887 }
3888
3889 /**
3890  * gtk_print_unix_dialog_get_page_setup:
3891  * @dialog: a #GtkPrintUnixDialog
3892  *
3893  * Gets the page setup that is used by the #GtkPrintUnixDialog.
3894  *
3895  * Returns: (transfer none): the page setup of @dialog.
3896  *
3897  * Since: 2.10
3898  */
3899 GtkPageSetup *
3900 gtk_print_unix_dialog_get_page_setup (GtkPrintUnixDialog *dialog)
3901 {
3902   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
3903
3904   return dialog->priv->page_setup;
3905 }
3906
3907 /**
3908  * gtk_print_unix_dialog_get_page_setup_set:
3909  * @dialog: a #GtkPrintUnixDialog
3910  *
3911  * Gets the page setup that is used by the #GtkPrintUnixDialog.
3912  *
3913  * Returns: whether a page setup was set by user.
3914  *
3915  * Since: 2.18
3916  */
3917 gboolean
3918 gtk_print_unix_dialog_get_page_setup_set (GtkPrintUnixDialog *dialog)
3919 {
3920   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), FALSE);
3921
3922   return dialog->priv->page_setup_set;
3923 }
3924
3925 /**
3926  * gtk_print_unix_dialog_set_current_page:
3927  * @dialog: a #GtkPrintUnixDialog
3928  * @current_page: the current page number.
3929  *
3930  * Sets the current page number. If @current_page is not -1, this enables
3931  * the current page choice for the range of pages to print.
3932  *
3933  * Since: 2.10
3934  */
3935 void
3936 gtk_print_unix_dialog_set_current_page (GtkPrintUnixDialog *dialog,
3937                                         gint                current_page)
3938 {
3939   GtkPrintUnixDialogPrivate *priv;
3940
3941   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
3942
3943   priv = dialog->priv;
3944
3945   if (priv->current_page != current_page)
3946     {
3947       priv->current_page = current_page;
3948
3949       if (priv->current_page_radio)
3950         gtk_widget_set_sensitive (priv->current_page_radio, current_page != -1);
3951
3952       g_object_notify (G_OBJECT (dialog), "current-page");
3953     }
3954 }
3955
3956 /**
3957  * gtk_print_unix_dialog_get_current_page:
3958  * @dialog: a #GtkPrintUnixDialog
3959  *
3960  * Gets the current page of the #GtkPrintUnixDialog.
3961  *
3962  * Returns: the current page of @dialog
3963  *
3964  * Since: 2.10
3965  */
3966 gint
3967 gtk_print_unix_dialog_get_current_page (GtkPrintUnixDialog *dialog)
3968 {
3969   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), -1);
3970
3971   return dialog->priv->current_page;
3972 }
3973
3974 static gboolean
3975 set_active_printer (GtkPrintUnixDialog *dialog,
3976                     const gchar        *printer_name)
3977 {
3978   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3979   GtkTreeModel *model;
3980   GtkTreeIter iter, filter_iter;
3981   GtkTreeSelection *selection;
3982   GtkPrinter *printer;
3983
3984   model = GTK_TREE_MODEL (priv->printer_list);
3985
3986   if (gtk_tree_model_get_iter_first (model, &iter))
3987     {
3988       do
3989         {
3990           gtk_tree_model_get (GTK_TREE_MODEL (priv->printer_list), &iter,
3991                               PRINTER_LIST_COL_PRINTER_OBJ, &printer,
3992                               -1);
3993           if (printer == NULL)
3994             continue;
3995
3996           if (strcmp (gtk_printer_get_name (printer), printer_name) == 0)
3997             {
3998               gtk_tree_model_filter_convert_child_iter_to_iter (priv->printer_list_filter,
3999                                                                 &filter_iter, &iter);
4000
4001               selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
4002               priv->internal_printer_change = TRUE;
4003               gtk_tree_selection_select_iter (selection, &filter_iter);
4004               priv->internal_printer_change = FALSE;
4005               g_free (priv->waiting_for_printer);
4006               priv->waiting_for_printer = NULL;
4007
4008               g_object_unref (printer);
4009               return TRUE;
4010             }
4011
4012           g_object_unref (printer);
4013
4014         } while (gtk_tree_model_iter_next (model, &iter));
4015     }
4016
4017   return FALSE;
4018 }
4019
4020 /**
4021  * gtk_print_unix_dialog_set_settings:
4022  * @dialog: a #GtkPrintUnixDialog
4023  * @settings: (allow-none): a #GtkPrintSettings, or %NULL
4024  *
4025  * Sets the #GtkPrintSettings for the #GtkPrintUnixDialog. Typically,
4026  * this is used to restore saved print settings from a previous print
4027  * operation before the print dialog is shown.
4028  *
4029  * Since: 2.10
4030  **/
4031 void
4032 gtk_print_unix_dialog_set_settings (GtkPrintUnixDialog *dialog,
4033                                     GtkPrintSettings   *settings)
4034 {
4035   GtkPrintUnixDialogPrivate *priv;
4036   const gchar *printer;
4037   GtkPageRange *ranges;
4038   gint num_ranges;
4039
4040   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
4041   g_return_if_fail (settings == NULL || GTK_IS_PRINT_SETTINGS (settings));
4042
4043   priv = dialog->priv;
4044
4045   if (settings != NULL)
4046     {
4047       dialog_set_collate (dialog, gtk_print_settings_get_collate (settings));
4048       dialog_set_reverse (dialog, gtk_print_settings_get_reverse (settings));
4049       dialog_set_n_copies (dialog, gtk_print_settings_get_n_copies (settings));
4050       dialog_set_scale (dialog, gtk_print_settings_get_scale (settings));
4051       dialog_set_page_set (dialog, gtk_print_settings_get_page_set (settings));
4052       dialog_set_print_pages (dialog, gtk_print_settings_get_print_pages (settings));
4053       ranges = gtk_print_settings_get_page_ranges (settings, &num_ranges);
4054       if (ranges)
4055         {
4056           dialog_set_page_ranges (dialog, ranges, num_ranges);
4057           g_free (ranges);
4058         }
4059
4060       priv->format_for_printer =
4061         g_strdup (gtk_print_settings_get (settings, "format-for-printer"));
4062     }
4063
4064   if (priv->initial_settings)
4065     g_object_unref (priv->initial_settings);
4066
4067   priv->initial_settings = settings;
4068
4069   g_free (priv->waiting_for_printer);
4070   priv->waiting_for_printer = NULL;
4071
4072   if (settings)
4073     {
4074       g_object_ref (settings);
4075
4076       printer = gtk_print_settings_get_printer (settings);
4077
4078       if (printer && !set_active_printer (dialog, printer))
4079         priv->waiting_for_printer = g_strdup (printer);
4080     }
4081
4082   g_object_notify (G_OBJECT (dialog), "print-settings");
4083 }
4084
4085 /**
4086  * gtk_print_unix_dialog_get_settings:
4087  * @dialog: a #GtkPrintUnixDialog
4088  *
4089  * Gets a new #GtkPrintSettings object that represents the
4090  * current values in the print dialog. Note that this creates a
4091  * <emphasis>new object</emphasis>, and you need to unref it
4092  * if don't want to keep it.
4093  *
4094  * Returns: a new #GtkPrintSettings object with the values from @dialog
4095  *
4096  * Since: 2.10
4097  */
4098 GtkPrintSettings *
4099 gtk_print_unix_dialog_get_settings (GtkPrintUnixDialog *dialog)
4100 {
4101   GtkPrintUnixDialogPrivate *priv;
4102   GtkPrintSettings *settings;
4103   GtkPrintPages print_pages;
4104   GtkPageRange *ranges;
4105   gint n_ranges;
4106
4107   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
4108
4109   priv = dialog->priv;
4110   settings = gtk_print_settings_new ();
4111
4112   if (priv->current_printer)
4113     gtk_print_settings_set_printer (settings,
4114                                     gtk_printer_get_name (priv->current_printer));
4115   else
4116     gtk_print_settings_set_printer (settings, "default");
4117
4118   gtk_print_settings_set (settings, "format-for-printer",
4119                           priv->format_for_printer);
4120
4121   gtk_print_settings_set_collate (settings,
4122                                   dialog_get_collate (dialog));
4123
4124   gtk_print_settings_set_reverse (settings,
4125                                   dialog_get_reverse (dialog));
4126
4127   gtk_print_settings_set_n_copies (settings,
4128                                    dialog_get_n_copies (dialog));
4129
4130   gtk_print_settings_set_scale (settings,
4131                                 dialog_get_scale (dialog));
4132
4133   gtk_print_settings_set_page_set (settings,
4134                                    dialog_get_page_set (dialog));
4135
4136   print_pages = dialog_get_print_pages (dialog);
4137   gtk_print_settings_set_print_pages (settings, print_pages);
4138
4139   ranges = dialog_get_page_ranges (dialog, &n_ranges);
4140   if (ranges)
4141     {
4142       gtk_print_settings_set_page_ranges (settings, ranges, n_ranges);
4143       g_free (ranges);
4144     }
4145
4146   /* TODO: print when. How to handle? */
4147
4148   if (priv->current_printer)
4149     _gtk_printer_get_settings_from_options (priv->current_printer,
4150                                             priv->options,
4151                                             settings);
4152
4153   return settings;
4154 }
4155
4156 /**
4157  * gtk_print_unix_dialog_add_custom_tab:
4158  * @dialog: a #GtkPrintUnixDialog
4159  * @child: the widget to put in the custom tab
4160  * @tab_label: the widget to use as tab label
4161  *
4162  * Adds a custom tab to the print dialog.
4163  *
4164  * Since: 2.10
4165  */
4166 void
4167 gtk_print_unix_dialog_add_custom_tab (GtkPrintUnixDialog *dialog,
4168                                       GtkWidget          *child,
4169                                       GtkWidget          *tab_label)
4170 {
4171   gtk_notebook_insert_page (GTK_NOTEBOOK (dialog->priv->notebook),
4172                             child, tab_label, 2);
4173   gtk_widget_show (child);
4174   gtk_widget_show (tab_label);
4175 }
4176
4177 /**
4178  * gtk_print_unix_dialog_set_manual_capabilities:
4179  * @dialog: a #GtkPrintUnixDialog
4180  * @capabilities: the printing capabilities of your application
4181  *
4182  * This lets you specify the printing capabilities your application
4183  * supports. For instance, if you can handle scaling the output then
4184  * you pass #GTK_PRINT_CAPABILITY_SCALE. If you don't pass that, then
4185  * the dialog will only let you select the scale if the printing
4186  * system automatically handles scaling.
4187  *
4188  * Since: 2.10
4189  */
4190 void
4191 gtk_print_unix_dialog_set_manual_capabilities (GtkPrintUnixDialog   *dialog,
4192                                                GtkPrintCapabilities  capabilities)
4193 {
4194   GtkPrintUnixDialogPrivate *priv = dialog->priv;
4195
4196   if (priv->manual_capabilities != capabilities)
4197     {
4198       priv->manual_capabilities = capabilities;
4199       update_dialog_from_capabilities (dialog);
4200
4201       if (priv->current_printer)
4202         {
4203           GtkTreeSelection *selection;
4204
4205           selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
4206           g_clear_object (&priv->current_printer);
4207           priv->internal_printer_change = TRUE;
4208           selected_printer_changed (selection, dialog);
4209           priv->internal_printer_change = FALSE;
4210        }
4211
4212       g_object_notify (G_OBJECT (dialog), "manual-capabilities");
4213     }
4214 }
4215
4216 /**
4217  * gtk_print_unix_dialog_get_manual_capabilities:
4218  * @dialog: a #GtkPrintUnixDialog
4219  *
4220  * Gets the value of #GtkPrintUnixDialog:manual-capabilities property.
4221  *
4222  * Returns: the printing capabilities
4223  *
4224  * Since: 2.18
4225  */
4226 GtkPrintCapabilities
4227 gtk_print_unix_dialog_get_manual_capabilities (GtkPrintUnixDialog *dialog)
4228 {
4229   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), FALSE);
4230
4231   return dialog->priv->manual_capabilities;
4232 }
4233
4234 /**
4235  * gtk_print_unix_dialog_set_support_selection:
4236  * @dialog: a #GtkPrintUnixDialog
4237  * @support_selection: %TRUE to allow print selection
4238  *
4239  * Sets whether the print dialog allows user to print a selection.
4240  *
4241  * Since: 2.18
4242  */
4243 void
4244 gtk_print_unix_dialog_set_support_selection (GtkPrintUnixDialog *dialog,
4245                                              gboolean            support_selection)
4246 {
4247   GtkPrintUnixDialogPrivate *priv;
4248
4249   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
4250
4251   priv = dialog->priv;
4252
4253   support_selection = support_selection != FALSE;
4254   if (priv->support_selection != support_selection)
4255     {
4256       priv->support_selection = support_selection;
4257
4258       if (priv->selection_radio)
4259         {
4260           if (support_selection)
4261             {
4262               gtk_widget_set_sensitive (priv->selection_radio, priv->has_selection);
4263               gtk_widget_show (priv->selection_radio);
4264             }
4265           else
4266             {
4267               gtk_widget_set_sensitive (priv->selection_radio, FALSE);
4268               gtk_widget_hide (priv->selection_radio);
4269             }
4270         }
4271
4272       g_object_notify (G_OBJECT (dialog), "support-selection");
4273     }
4274 }
4275
4276 /**
4277  * gtk_print_unix_dialog_get_support_selection:
4278  * @dialog: a #GtkPrintUnixDialog
4279  *
4280  * Gets the value of #GtkPrintUnixDialog:support-selection property.
4281  *
4282  * Returns: whether the application supports print of selection
4283  *
4284  * Since: 2.18
4285  */
4286 gboolean
4287 gtk_print_unix_dialog_get_support_selection (GtkPrintUnixDialog *dialog)
4288 {
4289   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), FALSE);
4290
4291   return dialog->priv->support_selection;
4292 }
4293
4294 /**
4295  * gtk_print_unix_dialog_set_has_selection:
4296  * @dialog: a #GtkPrintUnixDialog
4297  * @has_selection: %TRUE indicates that a selection exists
4298  *
4299  * Sets whether a selection exists.
4300  *
4301  * Since: 2.18
4302  */
4303 void
4304 gtk_print_unix_dialog_set_has_selection (GtkPrintUnixDialog *dialog,
4305                                          gboolean            has_selection)
4306 {
4307   GtkPrintUnixDialogPrivate *priv;
4308
4309   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
4310
4311   priv = dialog->priv;
4312
4313   has_selection = has_selection != FALSE;
4314   if (priv->has_selection != has_selection)
4315     {
4316       priv->has_selection = has_selection;
4317
4318       if (priv->selection_radio)
4319         {
4320           if (priv->support_selection)
4321             gtk_widget_set_sensitive (priv->selection_radio, has_selection);
4322           else
4323             gtk_widget_set_sensitive (priv->selection_radio, FALSE);
4324         }
4325
4326       g_object_notify (G_OBJECT (dialog), "has-selection");
4327     }
4328 }
4329
4330 /**
4331  * gtk_print_unix_dialog_get_has_selection:
4332  * @dialog: a #GtkPrintUnixDialog
4333  *
4334  * Gets the value of #GtkPrintUnixDialog:has-selection property.
4335  *
4336  * Returns: whether there is a selection
4337  *
4338  * Since: 2.18
4339  */
4340 gboolean
4341 gtk_print_unix_dialog_get_has_selection (GtkPrintUnixDialog *dialog)
4342 {
4343   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), FALSE);
4344
4345   return dialog->priv->has_selection;
4346 }
4347
4348 /**
4349  * gtk_print_unix_dialog_set_embed_page_setup
4350  * @dialog: a #GtkPrintUnixDialog
4351  * @embed: embed page setup selection
4352  *
4353  * Embed page size combo box and orientation combo box into page setup page.
4354  *
4355  * Since: 2.18
4356  */
4357 void
4358 gtk_print_unix_dialog_set_embed_page_setup (GtkPrintUnixDialog *dialog,
4359                                             gboolean            embed)
4360 {
4361   GtkPrintUnixDialogPrivate *priv;
4362
4363   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
4364
4365   priv = dialog->priv;
4366
4367   embed = embed != FALSE;
4368   if (priv->embed_page_setup != embed)
4369     {
4370       priv->embed_page_setup = embed;
4371
4372       gtk_widget_set_sensitive (priv->paper_size_combo, priv->embed_page_setup);
4373       gtk_widget_set_sensitive (priv->orientation_combo, priv->embed_page_setup);
4374
4375       if (priv->embed_page_setup)
4376         {
4377           if (priv->paper_size_combo != NULL)
4378             g_signal_connect (priv->paper_size_combo, "changed", G_CALLBACK (paper_size_changed), dialog);
4379
4380           if (priv->orientation_combo)
4381             g_signal_connect (priv->orientation_combo, "changed", G_CALLBACK (orientation_changed), dialog);
4382         }
4383       else
4384         {
4385           if (priv->paper_size_combo != NULL)
4386             g_signal_handlers_disconnect_by_func (priv->paper_size_combo, G_CALLBACK (paper_size_changed), dialog);
4387
4388           if (priv->orientation_combo)
4389             g_signal_handlers_disconnect_by_func (priv->orientation_combo, G_CALLBACK (orientation_changed), dialog);
4390         }
4391
4392       priv->internal_page_setup_change = TRUE;
4393       update_paper_sizes (dialog);
4394       priv->internal_page_setup_change = FALSE;
4395     }
4396 }
4397
4398 /**
4399  * gtk_print_unix_dialog_get_embed_page_setup:
4400  * @dialog: a #GtkPrintUnixDialog
4401  *
4402  * Gets the value of #GtkPrintUnixDialog:embed-page-setup property.
4403  *
4404  * Returns: whether there is a selection
4405  *
4406  * Since: 2.18
4407  */
4408 gboolean
4409 gtk_print_unix_dialog_get_embed_page_setup (GtkPrintUnixDialog *dialog)
4410 {
4411   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), FALSE);
4412
4413   return dialog->priv->embed_page_setup;
4414 }