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