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