]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintunixdialog.c
Merge branch 'master' into client-side-windows
[~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 "gtkprintbackend.h"
54 #include "gtkprinter-private.h"
55 #include "gtkprintunixdialog.h"
56 #include "gtkprinteroptionwidget.h"
57 #include "gtkalias.h"
58
59 #include "gtkmessagedialog.h"
60 #include "gtkbutton.h"
61
62 #define EXAMPLE_PAGE_AREA_SIZE 140
63
64 #define GTK_PRINT_UNIX_DIALOG_GET_PRIVATE(o)  \
65    (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_PRINT_UNIX_DIALOG, GtkPrintUnixDialogPrivate))
66
67 static void     gtk_print_unix_dialog_destroy      (GtkPrintUnixDialog *dialog);
68 static void     gtk_print_unix_dialog_finalize     (GObject            *object);
69 static void     gtk_print_unix_dialog_set_property (GObject            *object,
70                                                     guint               prop_id,
71                                                     const GValue       *value,
72                                                     GParamSpec         *pspec);
73 static void     gtk_print_unix_dialog_get_property (GObject            *object,
74                                                     guint               prop_id,
75                                                     GValue             *value,
76                                                     GParamSpec         *pspec);
77 static void     gtk_print_unix_dialog_style_set    (GtkWidget          *widget,
78                                                     GtkStyle           *previous_style);
79 static void     populate_dialog                    (GtkPrintUnixDialog *dialog);
80 static void     unschedule_idle_mark_conflicts     (GtkPrintUnixDialog *dialog);
81 static void     selected_printer_changed           (GtkTreeSelection   *selection,
82                                                     GtkPrintUnixDialog *dialog);
83 static void     clear_per_printer_ui               (GtkPrintUnixDialog *dialog);
84 static void     printer_added_cb                   (GtkPrintBackend    *backend,
85                                                     GtkPrinter         *printer,
86                                                     GtkPrintUnixDialog *dialog);
87 static void     printer_removed_cb                 (GtkPrintBackend    *backend,
88                                                     GtkPrinter         *printer,
89                                                     GtkPrintUnixDialog *dialog);
90 static void     printer_status_cb                  (GtkPrintBackend    *backend,
91                                                     GtkPrinter         *printer,
92                                                     GtkPrintUnixDialog *dialog);
93 static void     update_collate_icon                (GtkToggleButton    *toggle_button,
94                                                     GtkPrintUnixDialog *dialog);
95 static gboolean dialog_get_collate                 (GtkPrintUnixDialog *dialog);
96 static gboolean dialog_get_reverse                 (GtkPrintUnixDialog *dialog);
97 static gint     dialog_get_n_copies                (GtkPrintUnixDialog *dialog);
98
99 static void     set_cell_sensitivity_func          (GtkTreeViewColumn *tree_column,
100                                                     GtkCellRenderer   *cell,
101                                                     GtkTreeModel      *model,
102                                                     GtkTreeIter       *iter,
103                                                     gpointer           data);
104 static gboolean set_active_printer                 (GtkPrintUnixDialog *dialog,
105                                                     const gchar        *printer_name);
106
107 /* GtkBuildable */
108 static void gtk_print_unix_dialog_buildable_init                    (GtkBuildableIface *iface);
109 static GObject *gtk_print_unix_dialog_buildable_get_internal_child  (GtkBuildable *buildable,
110                                                                      GtkBuilder   *builder,
111                                                                      const gchar  *childname);
112
113 enum {
114   PROP_0,
115   PROP_PAGE_SETUP,
116   PROP_CURRENT_PAGE,
117   PROP_PRINT_SETTINGS,
118   PROP_SELECTED_PRINTER
119 };
120
121 enum {
122   PRINTER_LIST_COL_ICON,
123   PRINTER_LIST_COL_NAME,
124   PRINTER_LIST_COL_STATE,
125   PRINTER_LIST_COL_JOBS,
126   PRINTER_LIST_COL_LOCATION,
127   PRINTER_LIST_COL_PRINTER_OBJ,
128   PRINTER_LIST_N_COLS
129 };
130
131 struct GtkPrintUnixDialogPrivate
132 {
133   GtkWidget *notebook;
134
135   GtkWidget *printer_treeview;
136
137   GtkPrintCapabilities manual_capabilities;
138   GtkPrintCapabilities printer_capabilities;
139   
140   GtkTreeModel *printer_list;
141   GtkTreeModelFilter *printer_list_filter;
142
143   GtkPageSetup *page_setup;
144   gboolean page_setup_set;
145
146   GtkWidget *all_pages_radio;
147   GtkWidget *current_page_radio;
148   GtkWidget *page_range_radio;
149   GtkWidget *page_range_entry;
150   
151   GtkWidget *copies_spin;
152   GtkWidget *collate_check;
153   GtkWidget *reverse_check;
154   GtkWidget *collate_image;
155   GtkWidget *page_layout_preview;
156   GtkWidget *scale_spin;
157   GtkWidget *page_set_combo;
158   GtkWidget *print_now_radio;
159   GtkWidget *print_at_radio;
160   GtkWidget *print_at_entry;
161   GtkWidget *print_hold_radio;
162   GtkWidget *preview_button;
163   gboolean updating_print_at;
164   GtkPrinterOptionWidget *pages_per_sheet;
165   GtkPrinterOptionWidget *duplex;
166   GtkPrinterOptionWidget *paper_type;
167   GtkPrinterOptionWidget *paper_source;
168   GtkPrinterOptionWidget *output_tray;
169   GtkPrinterOptionWidget *job_prio;
170   GtkPrinterOptionWidget *billing_info;
171   GtkPrinterOptionWidget *cover_before;
172   GtkPrinterOptionWidget *cover_after;
173   GtkPrinterOptionWidget *number_up_layout;
174
175   GtkWidget *conflicts_widget;
176
177   GtkWidget *job_page;
178   GtkWidget *finishing_table;
179   GtkWidget *finishing_page;
180   GtkWidget *image_quality_table;
181   GtkWidget *image_quality_page;
182   GtkWidget *color_table;
183   GtkWidget *color_page;
184
185   GtkWidget *advanced_vbox;
186   GtkWidget *advanced_page;
187
188   GtkWidget *extension_point;
189
190   /* These are set initially on selected printer (either default printer, 
191    * printer taken from set settings, or user-selected), but when any setting 
192    * is changed by the user it is cleared.
193    */
194   GtkPrintSettings *initial_settings;
195
196   GtkPrinterOption *number_up_layout_n_option;
197   GtkPrinterOption *number_up_layout_2_option;
198   
199   /* This is the initial printer set by set_settings. We look for it in the
200    * added printers. We clear this whenever the user manually changes
201    * to another printer, when the user changes a setting or when we find
202    * this printer.
203    */
204   char *waiting_for_printer;
205   gboolean internal_printer_change;
206   
207   GList *print_backends;
208   
209   GtkPrinter *current_printer;
210   GtkPrinter *request_details_printer;
211   guint request_details_tag;
212   GtkPrinterOptionSet *options;
213   gulong options_changed_handler;
214   gulong mark_conflicts_id;
215
216   gchar *format_for_printer;
217   
218   gint current_page;
219 };
220
221 G_DEFINE_TYPE_WITH_CODE (GtkPrintUnixDialog, gtk_print_unix_dialog, GTK_TYPE_DIALOG,
222                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
223                                                 gtk_print_unix_dialog_buildable_init))
224
225 static GtkBuildableIface *parent_buildable_iface;
226
227 static gboolean
228 is_default_printer (GtkPrintUnixDialog *dialog,
229                     GtkPrinter         *printer)
230 {
231   GtkPrintUnixDialogPrivate *priv = dialog->priv;
232
233   if (priv->format_for_printer)
234     return strcmp (priv->format_for_printer,
235                    gtk_printer_get_name (printer)) == 0;
236  else
237    return gtk_printer_is_default (printer);
238 }
239
240 static void
241 gtk_print_unix_dialog_class_init (GtkPrintUnixDialogClass *class)
242 {
243   GObjectClass *object_class;
244   GtkWidgetClass *widget_class;
245
246   object_class = (GObjectClass *) class;
247   widget_class = (GtkWidgetClass *) class;
248
249   object_class->finalize = gtk_print_unix_dialog_finalize;
250   object_class->set_property = gtk_print_unix_dialog_set_property;
251   object_class->get_property = gtk_print_unix_dialog_get_property;
252
253   widget_class->style_set = gtk_print_unix_dialog_style_set;
254
255   g_object_class_install_property (object_class,
256                                    PROP_PAGE_SETUP,
257                                    g_param_spec_object ("page-setup",
258                                                         P_("Page Setup"),
259                                                         P_("The GtkPageSetup to use"),
260                                                         GTK_TYPE_PAGE_SETUP,
261                                                         GTK_PARAM_READWRITE));
262
263   g_object_class_install_property (object_class,
264                                    PROP_CURRENT_PAGE,
265                                    g_param_spec_int ("current-page",
266                                                      P_("Current Page"),
267                                                      P_("The current page in the document"),
268                                                      -1,
269                                                      G_MAXINT,
270                                                      -1,
271                                                      GTK_PARAM_READWRITE));
272
273   g_object_class_install_property (object_class,
274                                    PROP_PRINT_SETTINGS,
275                                    g_param_spec_object ("print-settings",
276                                                         P_("Print Settings"),
277                                                         P_("The GtkPrintSettings used for initializing the dialog"),
278                                                         GTK_TYPE_PRINT_SETTINGS,
279                                                         GTK_PARAM_READWRITE));
280
281   g_object_class_install_property (object_class,
282                                    PROP_SELECTED_PRINTER,
283                                    g_param_spec_object ("selected-printer",
284                                                         P_("Selected Printer"),
285                                                         P_("The GtkPrinter which is selected"),
286                                                         GTK_TYPE_PRINTER,
287                                                         GTK_PARAM_READABLE));
288   
289   
290   g_type_class_add_private (class, sizeof (GtkPrintUnixDialogPrivate));  
291 }
292
293 /* Returns a toplevel GtkWindow, or NULL if none */
294 static GtkWindow *
295 get_toplevel (GtkWidget *widget)
296 {
297   GtkWidget *toplevel = NULL;
298
299   toplevel = gtk_widget_get_toplevel (widget);
300   if (!GTK_WIDGET_TOPLEVEL (toplevel))
301     return NULL;
302   else
303     return GTK_WINDOW (toplevel);
304 }
305
306 static void
307 add_custom_button_to_dialog (GtkDialog   *dialog,
308                              const gchar *mnemonic_label,
309                              const gchar *stock_id,
310                              gint         response_id)
311 {
312   GtkWidget *button = NULL;
313
314   button = gtk_button_new_with_mnemonic (mnemonic_label);
315   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
316   gtk_button_set_image (GTK_BUTTON (button),
317                         gtk_image_new_from_stock (stock_id,
318                                                   GTK_ICON_SIZE_BUTTON));
319   gtk_widget_show (button);
320
321   gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, response_id);
322 }
323
324 /* This function handles error messages before printing.
325  */
326 static gboolean
327 error_dialogs (GtkPrintUnixDialog *print_dialog,
328                gint                print_dialog_response_id,
329                gpointer            data)
330 {
331   GtkPrintUnixDialogPrivate *priv = print_dialog->priv;
332   GtkPrinterOption          *option = NULL;
333   GtkPrinter                *printer = NULL;
334   GtkWindow                 *toplevel = NULL;
335   GtkWidget                 *dialog = NULL;
336   GFile                     *file = NULL;
337   gchar                     *basename = NULL;
338   gchar                     *dirname = NULL;
339   int                        response;
340
341   if (print_dialog != NULL && print_dialog_response_id == GTK_RESPONSE_OK)
342     {
343       printer = gtk_print_unix_dialog_get_selected_printer (print_dialog);
344
345       /* Shows overwrite confirmation dialog in the case of printing to file which
346        * already exists. */
347       if (printer != NULL && gtk_printer_is_virtual (printer))
348         {
349           option = gtk_printer_option_set_lookup (priv->options,
350                                                   "gtk-main-page-custom-input");
351
352           if (option != NULL &&
353               option->type == GTK_PRINTER_OPTION_TYPE_FILESAVE)
354             {
355               file = g_file_new_for_uri (option->value);
356
357               if (file != NULL &&
358                   g_file_query_exists (file, NULL))
359                 {
360                   toplevel = get_toplevel (GTK_WIDGET (print_dialog));
361
362                   basename = g_file_get_basename (file);
363                   dirname = g_file_get_parse_name (g_file_get_parent (file));
364
365                   dialog = gtk_message_dialog_new (toplevel,
366                                                    GTK_DIALOG_MODAL |
367                                                    GTK_DIALOG_DESTROY_WITH_PARENT,
368                                                    GTK_MESSAGE_QUESTION,
369                                                    GTK_BUTTONS_NONE,
370                                                    _("A file named \"%s\" already exists.  Do you want to replace it?"),
371                                                    basename);
372
373                   gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
374                                                             _("The file already exists in \"%s\".  Replacing it will "
375                                                             "overwrite its contents."),
376                                                             dirname);
377
378                   gtk_dialog_add_button (GTK_DIALOG (dialog),
379                                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
380                   add_custom_button_to_dialog (GTK_DIALOG (dialog),
381                                                _("_Replace"),
382                                                GTK_STOCK_PRINT,
383                                                GTK_RESPONSE_ACCEPT);
384                   gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
385                                                            GTK_RESPONSE_ACCEPT,
386                                                            GTK_RESPONSE_CANCEL,
387                                                            -1);
388                   gtk_dialog_set_default_response (GTK_DIALOG (dialog),
389                                                    GTK_RESPONSE_ACCEPT);
390
391                   if (toplevel->group)
392                     gtk_window_group_add_window (toplevel->group,
393                                                  GTK_WINDOW (dialog));
394
395                   response = gtk_dialog_run (GTK_DIALOG (dialog));
396
397                   gtk_widget_destroy (dialog);
398
399                   g_free (dirname);
400                   g_free (basename);
401
402                   if (response != GTK_RESPONSE_ACCEPT)
403                     {
404                       g_signal_stop_emission_by_name (print_dialog, "response");
405                       g_object_unref (file);
406                       return TRUE;
407                     }
408                 }
409
410               g_object_unref (file);
411             }
412         }
413     }
414   return FALSE;
415 }
416
417 static void
418 gtk_print_unix_dialog_init (GtkPrintUnixDialog *dialog)
419 {
420   GtkPrintUnixDialogPrivate *priv = dialog->priv;
421
422   priv = dialog->priv = GTK_PRINT_UNIX_DIALOG_GET_PRIVATE (dialog); 
423   priv->print_backends = NULL;
424   priv->current_page = -1;
425   priv->number_up_layout_n_option = NULL;
426   priv->number_up_layout_2_option = NULL;
427
428   priv->page_setup = gtk_page_setup_new ();
429   priv->page_setup_set = FALSE;
430
431   g_signal_connect (dialog, 
432                     "destroy", 
433                     (GCallback) gtk_print_unix_dialog_destroy, 
434                     NULL);
435
436   g_signal_connect (dialog,
437                     "response",
438                     (GCallback) error_dialogs,
439                     NULL);
440
441   priv->preview_button = gtk_button_new_from_stock (GTK_STOCK_PRINT_PREVIEW);
442   gtk_widget_show (priv->preview_button);
443    
444   gtk_dialog_add_action_widget (GTK_DIALOG (dialog), 
445                                 priv->preview_button, 
446                                 GTK_RESPONSE_APPLY);
447   gtk_dialog_add_buttons (GTK_DIALOG (dialog),
448                           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
449                           GTK_STOCK_PRINT, GTK_RESPONSE_OK,
450                           NULL);
451   gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
452                                            GTK_RESPONSE_APPLY,
453                                            GTK_RESPONSE_OK,
454                                            GTK_RESPONSE_CANCEL,
455                                            -1);
456
457   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
458   gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
459
460   populate_dialog (dialog);  
461 }
462
463 static void
464 gtk_print_unix_dialog_destroy (GtkPrintUnixDialog *dialog)
465 {
466   /* Make sure we don't destroy custom widgets owned by the backends */
467   clear_per_printer_ui (dialog);  
468 }
469
470 static void
471 disconnect_printer_details_request (GtkPrintUnixDialog *dialog)
472 {
473   GtkPrintUnixDialogPrivate *priv = dialog->priv;
474
475   if (priv->request_details_tag)
476     {
477       g_signal_handler_disconnect (priv->request_details_printer,
478                                    priv->request_details_tag);
479       priv->request_details_tag = 0;
480       g_object_unref (priv->request_details_printer);
481       priv->request_details_printer = NULL;
482     }
483 }
484
485 static void
486 gtk_print_unix_dialog_finalize (GObject *object)
487 {
488   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
489   GtkPrintUnixDialogPrivate *priv = dialog->priv;
490   GtkPrintBackend *backend;
491   GList *node;
492
493   unschedule_idle_mark_conflicts (dialog);
494   disconnect_printer_details_request (dialog);
495
496   if (priv->current_printer)
497     {
498       g_object_unref (priv->current_printer);
499       priv->current_printer = NULL;
500     }
501
502   if (priv->printer_list)
503     {
504       g_object_unref (priv->printer_list);
505       priv->printer_list = NULL;
506     }
507  
508   if (priv->printer_list_filter)
509     {
510       g_object_unref (priv->printer_list_filter);
511       priv->printer_list_filter = NULL;
512     }
513
514  
515   if (priv->options)
516     {
517       g_object_unref (priv->options);
518       priv->options = NULL;
519     }
520  
521   if (priv->number_up_layout_2_option)
522     {
523       priv->number_up_layout_2_option->choices[0] = NULL;
524       priv->number_up_layout_2_option->choices[1] = NULL;
525       g_free (priv->number_up_layout_2_option->choices_display[0]);
526       g_free (priv->number_up_layout_2_option->choices_display[1]);
527       priv->number_up_layout_2_option->choices_display[0] = NULL;
528       priv->number_up_layout_2_option->choices_display[1] = NULL;
529       g_object_unref (priv->number_up_layout_2_option);
530       priv->number_up_layout_2_option = NULL;
531     }
532
533   if (priv->number_up_layout_n_option)
534     {
535       g_object_unref (priv->number_up_layout_n_option);
536       priv->number_up_layout_n_option = NULL;
537     }
538
539  if (priv->page_setup)
540     {
541       g_object_unref (priv->page_setup);
542       priv->page_setup = NULL;
543     }
544
545   if (priv->initial_settings)
546     {
547       g_object_unref (priv->initial_settings);
548       priv->initial_settings = NULL;
549     }
550
551   g_free (priv->waiting_for_printer);
552   priv->waiting_for_printer = NULL;
553   
554   g_free (priv->format_for_printer);
555   priv->format_for_printer = NULL;
556
557   for (node = priv->print_backends; node != NULL; node = node->next)
558     {
559       backend = GTK_PRINT_BACKEND (node->data);
560
561       g_signal_handlers_disconnect_by_func (backend, printer_added_cb, dialog);
562       g_signal_handlers_disconnect_by_func (backend, printer_removed_cb, dialog);
563       g_signal_handlers_disconnect_by_func (backend, printer_status_cb, dialog);
564
565       gtk_print_backend_destroy (backend);
566       g_object_unref (backend);
567     }
568   
569   g_list_free (priv->print_backends);
570   priv->print_backends = NULL;
571   
572   G_OBJECT_CLASS (gtk_print_unix_dialog_parent_class)->finalize (object);
573 }
574
575 static void
576 printer_removed_cb (GtkPrintBackend    *backend, 
577                     GtkPrinter         *printer, 
578                     GtkPrintUnixDialog *dialog)
579 {
580   GtkPrintUnixDialogPrivate *priv = dialog->priv;
581   GtkTreeIter *iter;
582
583   iter = g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter");
584   gtk_list_store_remove (GTK_LIST_STORE (priv->printer_list), iter);
585 }
586
587 static void
588 gtk_print_unix_dialog_buildable_init (GtkBuildableIface *iface)
589 {
590   parent_buildable_iface = g_type_interface_peek_parent (iface);
591
592   iface->get_internal_child = gtk_print_unix_dialog_buildable_get_internal_child;
593 }
594
595 static GObject *
596 gtk_print_unix_dialog_buildable_get_internal_child (GtkBuildable *buildable,
597                                                     GtkBuilder   *builder,
598                                                     const gchar  *childname)
599 {
600   if (strcmp (childname, "notebook") == 0)
601     return G_OBJECT (GTK_PRINT_UNIX_DIALOG (buildable)->priv->notebook);
602
603   return parent_buildable_iface->get_internal_child (buildable, builder, childname);
604 }
605
606 /* This function controls "sensitive" property of GtkCellRenderer based on pause
607  * state of printers. */
608 void set_cell_sensitivity_func (GtkTreeViewColumn *tree_column,
609                                 GtkCellRenderer   *cell,
610                                 GtkTreeModel      *tree_model,
611                                 GtkTreeIter       *iter,
612                                 gpointer           data)
613 {
614   GtkPrinter *printer;
615   
616   gtk_tree_model_get (tree_model, iter, PRINTER_LIST_COL_PRINTER_OBJ, &printer, -1);
617
618   if (printer != NULL && !gtk_printer_is_accepting_jobs (printer))
619     g_object_set (cell,
620                   "sensitive", FALSE,
621                   NULL);
622   else
623     g_object_set (cell,
624                   "sensitive", TRUE,
625                   NULL);
626 }
627
628 static void
629 printer_status_cb (GtkPrintBackend    *backend, 
630                    GtkPrinter         *printer, 
631                    GtkPrintUnixDialog *dialog)
632 {
633   GtkPrintUnixDialogPrivate *priv = dialog->priv;
634   GtkTreeIter *iter;
635   GtkTreeSelection *selection;
636
637   iter = g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter");
638
639   gtk_list_store_set (GTK_LIST_STORE (priv->printer_list), iter,
640                       PRINTER_LIST_COL_ICON, gtk_printer_get_icon_name (printer),
641                       PRINTER_LIST_COL_STATE, gtk_printer_get_state_message (printer),
642                       PRINTER_LIST_COL_JOBS, gtk_printer_get_job_count (printer),
643                       PRINTER_LIST_COL_LOCATION, gtk_printer_get_location (printer),
644                       -1);
645
646   /* When the pause state change then we need to update sensitive property
647    * of GTK_RESPONSE_OK button inside of selected_printer_changed function. */
648   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
649   selected_printer_changed (selection, dialog);
650
651   if (gtk_print_backend_printer_list_is_done (backend) &&
652       gtk_printer_is_default (printer) &&
653       (gtk_tree_selection_count_selected_rows (selection) == 0))
654     set_active_printer (dialog, gtk_printer_get_name (printer));
655 }
656
657 static void
658 printer_added_cb (GtkPrintBackend    *backend, 
659                   GtkPrinter         *printer, 
660                   GtkPrintUnixDialog *dialog)
661 {
662   GtkPrintUnixDialogPrivate *priv = dialog->priv;
663   GtkTreeIter iter, filter_iter;
664   GtkTreeSelection *selection;
665   GtkTreePath *path;
666
667   gtk_list_store_append (GTK_LIST_STORE (priv->printer_list), &iter);
668   
669   g_object_set_data_full (G_OBJECT (printer), 
670                          "gtk-print-tree-iter", 
671                           gtk_tree_iter_copy (&iter),
672                           (GDestroyNotify) gtk_tree_iter_free);
673
674   gtk_list_store_set (GTK_LIST_STORE (priv->printer_list), &iter,
675                       PRINTER_LIST_COL_ICON, gtk_printer_get_icon_name (printer),
676                       PRINTER_LIST_COL_NAME, gtk_printer_get_name (printer),
677                       PRINTER_LIST_COL_STATE, gtk_printer_get_state_message (printer),
678                       PRINTER_LIST_COL_JOBS, gtk_printer_get_job_count (printer),
679                       PRINTER_LIST_COL_LOCATION, gtk_printer_get_location (printer),
680                       PRINTER_LIST_COL_PRINTER_OBJ, printer,
681                       -1);
682
683   gtk_tree_model_filter_convert_child_iter_to_iter (priv->printer_list_filter,
684                                                     &filter_iter, &iter);
685   path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->printer_list_filter), &filter_iter);
686
687   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
688   
689   if (priv->waiting_for_printer != NULL &&
690       strcmp (gtk_printer_get_name (printer),
691               priv->waiting_for_printer) == 0)
692     {
693       priv->internal_printer_change = TRUE;
694       gtk_tree_selection_select_iter (selection, &filter_iter);
695       gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->printer_treeview),
696                                     path, NULL, TRUE, 0.5, 0.0);
697       priv->internal_printer_change = FALSE;
698       g_free (priv->waiting_for_printer);
699       priv->waiting_for_printer = NULL;
700     }
701   else if (is_default_printer (dialog, printer) &&
702            gtk_tree_selection_count_selected_rows (selection) == 0)
703     {
704       priv->internal_printer_change = TRUE;
705       gtk_tree_selection_select_iter (selection, &filter_iter);
706       gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->printer_treeview),
707                                     path, NULL, TRUE, 0.5, 0.0);
708       priv->internal_printer_change = FALSE;
709     }
710
711   gtk_tree_path_free (path);
712 }
713
714 static void
715 printer_list_initialize (GtkPrintUnixDialog *dialog,
716                          GtkPrintBackend    *print_backend)
717 {
718   GList *list;
719   GList *node;
720
721   g_return_if_fail (print_backend != NULL);
722
723   g_signal_connect_object (print_backend, 
724                            "printer-added", 
725                            (GCallback) printer_added_cb, 
726                            G_OBJECT (dialog), 0);
727
728   g_signal_connect_object (print_backend, 
729                            "printer-removed", 
730                            (GCallback) printer_removed_cb, 
731                            G_OBJECT (dialog), 0);
732
733   g_signal_connect_object (print_backend, 
734                            "printer-status-changed", 
735                            (GCallback) printer_status_cb, 
736                            G_OBJECT (dialog), 0);
737
738   list = gtk_print_backend_get_printer_list (print_backend);
739
740   node = list;
741   while (node != NULL)
742     {
743       printer_added_cb (print_backend, node->data, dialog);
744       node = node->next;
745     }
746
747   g_list_free (list);
748 }
749
750 static void
751 load_print_backends (GtkPrintUnixDialog *dialog)
752 {
753   GtkPrintUnixDialogPrivate *priv = dialog->priv;
754   GList *node;
755
756   if (g_module_supported ())
757     priv->print_backends = gtk_print_backend_load_modules ();
758
759   for (node = priv->print_backends; node != NULL; node = node->next)
760     {
761       GtkPrintBackend *backend = node->data;
762       printer_list_initialize (dialog, backend);
763     }
764 }
765
766 static void
767 gtk_print_unix_dialog_set_property (GObject      *object,
768                                     guint         prop_id,
769                                     const GValue *value,
770                                     GParamSpec   *pspec)
771
772 {
773   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
774
775   switch (prop_id)
776     {
777     case PROP_PAGE_SETUP:
778       gtk_print_unix_dialog_set_page_setup (dialog, g_value_get_object (value));
779       break;
780     case PROP_CURRENT_PAGE:
781       gtk_print_unix_dialog_set_current_page (dialog, g_value_get_int (value));
782       break;
783     case PROP_PRINT_SETTINGS:
784       gtk_print_unix_dialog_set_settings (dialog, g_value_get_object (value));
785       break;
786     default:
787       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
788       break;
789     }
790 }
791
792 static void
793 gtk_print_unix_dialog_get_property (GObject    *object,
794                                     guint       prop_id,
795                                     GValue     *value,
796                                     GParamSpec *pspec)
797 {
798   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
799   GtkPrintUnixDialogPrivate *priv = dialog->priv;
800
801   switch (prop_id)
802     {
803     case PROP_PAGE_SETUP:
804       g_value_set_object (value, priv->page_setup);
805       break;
806     case PROP_CURRENT_PAGE:
807       g_value_set_int (value, priv->current_page);
808       break;
809     case PROP_PRINT_SETTINGS:
810       g_value_take_object (value, gtk_print_unix_dialog_get_settings (dialog));
811       break;
812     case PROP_SELECTED_PRINTER:
813       g_value_set_object (value, priv->current_printer);
814       break;
815     default:
816       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
817       break;
818     }
819 }
820
821 static gboolean
822 is_printer_active (GtkTreeModel       *model,
823                    GtkTreeIter        *iter,
824                    GtkPrintUnixDialog *dialog)
825 {
826   gboolean result;
827   GtkPrinter *printer;
828   GtkPrintUnixDialogPrivate *priv = dialog->priv;
829
830   gtk_tree_model_get (model,
831                       iter,
832                       PRINTER_LIST_COL_PRINTER_OBJ,
833                       &printer,
834                       -1);
835   
836   if (printer == NULL)
837     return FALSE;
838
839   result = gtk_printer_is_active (printer);
840   
841   if (result && 
842       priv->manual_capabilities & (GTK_PRINT_CAPABILITY_GENERATE_PDF |
843                                    GTK_PRINT_CAPABILITY_GENERATE_PS))
844     {
845        /* Check that the printer can handle at least one of the data 
846         * formats that the application supports.
847         */
848        result = ((priv->manual_capabilities & GTK_PRINT_CAPABILITY_GENERATE_PDF) &&
849                  gtk_printer_accepts_pdf (printer)) ||
850                 ((priv->manual_capabilities & GTK_PRINT_CAPABILITY_GENERATE_PS) &&
851                  gtk_printer_accepts_ps (printer));
852     }
853   
854   g_object_unref (printer);
855   
856   return result;
857 }
858
859 static gint
860 default_printer_list_sort_func (GtkTreeModel *model,
861                                 GtkTreeIter  *a,
862                                 GtkTreeIter  *b,
863                                 gpointer      user_data)
864 {
865   gchar *a_name;
866   gchar *b_name;
867   GtkPrinter *a_printer;
868   GtkPrinter *b_printer;
869   gint result;
870
871   gtk_tree_model_get (model, a, 
872                       PRINTER_LIST_COL_NAME, &a_name, 
873                       PRINTER_LIST_COL_PRINTER_OBJ, &a_printer,
874                       -1);
875   gtk_tree_model_get (model, b, 
876                       PRINTER_LIST_COL_NAME, &b_name,
877                       PRINTER_LIST_COL_PRINTER_OBJ, &b_printer,
878                       -1);
879
880   if (a_printer == NULL && b_printer == NULL)
881     result = 0;
882   else if (a_printer == NULL)
883    result = G_MAXINT;
884   else if (b_printer == NULL)
885    result = G_MININT;
886   else if (gtk_printer_is_virtual (a_printer) && gtk_printer_is_virtual (b_printer))
887     result = 0;
888   else if (gtk_printer_is_virtual (a_printer) && !gtk_printer_is_virtual (b_printer))
889     result = G_MININT;
890   else if (!gtk_printer_is_virtual (a_printer) && gtk_printer_is_virtual (b_printer))
891     result = G_MAXINT;
892   else if (a_name == NULL && b_name == NULL)
893     result = 0;
894   else if (a_name == NULL && b_name != NULL)
895     result = 1;
896   else if (a_name != NULL && b_name == NULL)
897     result = -1;
898   else
899     result = g_ascii_strcasecmp (a_name, b_name);
900
901   g_free (a_name);
902   g_free (b_name);
903   g_object_unref (a_printer);
904   g_object_unref (b_printer);
905
906   return result;
907 }
908
909
910 static void
911 create_printer_list_model (GtkPrintUnixDialog *dialog)
912 {
913   GtkPrintUnixDialogPrivate *priv = dialog->priv;
914   GtkListStore *model;
915   GtkTreeSortable *sort;
916
917   model = gtk_list_store_new (PRINTER_LIST_N_COLS,
918                               G_TYPE_STRING,
919                               G_TYPE_STRING, 
920                               G_TYPE_STRING, 
921                               G_TYPE_INT, 
922                               G_TYPE_STRING,
923                               G_TYPE_OBJECT);
924
925   priv->printer_list = (GtkTreeModel *)model;
926   priv->printer_list_filter = (GtkTreeModelFilter *) gtk_tree_model_filter_new ((GtkTreeModel *)model,
927                                                                                         NULL);
928
929   gtk_tree_model_filter_set_visible_func (priv->printer_list_filter,
930                                           (GtkTreeModelFilterVisibleFunc) is_printer_active,
931                                           dialog,
932                                           NULL);
933
934   sort = GTK_TREE_SORTABLE (model);
935   gtk_tree_sortable_set_default_sort_func (sort,
936                                            default_printer_list_sort_func,
937                                            NULL,
938                                            NULL);
939  
940   gtk_tree_sortable_set_sort_column_id (sort,
941                                         GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
942                                         GTK_SORT_ASCENDING);
943
944 }
945
946
947 static GtkWidget *
948 wrap_in_frame (const gchar *label, 
949                GtkWidget   *child)
950 {
951   GtkWidget *frame, *alignment, *label_widget;
952   gchar *bold_text;
953
954   label_widget = gtk_label_new (NULL);
955   gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
956   gtk_widget_show (label_widget);
957   
958   bold_text = g_markup_printf_escaped ("<b>%s</b>", label);
959   gtk_label_set_markup (GTK_LABEL (label_widget), bold_text);
960   g_free (bold_text);
961   
962   frame = gtk_vbox_new (FALSE, 6);
963   gtk_box_pack_start (GTK_BOX (frame), label_widget, FALSE, FALSE, 0);
964   
965   alignment = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
966   gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
967                              0, 0, 12, 0);
968   gtk_box_pack_start (GTK_BOX (frame), alignment, FALSE, FALSE, 0);
969
970   gtk_container_add (GTK_CONTAINER (alignment), child);
971
972   gtk_widget_show (frame);
973   gtk_widget_show (alignment);
974   
975   return frame;
976 }
977
978 static gboolean
979 setup_option (GtkPrintUnixDialog     *dialog,
980               const gchar            *option_name,
981               GtkPrinterOptionWidget *widget)
982 {
983   GtkPrintUnixDialogPrivate *priv = dialog->priv;
984   GtkPrinterOption *option;
985
986   option = gtk_printer_option_set_lookup (priv->options, option_name);
987   gtk_printer_option_widget_set_source (widget, option);
988
989   return option != NULL;
990 }
991
992 static void
993 add_option_to_extension_point (GtkPrinterOption *option,
994                                gpointer          data)
995 {
996   GtkWidget *extension_point = data;
997   GtkWidget *widget;
998
999   widget = gtk_printer_option_widget_new (option);
1000   gtk_widget_show (widget);
1001    
1002   if (gtk_printer_option_widget_has_external_label (GTK_PRINTER_OPTION_WIDGET (widget)))
1003     {
1004       GtkWidget *label, *hbox;
1005       
1006       label = gtk_printer_option_widget_get_external_label (GTK_PRINTER_OPTION_WIDGET (widget));
1007       gtk_widget_show (label);
1008       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1009       gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
1010       
1011       hbox = gtk_hbox_new (FALSE, 12);
1012       gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1013       gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
1014       gtk_widget_show (hbox);
1015       
1016       gtk_box_pack_start (GTK_BOX (extension_point), hbox, FALSE, FALSE, 0);
1017     }
1018   else
1019     gtk_box_pack_start (GTK_BOX (extension_point), widget, FALSE, FALSE, 0);
1020 }
1021
1022 static void
1023 add_option_to_table (GtkPrinterOption *option,
1024                      gpointer          user_data)
1025 {
1026   GtkTable *table;
1027   GtkWidget *label, *widget;
1028   gint row;
1029
1030   table = GTK_TABLE (user_data);
1031   
1032   if (g_str_has_prefix (option->name, "gtk-"))
1033     return;
1034   
1035   widget = gtk_printer_option_widget_new (option);
1036   gtk_widget_show (widget);
1037
1038   row = table->nrows;
1039   gtk_table_resize (table, table->nrows + 1, 2);
1040   
1041   if (gtk_printer_option_widget_has_external_label (GTK_PRINTER_OPTION_WIDGET (widget)))
1042     {
1043       label = gtk_printer_option_widget_get_external_label (GTK_PRINTER_OPTION_WIDGET (widget));
1044       gtk_widget_show (label);
1045
1046       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1047       gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
1048
1049       gtk_table_attach (table, label,
1050                         0, 1, row - 1 , row,  GTK_FILL, 0, 0, 0);
1051       
1052       gtk_table_attach (table, widget,
1053                         1, 2, row - 1, row,  GTK_FILL, 0, 0, 0);
1054     }
1055   else
1056     gtk_table_attach (table, widget,
1057                       0, 2, row - 1, row,  GTK_FILL, 0, 0, 0);
1058 }
1059
1060
1061 static void
1062 setup_page_table (GtkPrinterOptionSet *options,
1063                   const gchar         *group,
1064                   GtkWidget           *table,
1065                   GtkWidget           *page)
1066 {
1067   gtk_printer_option_set_foreach_in_group (options, group,
1068                                            add_option_to_table,
1069                                            table);
1070   if (GTK_TABLE (table)->nrows == 1)
1071     gtk_widget_hide (page);
1072   else
1073     gtk_widget_show (page);
1074 }
1075
1076 static void
1077 update_print_at_option (GtkPrintUnixDialog *dialog)
1078 {
1079   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1080   GtkPrinterOption *option;
1081   
1082   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time");
1083
1084   if (option == NULL)
1085     return;
1086   
1087   if (priv->updating_print_at)
1088     return;
1089
1090   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->print_at_radio)))
1091     gtk_printer_option_set (option, "at");
1092   else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->print_hold_radio)))
1093     gtk_printer_option_set (option, "on-hold");
1094   else
1095     gtk_printer_option_set (option, "now");
1096
1097   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time-text");
1098   if (option != NULL)
1099     {
1100       const char *text = gtk_entry_get_text (GTK_ENTRY (priv->print_at_entry));
1101       gtk_printer_option_set (option, text);
1102     }
1103 }
1104
1105
1106 static gboolean
1107 setup_print_at (GtkPrintUnixDialog *dialog)
1108 {
1109   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1110   GtkPrinterOption *option;
1111
1112   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time");
1113
1114   if (option == NULL)
1115     {
1116       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_now_radio),
1117                                     TRUE);
1118       gtk_widget_set_sensitive (priv->print_at_radio, FALSE);
1119       gtk_widget_set_sensitive (priv->print_at_entry, FALSE);
1120       gtk_widget_set_sensitive (priv->print_hold_radio, FALSE);
1121       gtk_entry_set_text (GTK_ENTRY (priv->print_at_entry), "");
1122       return FALSE;
1123     }
1124
1125   priv->updating_print_at = TRUE;
1126
1127   gtk_widget_set_sensitive (priv->print_at_entry, FALSE);
1128   gtk_widget_set_sensitive (priv->print_at_radio,
1129                             gtk_printer_option_has_choice (option, "at"));
1130
1131   gtk_widget_set_sensitive (priv->print_hold_radio,
1132                             gtk_printer_option_has_choice (option, "on-hold"));
1133
1134   update_print_at_option (dialog);
1135
1136   if (strcmp (option->value, "at") == 0)
1137     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_at_radio),
1138                                   TRUE);
1139   else if (strcmp (option->value, "on-hold") == 0)
1140     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_hold_radio),
1141                                   TRUE);
1142   else
1143     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_now_radio),
1144                                   TRUE);
1145
1146   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time-text");
1147   if (option != NULL)
1148     gtk_entry_set_text (GTK_ENTRY (priv->print_at_entry), option->value);
1149
1150
1151   priv->updating_print_at = FALSE;
1152
1153   return TRUE;
1154 }
1155
1156 static void
1157 update_dialog_from_settings (GtkPrintUnixDialog *dialog)
1158 {
1159   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1160   GList *groups, *l;
1161   gchar *group;
1162   GtkWidget *table, *frame;
1163   gboolean has_advanced, has_job;
1164  
1165   if (priv->current_printer == NULL)
1166     {
1167        clear_per_printer_ui (dialog);
1168        gtk_widget_hide (priv->job_page);
1169        gtk_widget_hide (priv->advanced_page);
1170        gtk_widget_hide (priv->image_quality_page);
1171        gtk_widget_hide (priv->finishing_page);
1172        gtk_widget_hide (priv->color_page);
1173        gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
1174
1175        return;
1176     }
1177  
1178   setup_option (dialog, "gtk-n-up", priv->pages_per_sheet);
1179   setup_option (dialog, "gtk-n-up-layout", priv->number_up_layout);
1180   setup_option (dialog, "gtk-duplex", priv->duplex);
1181   setup_option (dialog, "gtk-paper-type", priv->paper_type);
1182   setup_option (dialog, "gtk-paper-source", priv->paper_source);
1183   setup_option (dialog, "gtk-output-tray", priv->output_tray);
1184
1185   has_job = FALSE;
1186   has_job |= setup_option (dialog, "gtk-job-prio", priv->job_prio);
1187   has_job |= setup_option (dialog, "gtk-billing-info", priv->billing_info);
1188   has_job |= setup_option (dialog, "gtk-cover-before", priv->cover_before);
1189   has_job |= setup_option (dialog, "gtk-cover-after", priv->cover_after);
1190   has_job |= setup_print_at (dialog);
1191   
1192   if (has_job)
1193     gtk_widget_show (priv->job_page);
1194   else
1195     gtk_widget_hide (priv->job_page);
1196
1197   
1198   setup_page_table (priv->options,
1199                     "ImageQualityPage",
1200                     priv->image_quality_table,
1201                     priv->image_quality_page);
1202   
1203   setup_page_table (priv->options,
1204                     "FinishingPage",
1205                     priv->finishing_table,
1206                     priv->finishing_page);
1207
1208   setup_page_table (priv->options,
1209                     "ColorPage",
1210                     priv->color_table,
1211                     priv->color_page);
1212
1213   gtk_printer_option_set_foreach_in_group (priv->options,
1214                                            "GtkPrintDialogExtension",
1215                                            add_option_to_extension_point,
1216                                            priv->extension_point);
1217
1218   /* Put the rest of the groups in the advanced page */
1219   groups = gtk_printer_option_set_get_groups (priv->options);
1220
1221   has_advanced = FALSE;
1222   for (l = groups; l != NULL; l = l->next)
1223     {
1224       group = l->data;
1225
1226       if (group == NULL)
1227         continue;
1228       
1229       if (strcmp (group, "ImageQualityPage") == 0 ||
1230           strcmp (group, "ColorPage") == 0 ||
1231           strcmp (group, "FinishingPage") == 0 ||
1232           strcmp (group, "GtkPrintDialogExtension") == 0)
1233         continue;
1234
1235       table = gtk_table_new (1, 2, FALSE);
1236       gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1237       gtk_table_set_col_spacings (GTK_TABLE (table), 12);
1238       
1239       gtk_printer_option_set_foreach_in_group (priv->options,
1240                                                group,
1241                                                add_option_to_table,
1242                                                table);
1243       if (GTK_TABLE (table)->nrows == 1)
1244         gtk_widget_destroy (table);
1245       else
1246         {
1247           has_advanced = TRUE;
1248           frame = wrap_in_frame (group, table);
1249           gtk_widget_show (table);
1250           gtk_widget_show (frame);
1251           
1252           gtk_box_pack_start (GTK_BOX (priv->advanced_vbox),
1253                               frame, FALSE, FALSE, 0);
1254         }
1255     }
1256
1257   if (has_advanced)
1258     gtk_widget_show (priv->advanced_page);
1259   else
1260     gtk_widget_hide (priv->advanced_page);
1261
1262   
1263   g_list_foreach (groups, (GFunc) g_free, NULL);
1264   g_list_free (groups);
1265 }
1266
1267 static void
1268 update_dialog_from_capabilities (GtkPrintUnixDialog *dialog)
1269 {
1270   GtkPrintCapabilities caps;
1271   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1272   gboolean can_collate;
1273   const gchar *copies;
1274
1275   copies = gtk_entry_get_text (GTK_ENTRY (priv->copies_spin));
1276   can_collate = (*copies != '\0' && atoi (copies) > 1);
1277
1278   caps = priv->manual_capabilities | priv->printer_capabilities;
1279
1280   gtk_widget_set_sensitive (priv->page_set_combo,
1281                             caps & GTK_PRINT_CAPABILITY_PAGE_SET);
1282   gtk_widget_set_sensitive (priv->copies_spin,
1283                             caps & GTK_PRINT_CAPABILITY_COPIES);
1284   gtk_widget_set_sensitive (priv->collate_check,
1285                             can_collate && 
1286                             (caps & GTK_PRINT_CAPABILITY_COLLATE));
1287   gtk_widget_set_sensitive (priv->reverse_check,
1288                             caps & GTK_PRINT_CAPABILITY_REVERSE);
1289   gtk_widget_set_sensitive (priv->scale_spin,
1290                             caps & GTK_PRINT_CAPABILITY_SCALE);
1291   gtk_widget_set_sensitive (GTK_WIDGET (priv->pages_per_sheet),
1292                             caps & GTK_PRINT_CAPABILITY_NUMBER_UP);
1293
1294   if (caps & GTK_PRINT_CAPABILITY_PREVIEW)
1295     gtk_widget_show (priv->preview_button);
1296   else
1297     gtk_widget_hide (priv->preview_button);
1298
1299   update_collate_icon (NULL, dialog);
1300
1301   gtk_tree_model_filter_refilter (priv->printer_list_filter);
1302 }
1303
1304 static void
1305 mark_conflicts (GtkPrintUnixDialog *dialog)
1306 {
1307   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1308   GtkPrinter *printer;
1309   gboolean have_conflict;
1310
1311   have_conflict = FALSE;
1312
1313   printer = priv->current_printer;
1314
1315   if (printer)
1316     {
1317
1318       g_signal_handler_block (priv->options,
1319                               priv->options_changed_handler);
1320       
1321       gtk_printer_option_set_clear_conflicts (priv->options);
1322       
1323       have_conflict = _gtk_printer_mark_conflicts (printer,
1324                                                    priv->options);
1325       
1326       g_signal_handler_unblock (priv->options,
1327                                 priv->options_changed_handler);
1328     }
1329
1330   if (have_conflict)
1331     gtk_widget_show (priv->conflicts_widget);
1332   else
1333     gtk_widget_hide (priv->conflicts_widget);
1334 }
1335
1336 static gboolean
1337 mark_conflicts_callback (gpointer data)
1338 {
1339   GtkPrintUnixDialog *dialog = data;
1340   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1341
1342   priv->mark_conflicts_id = 0;
1343
1344   mark_conflicts (dialog);
1345
1346   return FALSE;
1347 }
1348
1349 static void
1350 unschedule_idle_mark_conflicts (GtkPrintUnixDialog *dialog)
1351 {
1352   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1353
1354   if (priv->mark_conflicts_id != 0)
1355     {
1356       g_source_remove (priv->mark_conflicts_id);
1357       priv->mark_conflicts_id = 0;
1358     }
1359 }
1360
1361 static void
1362 schedule_idle_mark_conflicts (GtkPrintUnixDialog *dialog)
1363 {
1364   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1365
1366   if (priv->mark_conflicts_id != 0)
1367     return;
1368
1369   priv->mark_conflicts_id = gdk_threads_add_idle (mark_conflicts_callback,
1370                                         dialog);
1371 }
1372
1373 static void
1374 options_changed_cb (GtkPrintUnixDialog *dialog)
1375 {
1376   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1377
1378   schedule_idle_mark_conflicts (dialog);
1379
1380   if (priv->initial_settings)
1381     {
1382       g_object_unref (priv->initial_settings);
1383       priv->initial_settings = NULL;
1384     }
1385
1386   g_free (priv->waiting_for_printer);
1387   priv->waiting_for_printer = NULL;
1388 }
1389
1390 static void
1391 remove_custom_widget (GtkWidget    *widget,
1392                       GtkContainer *container)
1393 {
1394   gtk_container_remove (container, widget);
1395 }
1396
1397 static void
1398 extension_point_clear_children (GtkContainer *container)
1399 {
1400   gtk_container_foreach (container,
1401                          (GtkCallback)remove_custom_widget,
1402                          container);
1403 }
1404
1405 static void
1406 clear_per_printer_ui (GtkPrintUnixDialog *dialog)
1407 {
1408   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1409
1410   gtk_container_foreach (GTK_CONTAINER (priv->finishing_table),
1411                          (GtkCallback)gtk_widget_destroy,
1412                          NULL);
1413   gtk_table_resize (GTK_TABLE (priv->finishing_table), 1, 2);
1414   gtk_container_foreach (GTK_CONTAINER (priv->image_quality_table),
1415                          (GtkCallback)gtk_widget_destroy,
1416                          NULL);
1417   gtk_table_resize (GTK_TABLE (priv->image_quality_table), 1, 2);
1418   gtk_container_foreach (GTK_CONTAINER (priv->color_table),
1419                          (GtkCallback)gtk_widget_destroy,
1420                          NULL);
1421   gtk_table_resize (GTK_TABLE (priv->color_table), 1, 2);
1422   gtk_container_foreach (GTK_CONTAINER (priv->advanced_vbox),
1423                          (GtkCallback)gtk_widget_destroy,
1424                          NULL);
1425   extension_point_clear_children (GTK_CONTAINER (priv->extension_point));
1426 }
1427
1428 static void
1429 printer_details_acquired (GtkPrinter         *printer,
1430                           gboolean            success,
1431                           GtkPrintUnixDialog *dialog)
1432 {
1433   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1434
1435   disconnect_printer_details_request (dialog);
1436   
1437   if (success)
1438     {
1439       GtkTreeSelection *selection;
1440       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
1441       
1442       selected_printer_changed (selection, dialog);
1443     }
1444 }
1445
1446 static void
1447 selected_printer_changed (GtkTreeSelection   *selection,
1448                           GtkPrintUnixDialog *dialog)
1449 {
1450   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1451   GtkPrinter *printer;
1452   GtkTreeIter iter, filter_iter;
1453
1454   /* Whenever the user selects a printer we stop looking for
1455      the printer specified in the initial settings */
1456   if (priv->waiting_for_printer &&
1457       !priv->internal_printer_change)
1458     {
1459       g_free (priv->waiting_for_printer);
1460       priv->waiting_for_printer = NULL;
1461     }
1462
1463   disconnect_printer_details_request (dialog);
1464
1465   printer = NULL;
1466   if (gtk_tree_selection_get_selected (selection, NULL, &filter_iter))
1467     {
1468       gtk_tree_model_filter_convert_iter_to_child_iter (priv->printer_list_filter,
1469                                                         &iter,
1470                                                         &filter_iter);
1471
1472       gtk_tree_model_get (priv->printer_list, &iter,
1473                           PRINTER_LIST_COL_PRINTER_OBJ, &printer,
1474                           -1);
1475     }
1476
1477   /* sets GTK_RESPONSE_OK button sensitive/insensitive depending on whether the printer 
1478    * accepts/rejects jobs */
1479   if (printer != NULL)
1480     {
1481       if (!gtk_printer_is_accepting_jobs (printer))
1482         {
1483           gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
1484         }
1485       else
1486         {
1487           if (priv->current_printer == printer && gtk_printer_has_details (printer))
1488             gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
1489         }
1490     }
1491   
1492   if (printer != NULL && !gtk_printer_has_details (printer))
1493     {
1494       gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
1495       priv->request_details_tag =
1496         g_signal_connect (printer, "details-acquired",
1497                           G_CALLBACK (printer_details_acquired), dialog);
1498       /* take the reference */
1499       priv->request_details_printer = printer;
1500       gtk_printer_request_details (printer);
1501       return;
1502     }
1503   
1504   if (printer == priv->current_printer)
1505     {
1506       if (printer)
1507         g_object_unref (printer);
1508       return;
1509     }
1510
1511   if (priv->options)
1512     {
1513       g_object_unref (priv->options);
1514       priv->options = NULL;  
1515
1516       clear_per_printer_ui (dialog);
1517     }
1518
1519   if (priv->current_printer)
1520     {
1521       g_object_unref (priv->current_printer);
1522     }
1523
1524   priv->printer_capabilities = 0;
1525   
1526   if (gtk_printer_is_accepting_jobs (printer))
1527     gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
1528   priv->current_printer = printer;
1529
1530   if (printer != NULL)
1531     {
1532       if (!priv->page_setup_set)
1533         {
1534           /* if no explicit page setup has been set, use the printer default */   
1535           GtkPageSetup *page_setup;
1536
1537           page_setup = gtk_printer_get_default_page_size (printer);
1538
1539           if (!page_setup)
1540             page_setup = gtk_page_setup_new ();
1541
1542           g_object_unref (priv->page_setup);
1543           priv->page_setup = page_setup;
1544         }
1545
1546       priv->printer_capabilities = gtk_printer_get_capabilities (printer);
1547       priv->options = _gtk_printer_get_options (printer, 
1548                                                 priv->initial_settings,
1549                                                 priv->page_setup,
1550                                                 priv->manual_capabilities);
1551   
1552       priv->options_changed_handler = 
1553         g_signal_connect_swapped (priv->options, "changed", G_CALLBACK (options_changed_cb), dialog);
1554     }
1555
1556   update_dialog_from_settings (dialog);
1557   update_dialog_from_capabilities (dialog);
1558
1559   g_object_notify ( G_OBJECT(dialog), "selected-printer");
1560 }
1561
1562 static void
1563 update_collate_icon (GtkToggleButton    *toggle_button,
1564                      GtkPrintUnixDialog *dialog)
1565 {
1566   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1567
1568   gtk_widget_queue_draw (priv->collate_image);
1569 }
1570
1571 static void
1572 paint_page (GtkWidget *widget,
1573             cairo_t   *cr, 
1574             gfloat     scale,
1575             gint       x_offset, 
1576             gint       y_offset,
1577             gchar     *text,
1578             gint       text_x)
1579 {
1580   gint x, y, width, height;
1581   gint text_y, linewidth;
1582
1583   x = x_offset * scale;
1584   y = y_offset * scale;
1585   width = 20 * scale;
1586   height = 26 * scale;
1587
1588   linewidth = 2;
1589   text_y = 21;
1590
1591   gdk_cairo_set_source_color (cr, &widget->style->base[GTK_STATE_NORMAL]);
1592   cairo_rectangle (cr, x, y, width, height);
1593   cairo_fill (cr);
1594
1595   gdk_cairo_set_source_color (cr, &widget->style->text[GTK_STATE_NORMAL]);
1596   cairo_set_line_width (cr, linewidth);
1597   cairo_rectangle (cr, x + linewidth/2.0, y + linewidth/2.0, width - linewidth, height - linewidth);
1598   cairo_stroke (cr);
1599
1600   cairo_select_font_face (cr, "Sans", 
1601                           CAIRO_FONT_SLANT_NORMAL,
1602                           CAIRO_FONT_WEIGHT_NORMAL);
1603   cairo_set_font_size (cr, (gint)(9 * scale));
1604   cairo_move_to (cr, x + (gint)(text_x * scale), y + (gint)(text_y * scale));
1605   cairo_show_text (cr, text);
1606 }
1607
1608
1609 static gboolean
1610 draw_collate_cb (GtkWidget          *widget,
1611                  GdkEventExpose     *event,
1612                  GtkPrintUnixDialog *dialog)
1613 {
1614   GtkSettings *settings;
1615   cairo_t *cr;
1616   gint size;
1617   gfloat scale;
1618   gboolean collate, reverse, rtl;
1619   gint copies;
1620   gint text_x;
1621
1622   collate = dialog_get_collate (dialog);
1623   reverse = dialog_get_reverse (dialog);
1624   copies = dialog_get_n_copies (dialog);
1625
1626   rtl = (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_RTL);
1627
1628   settings = gtk_widget_get_settings (widget);
1629   gtk_icon_size_lookup_for_settings (settings,
1630                                      GTK_ICON_SIZE_DIALOG,
1631                                      &size,
1632                                      NULL);
1633   scale = size / 48.0;
1634   text_x = rtl ? 4 : 11;
1635
1636   cr = gdk_cairo_create (widget->window);
1637
1638   cairo_translate (cr, widget->allocation.x, widget->allocation.y);
1639
1640   if (copies == 1)
1641     {
1642       paint_page (widget, cr, scale, rtl ? 40: 15, 5, reverse ? "1" : "2", text_x);
1643       paint_page (widget, cr, scale, rtl ? 50: 5, 15, reverse ? "2" : "1", text_x);
1644     }
1645   else
1646     {
1647       paint_page (widget, cr, scale, rtl ? 40: 15, 5, collate == reverse ? "1" : "2", text_x);
1648       paint_page (widget, cr, scale, rtl ? 50: 5, 15, reverse ? "2" : "1", text_x);
1649
1650       paint_page (widget, cr, scale, rtl ? 5 : 50, 5, reverse ? "1" : "2", text_x);
1651       paint_page (widget, cr, scale, rtl ? 15 : 40, 15, collate == reverse ? "2" : "1", text_x);
1652     }
1653
1654   cairo_destroy (cr);
1655
1656   return TRUE;
1657 }
1658
1659 static void
1660 gtk_print_unix_dialog_style_set (GtkWidget *widget,
1661                                  GtkStyle  *previous_style)
1662 {
1663   GTK_WIDGET_CLASS (gtk_print_unix_dialog_parent_class)->style_set (widget, previous_style);
1664
1665   if (gtk_widget_has_screen (widget))
1666     {
1667       GtkPrintUnixDialog *dialog = (GtkPrintUnixDialog *)widget;
1668       GtkPrintUnixDialogPrivate *priv = dialog->priv;
1669       GtkSettings *settings;
1670       gint size;
1671       gfloat scale;
1672       
1673       settings = gtk_widget_get_settings (widget);
1674       gtk_icon_size_lookup_for_settings (settings,
1675                                          GTK_ICON_SIZE_DIALOG,
1676                                          &size,
1677                                          NULL);
1678       scale = size / 48.0;
1679
1680       gtk_widget_set_size_request (priv->collate_image,
1681                                    (50 + 20) * scale,
1682                                    (15 + 26) * scale);
1683     }
1684 }
1685
1686 static void
1687 update_entry_sensitivity (GtkWidget *button,
1688                           GtkWidget *range)
1689 {
1690   gboolean active;
1691
1692   active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
1693
1694   gtk_widget_set_sensitive (range, active);
1695
1696   if (active)
1697     gtk_widget_grab_focus (range);
1698 }
1699
1700 static void
1701 emit_ok_response (GtkTreeView       *tree_view,
1702                   GtkTreePath       *path,
1703                   GtkTreeViewColumn *column,
1704                   gpointer          *user_data)
1705 {
1706   GtkPrintUnixDialog *print_dialog;
1707
1708   print_dialog = (GtkPrintUnixDialog *) user_data;
1709
1710   gtk_dialog_response (GTK_DIALOG (print_dialog), GTK_RESPONSE_OK);
1711 }
1712
1713 static void
1714 create_main_page (GtkPrintUnixDialog *dialog)
1715 {
1716   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1717   GtkWidget *main_vbox, *label, *vbox, *hbox;
1718   GtkWidget *scrolled, *treeview, *frame, *table;
1719   GtkWidget *entry, *spinbutton;
1720   GtkWidget *radio, *check, *image;
1721   GtkCellRenderer *renderer;
1722   GtkTreeViewColumn *column;
1723   GtkTreeSelection *selection;
1724   GtkWidget *custom_input;
1725   const gchar *range_tooltip;
1726
1727   main_vbox = gtk_vbox_new (FALSE, 18);
1728   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
1729   gtk_widget_show (main_vbox);
1730
1731   vbox = gtk_vbox_new (FALSE, 6);
1732   gtk_box_pack_start (GTK_BOX (main_vbox), vbox, TRUE, TRUE, 0);
1733   gtk_widget_show (vbox);
1734
1735   scrolled = gtk_scrolled_window_new (NULL, NULL);
1736   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1737                                   GTK_POLICY_AUTOMATIC,
1738                                   GTK_POLICY_AUTOMATIC);
1739   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
1740                                        GTK_SHADOW_IN);
1741   gtk_widget_show (scrolled);
1742   gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
1743
1744   treeview = gtk_tree_view_new_with_model ((GtkTreeModel *) priv->printer_list_filter);
1745   priv->printer_treeview = treeview;
1746   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), TRUE);
1747   gtk_tree_view_set_search_column (GTK_TREE_VIEW (treeview), PRINTER_LIST_COL_NAME);
1748   gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
1749   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
1750   gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1751   g_signal_connect (selection, "changed", G_CALLBACK (selected_printer_changed), dialog);
1752  
1753   renderer = gtk_cell_renderer_pixbuf_new ();
1754   column = gtk_tree_view_column_new_with_attributes ("",
1755                                                      renderer,
1756                                                      "icon-name",
1757                                                      PRINTER_LIST_COL_ICON,
1758                                                      NULL);
1759   gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, NULL, NULL);
1760   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1761
1762   renderer = gtk_cell_renderer_text_new ();
1763   column = gtk_tree_view_column_new_with_attributes (_("Printer"),
1764                                                      renderer,
1765                                                      "text",
1766                                                      PRINTER_LIST_COL_NAME,
1767                                                      NULL);
1768   gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, NULL, NULL);
1769   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1770   
1771   renderer = gtk_cell_renderer_text_new ();
1772   /* Translators: this is the header for the location column in the print dialog */
1773   column = gtk_tree_view_column_new_with_attributes (_("Location"),
1774                                                      renderer,
1775                                                      "text",
1776                                                      PRINTER_LIST_COL_LOCATION,
1777                                                      NULL);
1778   gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, NULL, NULL);
1779   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1780
1781   renderer = gtk_cell_renderer_text_new ();
1782   g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
1783   /* Translators: this is the header for the printer status column in the print dialog */
1784   column = gtk_tree_view_column_new_with_attributes (_("Status"),
1785                                                      renderer,
1786                                                      "text",
1787                                                      PRINTER_LIST_COL_STATE,
1788                                                      NULL);
1789   gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, NULL, NULL);
1790   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1791
1792   g_signal_connect (GTK_TREE_VIEW (treeview), "row-activated", G_CALLBACK (emit_ok_response), dialog);
1793   
1794   gtk_widget_show (treeview);
1795   gtk_container_add (GTK_CONTAINER (scrolled), treeview);
1796
1797   custom_input = gtk_hbox_new (FALSE, 18);
1798   gtk_widget_show (custom_input);
1799   gtk_box_pack_start (GTK_BOX (vbox), custom_input, FALSE, FALSE, 0);
1800   priv->extension_point = custom_input;
1801
1802   hbox = gtk_hbox_new (FALSE, 18);
1803   gtk_widget_show (hbox);
1804   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
1805
1806   table = gtk_table_new (3, 2, FALSE);
1807   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1808   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
1809   frame = wrap_in_frame (_("Range"), table);
1810   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
1811   gtk_widget_show (table);
1812
1813   radio = gtk_radio_button_new_with_mnemonic (NULL, _("_All Pages"));
1814   priv->all_pages_radio = radio;
1815   gtk_widget_show (radio);
1816   gtk_table_attach (GTK_TABLE (table), radio,
1817                     0, 2, 0, 1,  GTK_FILL, 0,
1818                     0, 0);
1819   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
1820                                               _("C_urrent Page"));
1821   if (priv->current_page == -1)
1822     gtk_widget_set_sensitive (radio, FALSE);    
1823   priv->current_page_radio = radio;
1824   gtk_widget_show (radio);
1825   gtk_table_attach (GTK_TABLE (table), radio,
1826                     0, 2, 1, 2,  GTK_FILL, 0,
1827                     0, 0);
1828  
1829   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)), _("Pag_es:"));
1830   range_tooltip = _("Specify one or more page ranges,\n e.g. 1-3,7,11");
1831   gtk_widget_set_tooltip_text (radio, range_tooltip);
1832  
1833   priv->page_range_radio = radio;
1834   gtk_widget_show (radio);
1835   gtk_table_attach (GTK_TABLE (table), radio,
1836                     0, 1, 2, 3,  GTK_FILL, 0,
1837                     0, 0);
1838   entry = gtk_entry_new ();
1839   gtk_widget_set_tooltip_text (entry, range_tooltip);
1840   atk_object_set_name (gtk_widget_get_accessible (entry), _("Pages"));
1841   atk_object_set_description (gtk_widget_get_accessible (entry), range_tooltip);
1842   priv->page_range_entry = entry;
1843   gtk_widget_show (entry);
1844   gtk_table_attach (GTK_TABLE (table), entry,
1845                     1, 2, 2, 3,  GTK_FILL, 0,
1846                     0, 0);
1847   g_signal_connect (radio, "toggled", G_CALLBACK (update_entry_sensitivity), entry);
1848   update_entry_sensitivity (radio, entry);
1849
1850   table = gtk_table_new (3, 2, FALSE);
1851   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1852   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
1853   frame = wrap_in_frame (_("Copies"), table);
1854   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
1855   gtk_widget_show (table);
1856
1857   /* FIXME chpe: too much space between Copies and spinbutton, put those 2 in a hbox and make it span 2 columns */
1858   label = gtk_label_new_with_mnemonic (_("Copie_s:"));
1859   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1860   gtk_widget_show (label);
1861   gtk_table_attach (GTK_TABLE (table), label,
1862                     0, 1, 0, 1,  GTK_FILL, 0,
1863                     0, 0);
1864   spinbutton = gtk_spin_button_new_with_range (1.0, 100.0, 1.0);
1865   priv->copies_spin = spinbutton;
1866   gtk_widget_show (spinbutton);
1867   gtk_table_attach (GTK_TABLE (table), spinbutton,
1868                     1, 2, 0, 1,  GTK_FILL, 0,
1869                     0, 0);
1870   gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
1871   g_signal_connect_swapped (spinbutton, "value-changed", 
1872                             G_CALLBACK (update_dialog_from_capabilities), dialog);
1873   g_signal_connect_swapped (spinbutton, "changed", 
1874                             G_CALLBACK (update_dialog_from_capabilities), dialog);
1875   
1876   check = gtk_check_button_new_with_mnemonic (_("C_ollate"));
1877   priv->collate_check = check;
1878   g_signal_connect (check, "toggled", G_CALLBACK (update_collate_icon), dialog);
1879   gtk_widget_show (check);
1880   gtk_table_attach (GTK_TABLE (table), check,
1881                     0, 1, 1, 2,  GTK_FILL, 0,
1882                     0, 0);
1883
1884   check = gtk_check_button_new_with_mnemonic (_("_Reverse"));
1885   g_signal_connect (check, "toggled", G_CALLBACK (update_collate_icon), dialog);
1886   priv->reverse_check = check;
1887   gtk_widget_show (check);
1888   gtk_table_attach (GTK_TABLE (table), check,
1889                     0, 1, 2, 3,  GTK_FILL, 0,
1890                     0, 0);
1891
1892   image = gtk_drawing_area_new ();
1893   GTK_WIDGET_SET_FLAGS (image, GTK_NO_WINDOW);
1894
1895   priv->collate_image = image;
1896   gtk_widget_show (image);
1897   gtk_widget_set_size_request (image, 70, 90);
1898   gtk_table_attach (GTK_TABLE (table), image,
1899                     1, 2, 1, 3, GTK_FILL, 0,
1900                     0, 0);
1901   g_signal_connect (image, "expose-event",
1902                     G_CALLBACK (draw_collate_cb), dialog);
1903
1904   label = gtk_label_new (_("General"));
1905   gtk_widget_show (label);
1906   
1907   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), main_vbox, label);
1908 }
1909
1910 static gboolean
1911 is_range_separator (gchar c)
1912 {
1913   return (c == ',' || c == ';' || c == ':');
1914 }
1915
1916 static GtkPageRange *
1917 dialog_get_page_ranges (GtkPrintUnixDialog *dialog,
1918                         gint               *n_ranges_out)
1919 {
1920   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1921   gint i, n_ranges;
1922   const gchar *text, *p;
1923   gchar *next;
1924   GtkPageRange *ranges;
1925   gint start, end;
1926   
1927   text = gtk_entry_get_text (GTK_ENTRY (priv->page_range_entry));
1928
1929   if (*text == 0)
1930     {
1931       *n_ranges_out = 0;
1932       return NULL;
1933     }
1934   
1935   n_ranges = 1;
1936   p = text;
1937   while (*p)
1938     {
1939       if (is_range_separator (*p))
1940         n_ranges++;
1941       p++;
1942     }
1943
1944   ranges = g_new0 (GtkPageRange, n_ranges);
1945   
1946   i = 0;
1947   p = text;
1948   while (*p)
1949     {
1950       while (isspace (*p)) p++;
1951
1952       if (*p == '-')
1953         {
1954           /* a half-open range like -2 */
1955           start = 1;
1956         }
1957       else
1958         {
1959           start = (int)strtol (p, &next, 10);
1960           if (start < 1)
1961             start = 1;
1962           p = next;
1963         }
1964       
1965       end = start;
1966
1967       while (isspace (*p)) p++;
1968
1969       if (*p == '-')
1970         {
1971           p++;
1972           end = (int)strtol (p, &next, 10);
1973           if (next == p) /* a half-open range like 2- */
1974             end = 0;
1975           else if (end < start)
1976             end = start;
1977         }
1978
1979       ranges[i].start = start - 1;
1980       ranges[i].end = end - 1;
1981       i++;
1982
1983       /* Skip until end or separator */
1984       while (*p && !is_range_separator (*p))
1985         p++;
1986
1987       /* if not at end, skip separator */
1988       if (*p)
1989         p++;
1990     }
1991
1992   *n_ranges_out = i;
1993   
1994   return ranges;
1995 }
1996
1997 static void
1998 dialog_set_page_ranges (GtkPrintUnixDialog *dialog,
1999                         GtkPageRange       *ranges,
2000                         gint                n_ranges)
2001 {
2002   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2003   gint i;
2004   GString *s = g_string_new (NULL);
2005
2006   for (i = 0; i < n_ranges; i++)
2007     {
2008       g_string_append_printf (s, "%d", ranges[i].start + 1);
2009       if (ranges[i].end > ranges[i].start)
2010         g_string_append_printf (s, "-%d", ranges[i].end + 1);
2011       else if (ranges[i].end == -1)
2012         g_string_append (s, "-");
2013       
2014       if (i != n_ranges - 1)
2015         g_string_append (s, ",");
2016     }
2017
2018   gtk_entry_set_text (GTK_ENTRY (priv->page_range_entry), s->str);
2019   
2020   g_string_free (s, TRUE);
2021 }
2022
2023
2024 static GtkPrintPages
2025 dialog_get_print_pages (GtkPrintUnixDialog *dialog)
2026 {
2027   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2028   
2029   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->all_pages_radio)))
2030     return GTK_PRINT_PAGES_ALL;
2031   else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->current_page_radio)))
2032     return GTK_PRINT_PAGES_CURRENT;
2033   else
2034     return GTK_PRINT_PAGES_RANGES;
2035 }
2036
2037 static void
2038 dialog_set_print_pages (GtkPrintUnixDialog *dialog, 
2039                         GtkPrintPages       pages)
2040 {
2041   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2042
2043   if (pages == GTK_PRINT_PAGES_RANGES)
2044     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->page_range_radio), TRUE);
2045   else if (pages == GTK_PRINT_PAGES_CURRENT)
2046     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->current_page_radio), TRUE);
2047   else
2048     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->all_pages_radio), TRUE);
2049 }
2050
2051 static gdouble
2052 dialog_get_scale (GtkPrintUnixDialog *dialog)
2053 {
2054   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->scale_spin))
2055     return gtk_spin_button_get_value (GTK_SPIN_BUTTON (dialog->priv->scale_spin));
2056   else
2057     return 100.0;
2058 }
2059
2060 static void
2061 dialog_set_scale (GtkPrintUnixDialog *dialog, 
2062                   gdouble             val)
2063 {
2064   gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->scale_spin), val);
2065 }
2066
2067 static GtkPageSet
2068 dialog_get_page_set (GtkPrintUnixDialog *dialog)
2069 {
2070   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->page_set_combo))
2071     return (GtkPageSet)gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->page_set_combo));
2072   else
2073     return GTK_PAGE_SET_ALL;
2074 }
2075
2076 static void
2077 dialog_set_page_set (GtkPrintUnixDialog *dialog, 
2078                      GtkPageSet          val)
2079 {
2080   gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->priv->page_set_combo),
2081                             (int)val);
2082 }
2083
2084 static gint
2085 dialog_get_n_copies (GtkPrintUnixDialog *dialog)
2086 {
2087   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->copies_spin))
2088     return gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->priv->copies_spin));
2089   return 1;
2090 }
2091
2092 static void
2093 dialog_set_n_copies (GtkPrintUnixDialog *dialog, 
2094                      gint                n_copies)
2095 {
2096   gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->copies_spin),
2097                              n_copies);
2098 }
2099
2100 static gboolean
2101 dialog_get_collate (GtkPrintUnixDialog *dialog)
2102 {
2103   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->collate_check))
2104     return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->collate_check));
2105   return FALSE;
2106 }
2107
2108 static void
2109 dialog_set_collate (GtkPrintUnixDialog *dialog, 
2110                     gboolean            collate)
2111 {
2112   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->collate_check),
2113                                 collate);
2114 }
2115
2116 static gboolean
2117 dialog_get_reverse (GtkPrintUnixDialog *dialog)
2118 {
2119   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->reverse_check))
2120     return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->reverse_check));
2121   return FALSE;
2122 }
2123
2124 static void
2125 dialog_set_reverse (GtkPrintUnixDialog *dialog, 
2126                     gboolean            reverse)
2127 {
2128   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->reverse_check),
2129                                 reverse);
2130 }
2131
2132 static gint 
2133 dialog_get_pages_per_sheet (GtkPrintUnixDialog *dialog)
2134 {
2135   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2136   const gchar *val;
2137   gint num;
2138
2139   val = gtk_printer_option_widget_get_value (priv->pages_per_sheet);
2140
2141   num = 1;
2142   
2143   if (val)
2144     {
2145       num = atoi(val);
2146       if (num < 1)
2147         num = 1;
2148     }
2149   
2150   return num;
2151 }
2152
2153 static GtkNumberUpLayout
2154 dialog_get_number_up_layout (GtkPrintUnixDialog *dialog)
2155 {
2156   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2157   GtkPrintCapabilities       caps;
2158   GtkNumberUpLayout          layout;
2159   const gchar               *val;
2160   GEnumClass                *enum_class;
2161   GEnumValue                *enum_value;
2162
2163   val = gtk_printer_option_widget_get_value (priv->number_up_layout);
2164
2165   caps = priv->manual_capabilities | priv->printer_capabilities;
2166
2167   if ((caps & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT) == 0)
2168     return GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
2169
2170   if (gtk_widget_get_direction (GTK_WIDGET (dialog)) == GTK_TEXT_DIR_LTR)
2171     layout = GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
2172   else
2173     layout = GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM;
2174
2175   if (val == NULL)
2176     return layout;
2177
2178   enum_class = g_type_class_ref (GTK_TYPE_NUMBER_UP_LAYOUT);
2179   enum_value = g_enum_get_value_by_nick (enum_class, val);
2180   if (enum_value)
2181     layout = enum_value->value;
2182   g_type_class_unref (enum_class);
2183
2184   return layout;
2185 }
2186
2187 static gboolean
2188 draw_page_cb (GtkWidget          *widget,
2189               GdkEventExpose     *event,
2190               GtkPrintUnixDialog *dialog)
2191 {
2192   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2193   cairo_t *cr;
2194   gdouble ratio;
2195   gint w, h, tmp, shadow_offset;
2196   gint pages_x, pages_y, i, x, y, layout_w, layout_h;
2197   gdouble page_width, page_height;
2198   GtkPageOrientation orientation;
2199   gboolean landscape;
2200   PangoLayout *layout;
2201   PangoFontDescription *font;
2202   gchar *text;
2203   GdkColor *color;
2204   GtkNumberUpLayout number_up_layout;
2205   gint start_x, end_x, start_y, end_y;
2206   gint dx, dy;
2207   gboolean horizontal;
2208   
2209   orientation = gtk_page_setup_get_orientation (priv->page_setup);
2210   landscape =
2211     (orientation == GTK_PAGE_ORIENTATION_LANDSCAPE) ||
2212     (orientation == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE);
2213
2214   number_up_layout = dialog_get_number_up_layout (dialog);
2215
2216   cr = gdk_cairo_create (widget->window);
2217   
2218   cairo_translate (cr, widget->allocation.x, widget->allocation.y);
2219
2220   ratio = G_SQRT2;
2221
2222   w = (EXAMPLE_PAGE_AREA_SIZE - 3) / ratio;
2223   h = w * ratio;
2224
2225   switch (dialog_get_pages_per_sheet (dialog))
2226     {
2227     default:
2228     case 1:
2229       pages_x = 1; pages_y = 1;
2230       break;
2231     case 2:
2232       landscape = !landscape;
2233       pages_x = 1; pages_y = 2;
2234       break;
2235     case 4:
2236       pages_x = 2; pages_y = 2;
2237       break;
2238     case 6:
2239       landscape = !landscape;
2240       pages_x = 2; pages_y = 3;
2241       break;
2242     case 9:
2243       pages_x = 3; pages_y = 3;
2244       break;
2245     case 16:
2246       pages_x = 4; pages_y = 4;
2247       break;
2248     }
2249
2250   if (landscape)
2251     {
2252       tmp = w;
2253       w = h;
2254       h = tmp;
2255
2256       tmp = pages_x;
2257       pages_x = pages_y;
2258       pages_y = tmp;
2259     }
2260   
2261   shadow_offset = 3;
2262   
2263   color = &widget->style->text[GTK_STATE_NORMAL];
2264   cairo_set_source_rgba (cr, color->red / 65535., color->green / 65535., color->blue / 65535, 0.5);
2265   cairo_rectangle (cr, shadow_offset + 1, shadow_offset + 1, w, h);
2266   cairo_fill (cr);
2267   
2268   gdk_cairo_set_source_color (cr, &widget->style->base[GTK_STATE_NORMAL]);
2269   cairo_rectangle (cr, 1, 1, w, h);
2270   cairo_fill (cr);
2271   cairo_set_line_width (cr, 1.0);
2272   cairo_rectangle (cr, 0.5, 0.5, w+1, h+1);
2273   
2274   gdk_cairo_set_source_color (cr, &widget->style->text[GTK_STATE_NORMAL]);
2275   cairo_stroke (cr);
2276
2277   i = 1;
2278
2279   page_width = (double)w / pages_x;
2280   page_height = (double)h / pages_y;
2281
2282   layout  = pango_cairo_create_layout (cr);
2283
2284   font = pango_font_description_new ();
2285   pango_font_description_set_family (font, "sans");
2286   pango_font_description_set_absolute_size (font, page_height * 0.4 * PANGO_SCALE);
2287   pango_layout_set_font_description (layout, font);
2288   pango_font_description_free (font);
2289
2290   pango_layout_set_width (layout, page_width * PANGO_SCALE);
2291   pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
2292   
2293   switch (number_up_layout)
2294     {
2295       default:
2296       case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM:
2297         start_x = 0;
2298         end_x = pages_x - 1;
2299         start_y = 0;
2300         end_y = pages_y - 1;
2301         dx = 1;
2302         dy = 1;
2303         horizontal = TRUE;
2304         break;
2305       case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP:
2306         start_x = 0;
2307         end_x = pages_x - 1;
2308         start_y = pages_y - 1;
2309         end_y = 0;
2310         dx = 1;
2311         dy = - 1;
2312         horizontal = TRUE;
2313         break;
2314       case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM:
2315         start_x = pages_x - 1;
2316         end_x = 0;
2317         start_y = 0;
2318         end_y = pages_y - 1;
2319         dx = - 1;
2320         dy = 1;
2321         horizontal = TRUE;
2322         break;
2323       case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP:
2324         start_x = pages_x - 1;
2325         end_x = 0;
2326         start_y = pages_y - 1;
2327         end_y = 0;
2328         dx = - 1;
2329         dy = - 1;
2330         horizontal = TRUE;
2331         break;
2332       case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT:
2333         start_x = 0;
2334         end_x = pages_x - 1;
2335         start_y = 0;
2336         end_y = pages_y - 1;
2337         dx = 1;
2338         dy = 1;
2339         horizontal = FALSE;
2340         break;
2341       case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_RIGHT_TO_LEFT:
2342         start_x = pages_x - 1;
2343         end_x = 0;
2344         start_y = 0;
2345         end_y = pages_y - 1;
2346         dx = - 1;
2347         dy = 1;
2348         horizontal = FALSE;
2349         break;
2350       case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT:
2351         start_x = 0;
2352         end_x = pages_x - 1;
2353         start_y = pages_y - 1;
2354         end_y = 0;
2355         dx = 1;
2356         dy = - 1;
2357         horizontal = FALSE;
2358         break;
2359       case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_RIGHT_TO_LEFT:
2360         start_x = pages_x - 1;
2361         end_x = 0;
2362         start_y = pages_y - 1;
2363         end_y = 0;
2364         dx = - 1;
2365         dy = - 1;
2366         horizontal = FALSE;
2367         break;
2368     }
2369
2370   if (horizontal)
2371     for (y = start_y; y != end_y + dy; y += dy)
2372       {
2373         for (x = start_x; x != end_x + dx; x += dx)
2374           {
2375             text = g_strdup_printf ("%d", i++);
2376             pango_layout_set_text (layout, text, -1);
2377             g_free (text);
2378             pango_layout_get_size (layout, &layout_w, &layout_h);
2379             cairo_save (cr);
2380             cairo_translate (cr,
2381                              x * page_width,
2382                              y * page_height + (page_height - layout_h / 1024.0) / 2);
2383
2384             pango_cairo_show_layout (cr, layout);
2385             cairo_restore (cr);
2386           }
2387       }
2388   else
2389     for (x = start_x; x != end_x + dx; x += dx)
2390       {
2391         for (y = start_y; y != end_y + dy; y += dy)
2392           {
2393             text = g_strdup_printf ("%d", i++);
2394             pango_layout_set_text (layout, text, -1);
2395             g_free (text);
2396             pango_layout_get_size (layout, &layout_w, &layout_h);
2397             cairo_save (cr);
2398             cairo_translate (cr,
2399                              x * page_width,
2400                              y * page_height + (page_height - layout_h / 1024.0) / 2);
2401
2402             pango_cairo_show_layout (cr, layout);
2403             cairo_restore (cr);
2404           }
2405       }
2406   
2407   g_object_unref (layout);
2408   cairo_destroy (cr);
2409
2410   return TRUE;
2411 }
2412
2413 static void
2414 redraw_page_layout_preview (GtkPrintUnixDialog *dialog)
2415 {
2416   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2417
2418   if (priv->page_layout_preview)
2419     gtk_widget_queue_draw (priv->page_layout_preview);
2420 }
2421
2422 static void
2423 update_number_up_layout (GtkPrintUnixDialog *dialog)
2424 {
2425   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2426   GtkPrintCapabilities       caps;
2427   GtkPrinterOptionSet       *set;
2428   GtkNumberUpLayout          layout;
2429   GtkPrinterOption          *option;
2430   GtkPrinterOption          *old_option;
2431   GtkPageOrientation         page_orientation;
2432
2433   set = priv->options;
2434
2435   caps = priv->manual_capabilities | priv->printer_capabilities;
2436
2437   if (caps & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT)
2438     {
2439       if (priv->number_up_layout_n_option == NULL)
2440         {
2441           priv->number_up_layout_n_option = gtk_printer_option_set_lookup (set, "gtk-n-up-layout");
2442           if (priv->number_up_layout_n_option == NULL)
2443             {
2444               char *n_up_layout[] = { "lrtb", "lrbt", "rltb", "rlbt", "tblr", "tbrl", "btlr", "btrl" };
2445                /* Translators: These strings name the possible arrangements of
2446                 * multiple pages on a sheet when printing (same as in gtkprintbackendcups.c)
2447                 */
2448               char *n_up_layout_display[] = { N_("Left to right, top to bottom"), N_("Left to right, bottom to top"),
2449                                               N_("Right to left, top to bottom"), N_("Right to left, bottom to top"),
2450                                               N_("Top to bottom, left to right"), N_("Top to bottom, right to left"),
2451                                               N_("Bottom to top, left to right"), N_("Bottom to top, right to left") };
2452               int i;
2453
2454               priv->number_up_layout_n_option = gtk_printer_option_new ("gtk-n-up-layout",
2455                                                                         _("Page Ordering"),
2456                                                                         GTK_PRINTER_OPTION_TYPE_PICKONE);
2457               gtk_printer_option_allocate_choices (priv->number_up_layout_n_option, 8);
2458
2459               for (i = 0; i < G_N_ELEMENTS (n_up_layout_display); i++)
2460                 {
2461                   priv->number_up_layout_n_option->choices[i] = g_strdup (n_up_layout[i]);
2462                   priv->number_up_layout_n_option->choices_display[i] = g_strdup (_(n_up_layout_display[i]));
2463                 }
2464             }
2465           g_object_ref (priv->number_up_layout_n_option);
2466
2467           priv->number_up_layout_2_option = gtk_printer_option_new ("gtk-n-up-layout",
2468                                                                     _("Page Ordering"),
2469                                                                     GTK_PRINTER_OPTION_TYPE_PICKONE);
2470           gtk_printer_option_allocate_choices (priv->number_up_layout_2_option, 2);
2471         }
2472
2473       page_orientation = gtk_page_setup_get_orientation (priv->page_setup);
2474       if (page_orientation == GTK_PAGE_ORIENTATION_PORTRAIT ||
2475           page_orientation == GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT)
2476         {
2477           if (! (priv->number_up_layout_2_option->choices[0] == priv->number_up_layout_n_option->choices[0] &&
2478                  priv->number_up_layout_2_option->choices[1] == priv->number_up_layout_n_option->choices[2]))
2479             {
2480               g_free (priv->number_up_layout_2_option->choices_display[0]);
2481               g_free (priv->number_up_layout_2_option->choices_display[1]);
2482               priv->number_up_layout_2_option->choices[0] = priv->number_up_layout_n_option->choices[0];
2483               priv->number_up_layout_2_option->choices[1] = priv->number_up_layout_n_option->choices[2];
2484               priv->number_up_layout_2_option->choices_display[0] = g_strdup ( _("Left to right"));
2485               priv->number_up_layout_2_option->choices_display[1] = g_strdup ( _("Right to left"));
2486             }
2487         }
2488       else
2489         {
2490           if (! (priv->number_up_layout_2_option->choices[0] == priv->number_up_layout_n_option->choices[0] &&
2491                  priv->number_up_layout_2_option->choices[1] == priv->number_up_layout_n_option->choices[1]))
2492             {
2493               g_free (priv->number_up_layout_2_option->choices_display[0]);
2494               g_free (priv->number_up_layout_2_option->choices_display[1]);
2495               priv->number_up_layout_2_option->choices[0] = priv->number_up_layout_n_option->choices[0];
2496               priv->number_up_layout_2_option->choices[1] = priv->number_up_layout_n_option->choices[1];
2497               priv->number_up_layout_2_option->choices_display[0] = g_strdup ( _("Top to bottom"));
2498               priv->number_up_layout_2_option->choices_display[1] = g_strdup ( _("Bottom to top"));
2499             }
2500         }
2501
2502       layout = dialog_get_number_up_layout (dialog);
2503
2504       old_option = gtk_printer_option_set_lookup (set, "gtk-n-up-layout");
2505       if (old_option != NULL)
2506         gtk_printer_option_set_remove (set, old_option);
2507
2508       if (dialog_get_pages_per_sheet (dialog) != 1)
2509         {
2510           GEnumClass *enum_class;
2511           GEnumValue *enum_value;
2512           enum_class = g_type_class_ref (GTK_TYPE_NUMBER_UP_LAYOUT);
2513
2514           if (dialog_get_pages_per_sheet (dialog) == 2)
2515             {
2516               option = priv->number_up_layout_2_option;
2517
2518               if (layout == GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM ||
2519                   layout == GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT)
2520                 enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM);
2521
2522               if (layout == GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP ||
2523                   layout == GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT)
2524                 enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP);
2525
2526               if (layout == GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM ||
2527                   layout == GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_RIGHT_TO_LEFT)
2528                 enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM);
2529
2530               if (layout == GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP ||
2531                   layout == GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_RIGHT_TO_LEFT)
2532                 enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP);
2533             }
2534           else
2535             {
2536               option = priv->number_up_layout_n_option;
2537
2538               enum_value = g_enum_get_value (enum_class, layout);
2539             }
2540
2541           g_assert (enum_value != NULL);
2542           gtk_printer_option_set (option, enum_value->value_nick);
2543           g_type_class_unref (enum_class);
2544
2545           gtk_printer_option_set_add (set, option);
2546         }
2547     }
2548
2549   setup_option (dialog, "gtk-n-up-layout", priv->number_up_layout);
2550
2551   if (priv->number_up_layout != NULL)
2552     gtk_widget_set_sensitive (GTK_WIDGET (priv->number_up_layout),
2553                               (caps & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT) &&
2554                               (dialog_get_pages_per_sheet (dialog) > 1));
2555 }
2556
2557 static void
2558 create_page_setup_page (GtkPrintUnixDialog *dialog)
2559 {
2560   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2561   GtkWidget *main_vbox, *label, *hbox, *hbox2;
2562   GtkWidget *frame, *table, *widget;
2563   GtkWidget *combo, *spinbutton, *draw;
2564
2565   main_vbox = gtk_vbox_new (FALSE, 18);
2566   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
2567   gtk_widget_show (main_vbox);
2568
2569   hbox = gtk_hbox_new (FALSE, 18);
2570   gtk_widget_show (hbox);
2571   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
2572
2573   table = gtk_table_new (5, 2, FALSE);
2574   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2575   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2576   frame = wrap_in_frame (_("Layout"), table);
2577   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
2578   gtk_widget_show (table);
2579
2580   label = gtk_label_new_with_mnemonic (_("T_wo-sided:"));
2581   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2582   gtk_widget_show (label);
2583   gtk_table_attach (GTK_TABLE (table), label,
2584                     0, 1, 0, 1,  GTK_FILL, 0,
2585                     0, 0);
2586
2587   widget = gtk_printer_option_widget_new (NULL);
2588   priv->duplex = GTK_PRINTER_OPTION_WIDGET (widget);
2589   gtk_widget_show (widget);
2590   gtk_table_attach (GTK_TABLE (table), widget,
2591                     1, 2, 0, 1,  GTK_FILL, 0,
2592                     0, 0);
2593   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2594
2595   label = gtk_label_new_with_mnemonic (_("Pages per _side:"));
2596   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2597   gtk_widget_show (label);
2598   gtk_table_attach (GTK_TABLE (table), label,
2599                     0, 1, 1, 2,  GTK_FILL, 0,
2600                     0, 0);
2601
2602   widget = gtk_printer_option_widget_new (NULL);
2603   g_signal_connect_swapped (widget, "changed", G_CALLBACK (redraw_page_layout_preview), dialog);
2604   g_signal_connect_swapped (widget, "changed", G_CALLBACK (update_number_up_layout), dialog);
2605   priv->pages_per_sheet = GTK_PRINTER_OPTION_WIDGET (widget);
2606   gtk_widget_show (widget);
2607   gtk_table_attach (GTK_TABLE (table), widget,
2608                     1, 2, 1, 2,  GTK_FILL, 0,
2609                     0, 0);
2610   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2611
2612
2613   label = gtk_label_new_with_mnemonic (_("Page or_dering:"));
2614   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2615   gtk_widget_show (label);
2616   gtk_table_attach (GTK_TABLE (table), label,
2617                     0, 1, 2, 3,  GTK_FILL, 0,
2618                     0, 0);
2619
2620   widget = gtk_printer_option_widget_new (NULL);
2621   g_signal_connect_swapped (widget, "changed", G_CALLBACK (redraw_page_layout_preview), dialog);
2622   priv->number_up_layout = GTK_PRINTER_OPTION_WIDGET (widget);
2623   gtk_widget_show (widget);
2624   gtk_table_attach (GTK_TABLE (table), widget,
2625                     1, 2, 2, 3,  GTK_FILL, 0,
2626                     0, 0);
2627   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2628
2629   label = gtk_label_new_with_mnemonic (_("_Only print:"));
2630   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2631   gtk_widget_show (label);
2632   gtk_table_attach (GTK_TABLE (table), label,
2633                     0, 1, 3, 4,  GTK_FILL, 0,
2634                     0, 0);
2635
2636   combo = gtk_combo_box_new_text ();
2637   priv->page_set_combo = combo;
2638   gtk_widget_show (combo);
2639   gtk_table_attach (GTK_TABLE (table), combo,
2640                     1, 2, 3, 4,  GTK_FILL, 0,
2641                     0, 0);
2642   gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
2643   /* In enum order */
2644   gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("All sheets"));  
2645   gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Even sheets"));  
2646   gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Odd sheets"));  
2647   gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
2648
2649   label = gtk_label_new_with_mnemonic (_("Sc_ale:"));
2650   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2651   gtk_widget_show (label);
2652   gtk_table_attach (GTK_TABLE (table), label,
2653                     0, 1, 4, 5,  GTK_FILL, 0,
2654                     0, 0);
2655
2656   hbox2 = gtk_hbox_new (FALSE, 6);
2657   gtk_widget_show (hbox2);
2658   gtk_table_attach (GTK_TABLE (table), hbox2,
2659                     1, 2, 4, 5,  GTK_FILL, 0,
2660                     0, 0);
2661   
2662   spinbutton = gtk_spin_button_new_with_range (1.0, 1000.0, 1.0);
2663   priv->scale_spin = spinbutton;
2664   gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinbutton), 1);
2665   gtk_spin_button_set_value (GTK_SPIN_BUTTON (spinbutton), 100.0);
2666   gtk_box_pack_start (GTK_BOX (hbox2), spinbutton, FALSE, FALSE, 0);
2667   gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
2668   gtk_widget_show (spinbutton);
2669   label = gtk_label_new ("%"); /* FIXMEchpe does there exist any language where % needs to be translated? */
2670   gtk_widget_show (label);
2671   gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0);
2672
2673   table = gtk_table_new (4, 2, FALSE);
2674   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2675   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2676   frame = wrap_in_frame (_("Paper"), table);
2677   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 6);
2678   gtk_widget_show (table);
2679
2680   label = gtk_label_new_with_mnemonic (_("Paper _type:"));
2681   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2682   gtk_widget_show (label);
2683   gtk_table_attach (GTK_TABLE (table), label,
2684                     0, 1, 0, 1,  GTK_FILL, 0,
2685                     0, 0);
2686
2687   widget = gtk_printer_option_widget_new (NULL);
2688   priv->paper_type = GTK_PRINTER_OPTION_WIDGET (widget);
2689   gtk_widget_show (widget);
2690   gtk_table_attach (GTK_TABLE (table), widget,
2691                     1, 2, 0, 1,  GTK_FILL, 0,
2692                     0, 0);
2693   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2694
2695   label = gtk_label_new_with_mnemonic (_("Paper _source:"));
2696   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2697   gtk_widget_show (label);
2698   gtk_table_attach (GTK_TABLE (table), label,
2699                     0, 1, 1, 2,  GTK_FILL, 0,
2700                     0, 0);
2701
2702   widget = gtk_printer_option_widget_new (NULL);
2703   priv->paper_source = GTK_PRINTER_OPTION_WIDGET (widget);
2704   gtk_widget_show (widget);
2705   gtk_table_attach (GTK_TABLE (table), widget,
2706                     1, 2, 1, 2,  GTK_FILL, 0,
2707                     0, 0);
2708   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2709
2710   label = gtk_label_new_with_mnemonic (_("Output t_ray:"));
2711   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2712   gtk_widget_show (label);
2713   gtk_table_attach (GTK_TABLE (table), label,
2714                     0, 1, 2, 3,  GTK_FILL, 0,
2715                     0, 0);
2716
2717   widget = gtk_printer_option_widget_new (NULL);
2718   priv->output_tray = GTK_PRINTER_OPTION_WIDGET (widget);
2719   gtk_widget_show (widget);
2720   gtk_table_attach (GTK_TABLE (table), widget,
2721                     1, 2, 2, 3,  GTK_FILL, 0,
2722                     0, 0);
2723   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2724
2725   /* Add the page layout preview */
2726   hbox2 = gtk_hbox_new (FALSE, 0);
2727   gtk_widget_show (hbox2);
2728   gtk_box_pack_start (GTK_BOX (main_vbox), hbox2, TRUE, TRUE, 0);
2729
2730   draw = gtk_drawing_area_new ();
2731   GTK_WIDGET_SET_FLAGS (draw, GTK_NO_WINDOW);
2732   priv->page_layout_preview = draw;
2733   gtk_widget_set_size_request (draw, 200, 200);
2734   g_signal_connect (draw, "expose-event", G_CALLBACK (draw_page_cb), dialog);
2735   gtk_widget_show (draw);
2736
2737   gtk_box_pack_start (GTK_BOX (hbox2), draw, TRUE, FALSE, 0);
2738   
2739   label = gtk_label_new (_("Page Setup"));
2740   gtk_widget_show (label);
2741   
2742   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
2743                             main_vbox, label);
2744 }
2745
2746 static void
2747 create_job_page (GtkPrintUnixDialog *dialog)
2748 {
2749   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2750   GtkWidget *main_table, *label;
2751   GtkWidget *frame, *table, *radio;
2752   GtkWidget *entry, *widget;
2753   const gchar *at_tooltip;
2754   const gchar *on_hold_tooltip;
2755
2756   main_table = gtk_table_new (2, 2, FALSE);
2757   gtk_container_set_border_width (GTK_CONTAINER (main_table), 12);
2758   gtk_table_set_row_spacings (GTK_TABLE (main_table), 18);
2759   gtk_table_set_col_spacings (GTK_TABLE (main_table), 18);
2760
2761   table = gtk_table_new (2, 2, FALSE);
2762   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2763   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2764   frame = wrap_in_frame (_("Job Details"), table);
2765   gtk_table_attach (GTK_TABLE (main_table), frame,
2766                     0, 1, 0, 1,  GTK_FILL, 0,
2767                     0, 0);
2768   gtk_widget_show (table);
2769
2770   label = gtk_label_new_with_mnemonic (_("Pri_ority:"));
2771   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2772   gtk_widget_show (label);
2773   gtk_table_attach (GTK_TABLE (table), label,
2774                     0, 1, 0, 1,  GTK_FILL, 0,
2775                     0, 0);
2776
2777   widget = gtk_printer_option_widget_new (NULL);
2778   priv->job_prio = GTK_PRINTER_OPTION_WIDGET (widget);
2779   gtk_widget_show (widget);
2780   gtk_table_attach (GTK_TABLE (table), widget,
2781                     1, 2, 0, 1,  GTK_FILL, 0,
2782                     0, 0);
2783   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2784
2785   label = gtk_label_new_with_mnemonic (_("_Billing info:"));
2786   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2787   gtk_widget_show (label);
2788   gtk_table_attach (GTK_TABLE (table), label,
2789                     0, 1, 1, 2,  GTK_FILL, 0,
2790                     0, 0);
2791
2792   widget = gtk_printer_option_widget_new (NULL);
2793   priv->billing_info = GTK_PRINTER_OPTION_WIDGET (widget);
2794   gtk_widget_show (widget);
2795   gtk_table_attach (GTK_TABLE (table), widget,
2796                     1, 2, 1, 2,  GTK_FILL, 0,
2797                     0, 0);
2798   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2799
2800   table = gtk_table_new (2, 2, FALSE);
2801   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2802   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2803   frame = wrap_in_frame (_("Print Document"), table);
2804   gtk_table_attach (GTK_TABLE (main_table), frame,
2805                     0, 1, 1, 2,  GTK_FILL, 0,
2806                     0, 0);
2807   gtk_widget_show (table);
2808
2809   /* Translators: this is one of the choices for the print at option
2810    * in the print dialog
2811    */
2812   radio = gtk_radio_button_new_with_mnemonic (NULL, _("_Now"));
2813   priv->print_now_radio = radio;
2814   gtk_widget_show (radio);
2815   gtk_table_attach (GTK_TABLE (table), radio,
2816                     0, 2, 0, 1,  GTK_FILL, 0,
2817                     0, 0);
2818   /* Translators: this is one of the choices for the print at option
2819    * in the print dialog. It also serves as the label for an entry that
2820    * allows the user to enter a time.
2821    */
2822   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
2823                                               _("A_t:"));
2824
2825   /* Translators: Ability to parse the am/pm format depends on actual locale.
2826    * You can remove the am/pm values below for your locale if they are not
2827    * supported.
2828    */
2829   at_tooltip = _("Specify the time of print,\n e.g. 15:30, 2:35 pm, 14:15:20, 11:46:30 am, 4 pm");
2830   gtk_widget_set_tooltip_text (radio, at_tooltip);
2831   priv->print_at_radio = radio;
2832   gtk_widget_show (radio);
2833   gtk_table_attach (GTK_TABLE (table), radio,
2834                     0, 1, 1, 2,  GTK_FILL, 0,
2835                     0, 0);
2836
2837   entry = gtk_entry_new ();
2838   gtk_widget_set_tooltip_text (entry, at_tooltip);
2839   atk_object_set_name (gtk_widget_get_accessible (entry), _("Time of print"));
2840   atk_object_set_description (gtk_widget_get_accessible (entry), at_tooltip);
2841   priv->print_at_entry = entry;
2842   gtk_widget_show (entry);
2843   gtk_table_attach (GTK_TABLE (table), entry,
2844                     1, 2, 1, 2,  GTK_FILL, 0,
2845                     0, 0);
2846
2847   g_signal_connect (radio, "toggled", G_CALLBACK (update_entry_sensitivity), entry);
2848   update_entry_sensitivity (radio, entry);
2849
2850   /* Translators: this is one of the choices for the print at option
2851    * in the print dialog. It means that the print job will not be
2852    * printed until it explicitly gets 'released'.
2853    */
2854   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
2855                                               _("On _hold"));
2856   on_hold_tooltip = _("Hold the job until it is explicitly released");
2857   gtk_widget_set_tooltip_text (radio, on_hold_tooltip);
2858   priv->print_hold_radio = radio;
2859   gtk_widget_show (radio);
2860   gtk_table_attach (GTK_TABLE (table), radio,
2861                     0, 2, 2, 3,  GTK_FILL, 0,
2862                     0, 0);
2863
2864   g_signal_connect_swapped (priv->print_now_radio, "toggled",
2865                             G_CALLBACK (update_print_at_option), dialog);
2866   g_signal_connect_swapped (priv->print_at_radio, "toggled",
2867                             G_CALLBACK (update_print_at_option), dialog);
2868   g_signal_connect_swapped (priv->print_at_entry, "changed",
2869                             G_CALLBACK (update_print_at_option), dialog);
2870   g_signal_connect_swapped (priv->print_hold_radio, "toggled",
2871                             G_CALLBACK (update_print_at_option), dialog);
2872
2873   table = gtk_table_new (2, 2, FALSE);
2874   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2875   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2876   frame = wrap_in_frame (_("Add Cover Page"), table);
2877   gtk_table_attach (GTK_TABLE (main_table), frame,
2878                     1, 2, 0, 1,  GTK_FILL, 0,
2879                     0, 0);
2880   gtk_widget_show (table);
2881
2882   /* Translators, this is the label used for the option in the print 
2883    * dialog that controls the front cover page.
2884    */
2885   label = gtk_label_new_with_mnemonic (_("Be_fore:"));
2886   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2887   gtk_widget_show (label);
2888   gtk_table_attach (GTK_TABLE (table), label,
2889                     0, 1, 0, 1,  GTK_FILL, 0,
2890                     0, 0);
2891
2892   widget = gtk_printer_option_widget_new (NULL);
2893   priv->cover_before = GTK_PRINTER_OPTION_WIDGET (widget);
2894   gtk_widget_show (widget);
2895   gtk_table_attach (GTK_TABLE (table), widget,
2896                     1, 2, 0, 1,  GTK_FILL, 0,
2897                     0, 0);
2898   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2899
2900   /* Translators, this is the label used for the option in the print 
2901    * dialog that controls the back cover page.
2902    */
2903   label = gtk_label_new_with_mnemonic (_("_After:"));
2904   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2905   gtk_widget_show (label);
2906   gtk_table_attach (GTK_TABLE (table), label,
2907                     0, 1, 1, 2,  GTK_FILL, 0,
2908                     0, 0);
2909
2910   widget = gtk_printer_option_widget_new (NULL);
2911   priv->cover_after = GTK_PRINTER_OPTION_WIDGET (widget);
2912   gtk_widget_show (widget);
2913   gtk_table_attach (GTK_TABLE (table), widget,
2914                     1, 2, 1, 2,  GTK_FILL, 0,
2915                     0, 0);
2916   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2917
2918   /* Translators: this is the tab label for the notebook tab containing
2919    * job-specific options in the print dialog
2920    */
2921   label = gtk_label_new (_("Job"));
2922   gtk_widget_show (label);
2923
2924   priv->job_page = main_table;
2925   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
2926                             main_table, label);
2927 }
2928
2929 static void 
2930 create_optional_page (GtkPrintUnixDialog  *dialog,
2931                       const gchar         *text,
2932                       GtkWidget          **table_out,
2933                       GtkWidget          **page_out)
2934 {
2935   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2936   GtkWidget *table, *label, *scrolled;
2937
2938   scrolled = gtk_scrolled_window_new (NULL, NULL);
2939   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
2940                                   GTK_POLICY_NEVER,
2941                                   GTK_POLICY_AUTOMATIC);
2942   
2943   table = gtk_table_new (1, 2, FALSE);
2944   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2945   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2946   gtk_container_set_border_width (GTK_CONTAINER (table), 12);
2947   gtk_widget_show (table);
2948
2949   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
2950                                          table);
2951   gtk_viewport_set_shadow_type (GTK_VIEWPORT (GTK_BIN(scrolled)->child),
2952                                 GTK_SHADOW_NONE);
2953   
2954   label = gtk_label_new (text);
2955   gtk_widget_show (label);
2956   
2957   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
2958                             scrolled, label);
2959
2960   *table_out = table;
2961   *page_out = scrolled;
2962 }
2963
2964 static void
2965 create_advanced_page (GtkPrintUnixDialog *dialog)
2966 {
2967   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2968   GtkWidget *main_vbox, *label, *scrolled;
2969
2970   scrolled = gtk_scrolled_window_new (NULL, NULL);
2971   priv->advanced_page = scrolled;
2972   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
2973                                   GTK_POLICY_NEVER,
2974                                   GTK_POLICY_AUTOMATIC);
2975
2976   main_vbox = gtk_vbox_new (FALSE, 18);
2977   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
2978   gtk_widget_show (main_vbox);
2979
2980   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
2981                                          main_vbox);
2982   gtk_viewport_set_shadow_type (GTK_VIEWPORT (GTK_BIN(scrolled)->child),
2983                                 GTK_SHADOW_NONE);
2984   
2985   priv->advanced_vbox = main_vbox;
2986   
2987   label = gtk_label_new (_("Advanced"));
2988   gtk_widget_show (label);
2989   
2990   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
2991                             scrolled, label);
2992 }
2993
2994
2995 static void
2996 populate_dialog (GtkPrintUnixDialog *print_dialog)
2997 {
2998   GtkPrintUnixDialogPrivate *priv = print_dialog->priv;
2999   GtkDialog *dialog = GTK_DIALOG (print_dialog);
3000   GtkWidget *vbox, *conflict_hbox, *image, *label;
3001
3002   gtk_dialog_set_has_separator (dialog, FALSE);
3003   gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
3004   gtk_box_set_spacing (GTK_BOX (dialog->vbox), 2); /* 2 * 5 + 2 = 12 */
3005   gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 5);
3006   gtk_box_set_spacing (GTK_BOX (dialog->action_area), 6);
3007
3008   vbox = gtk_vbox_new (FALSE, 6);
3009   gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
3010   gtk_box_pack_start (GTK_BOX (dialog->vbox), vbox, TRUE, TRUE, 0);
3011   gtk_widget_show (vbox);
3012
3013   priv->notebook = gtk_notebook_new ();
3014   gtk_box_pack_start (GTK_BOX (vbox), priv->notebook, TRUE, TRUE, 0);
3015   gtk_widget_show (priv->notebook);
3016
3017   create_printer_list_model (print_dialog);
3018
3019   create_main_page (print_dialog);
3020   create_page_setup_page (print_dialog);
3021   create_job_page (print_dialog);
3022   create_optional_page (print_dialog, _("Image Quality"),
3023                         &priv->image_quality_table,
3024                         &priv->image_quality_page);
3025   create_optional_page (print_dialog, _("Color"),
3026                         &priv->color_table,
3027                         &priv->color_page);
3028   create_optional_page (print_dialog, _("Finishing"),
3029                         &priv->finishing_table,
3030                         &priv->finishing_page);
3031   create_advanced_page (print_dialog);
3032
3033   priv->conflicts_widget = conflict_hbox = gtk_hbox_new (FALSE, 12);
3034   gtk_box_pack_end (GTK_BOX (vbox), conflict_hbox, FALSE, FALSE, 0);
3035   image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_MENU);
3036   gtk_widget_show (image);
3037   gtk_box_pack_start (GTK_BOX (conflict_hbox), image, FALSE, TRUE, 0);
3038   label = gtk_label_new (_("Some of the settings in the dialog conflict"));
3039   gtk_widget_show (label);
3040   gtk_box_pack_start (GTK_BOX (conflict_hbox), label, FALSE, TRUE, 0);
3041   
3042   load_print_backends (print_dialog);
3043 }
3044
3045 /**
3046  * gtk_print_unix_dialog_new:
3047  * @title: Title of the dialog, or %NULL
3048  * @parent: Transient parent of the dialog, or %NULL
3049  *
3050  * Creates a new #GtkPrintUnixDialog.
3051  *
3052  * Return value: a new #GtkPrintUnixDialog
3053  *
3054  * Since: 2.10
3055  **/
3056 GtkWidget *
3057 gtk_print_unix_dialog_new (const gchar *title,
3058                            GtkWindow   *parent)
3059 {
3060   GtkWidget *result;
3061   const gchar *_title = _("Print");
3062
3063   if (title)
3064     _title = title;
3065
3066   result = g_object_new (GTK_TYPE_PRINT_UNIX_DIALOG,
3067                          "transient-for", parent,
3068                          "title", _title,
3069                          "has-separator", FALSE,
3070                          NULL);
3071   
3072   return result;
3073 }
3074
3075 /**
3076  * gtk_print_unix_dialog_get_selected_printer:
3077  * @dialog: a #GtkPrintUnixDialog
3078  * 
3079  * Gets the currently selected printer.
3080  * 
3081  * Returns: the currently selected printer
3082  * 
3083  * Since: 2.10
3084  */
3085 GtkPrinter *
3086 gtk_print_unix_dialog_get_selected_printer (GtkPrintUnixDialog *dialog)
3087 {
3088   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
3089
3090   return dialog->priv->current_printer;
3091 }
3092
3093 /**
3094  * gtk_print_unix_dialog_set_page_setup:
3095  * @dialog: a #GtkPrintUnixDialog
3096  * @page_setup: a #GtkPageSetup
3097  * 
3098  * Sets the page setup of the #GtkPrintUnixDialog.
3099  *
3100  * Since: 2.10
3101  */
3102 void
3103 gtk_print_unix_dialog_set_page_setup (GtkPrintUnixDialog *dialog,
3104                                       GtkPageSetup       *page_setup)
3105 {
3106   GtkPrintUnixDialogPrivate *priv;
3107
3108   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
3109   g_return_if_fail (GTK_IS_PAGE_SETUP (page_setup));
3110
3111   priv = dialog->priv;
3112
3113   if (priv->page_setup != page_setup)
3114     {
3115       g_object_unref (priv->page_setup);
3116       priv->page_setup = g_object_ref (page_setup);
3117
3118       priv->page_setup_set = TRUE;
3119
3120       g_object_notify (G_OBJECT (dialog), "page-setup");
3121     }
3122 }
3123
3124 /**
3125  * gtk_print_unix_dialog_get_page_setup:
3126  * @dialog: a #GtkPrintUnixDialog
3127  * 
3128  * Gets the page setup that is used by the #GtkPrintUnixDialog.
3129  * 
3130  * Returns: the page setup of @dialog.
3131  *
3132  * Since: 2.10
3133  */
3134 GtkPageSetup *
3135 gtk_print_unix_dialog_get_page_setup (GtkPrintUnixDialog *dialog)
3136 {
3137   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
3138
3139   return dialog->priv->page_setup;
3140 }
3141
3142 /**
3143  * gtk_print_unix_dialog_set_current_page:
3144  * @dialog: a #GtkPrintUnixDialog
3145  * @current_page: the current page number.
3146  * 
3147  * Sets the current page number. If @current_page is not -1, this enables
3148  * the current page choice for the range of pages to print.
3149  *
3150  * Since: 2.10
3151  */
3152 void
3153 gtk_print_unix_dialog_set_current_page (GtkPrintUnixDialog *dialog,
3154                                         gint                current_page)
3155 {
3156   GtkPrintUnixDialogPrivate *priv;
3157
3158   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
3159
3160   priv = dialog->priv;
3161
3162   if (priv->current_page != current_page)
3163     {
3164       priv->current_page = current_page;
3165
3166       if (priv->current_page_radio)
3167         gtk_widget_set_sensitive (priv->current_page_radio, current_page != -1);
3168
3169       g_object_notify (G_OBJECT (dialog), "current-page");
3170     }
3171 }
3172
3173 /**
3174  * gtk_print_unix_dialog_get_current_page:
3175  * @dialog: a #GtkPrintUnixDialog
3176  * 
3177  * Gets the current page of the #GtkPrintDialog.
3178  * 
3179  * Returns: the current page of @dialog
3180  * 
3181  * Since: 2.10
3182  */
3183 gint
3184 gtk_print_unix_dialog_get_current_page (GtkPrintUnixDialog *dialog)
3185 {
3186   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), -1);
3187
3188   return dialog->priv->current_page;
3189 }
3190
3191 static gboolean
3192 set_active_printer (GtkPrintUnixDialog *dialog,
3193                     const gchar        *printer_name)
3194 {
3195   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3196   GtkTreeModel *model;
3197   GtkTreeIter iter, filter_iter;
3198   GtkTreeSelection *selection;
3199   GtkPrinter *printer;
3200
3201   model = GTK_TREE_MODEL (priv->printer_list);
3202
3203   if (gtk_tree_model_get_iter_first (model, &iter))
3204     {
3205       do
3206         {
3207           gtk_tree_model_get (GTK_TREE_MODEL (priv->printer_list), &iter,
3208                               PRINTER_LIST_COL_PRINTER_OBJ, &printer, -1);
3209           if (printer == NULL)
3210             continue;
3211           
3212           if (strcmp (gtk_printer_get_name (printer), printer_name) == 0)
3213             {
3214               gtk_tree_model_filter_convert_child_iter_to_iter (priv->printer_list_filter,
3215                                                                 &filter_iter, &iter);
3216               
3217               selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
3218               priv->internal_printer_change = TRUE;
3219               gtk_tree_selection_select_iter (selection, &filter_iter);
3220               priv->internal_printer_change = FALSE;
3221               g_free (priv->waiting_for_printer);
3222               priv->waiting_for_printer = NULL;
3223               
3224               g_object_unref (printer);
3225               return TRUE;
3226             }
3227               
3228           g_object_unref (printer);
3229           
3230         } while (gtk_tree_model_iter_next (model, &iter));
3231     }
3232   
3233   return FALSE;
3234 }
3235
3236 /**
3237  * gtk_print_unix_dialog_set_settings:
3238  * @dialog: a #GtkPrintUnixDialog
3239  * @settings: a #GtkPrintSettings, or %NULL
3240  * 
3241  * Sets the #GtkPrintSettings for the #GtkPrintUnixDialog. Typically,
3242  * this is used to restore saved print settings from a previous print
3243  * operation before the print dialog is shown.
3244  * 
3245  * Since: 2.10
3246  **/
3247 void
3248 gtk_print_unix_dialog_set_settings (GtkPrintUnixDialog *dialog,
3249                                     GtkPrintSettings   *settings)
3250 {
3251   GtkPrintUnixDialogPrivate *priv;
3252   const gchar *printer;
3253   GtkPageRange *ranges;
3254   gint num_ranges;
3255   
3256   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
3257   g_return_if_fail (settings == NULL || GTK_IS_PRINT_SETTINGS (settings));
3258
3259   priv = dialog->priv;
3260
3261   if (settings != NULL)
3262     {
3263       dialog_set_collate (dialog, gtk_print_settings_get_collate (settings));
3264       dialog_set_reverse (dialog, gtk_print_settings_get_reverse (settings));
3265       dialog_set_n_copies (dialog, gtk_print_settings_get_n_copies (settings));
3266       dialog_set_scale (dialog, gtk_print_settings_get_scale (settings));
3267       dialog_set_page_set (dialog, gtk_print_settings_get_page_set (settings));
3268       dialog_set_print_pages (dialog, gtk_print_settings_get_print_pages (settings));
3269       ranges = gtk_print_settings_get_page_ranges (settings, &num_ranges);
3270       if (ranges)
3271         {
3272           dialog_set_page_ranges (dialog, ranges, num_ranges);
3273           g_free (ranges);
3274         }
3275
3276       priv->format_for_printer =
3277         g_strdup (gtk_print_settings_get (settings, "format-for-printer"));
3278     }
3279
3280   if (priv->initial_settings)
3281     g_object_unref (priv->initial_settings);
3282
3283   priv->initial_settings = settings;
3284
3285   g_free (priv->waiting_for_printer);
3286   priv->waiting_for_printer = NULL;
3287   
3288   if (settings)
3289     {
3290       g_object_ref (settings);
3291
3292       printer = gtk_print_settings_get_printer (settings);
3293       
3294       if (printer && !set_active_printer (dialog, printer))
3295         priv->waiting_for_printer = g_strdup (printer); 
3296     }
3297
3298   g_object_notify (G_OBJECT (dialog), "print-settings");
3299 }
3300
3301 /**
3302  * gtk_print_unix_dialog_get_settings:
3303  * @dialog: a #GtkPrintUnixDialog
3304  * 
3305  * Gets a new #GtkPrintSettings object that represents the
3306  * current values in the print dialog. Note that this creates a
3307  * <emphasis>new object</emphasis>, and you need to unref it
3308  * if don't want to keep it.
3309  * 
3310  * Returns: a new #GtkPrintSettings object with the values from @dialog
3311  *
3312  * Since: 2.10
3313  */
3314 GtkPrintSettings *
3315 gtk_print_unix_dialog_get_settings (GtkPrintUnixDialog *dialog)
3316 {
3317   GtkPrintUnixDialogPrivate *priv;
3318   GtkPrintSettings *settings;
3319   GtkPrintPages print_pages;
3320   GtkPageRange *ranges;
3321   gint n_ranges;
3322
3323   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
3324
3325   priv = dialog->priv;
3326   settings = gtk_print_settings_new ();
3327
3328   if (priv->current_printer)
3329     gtk_print_settings_set_printer (settings,
3330                                     gtk_printer_get_name (priv->current_printer));
3331   else
3332     gtk_print_settings_set_printer (settings, "default");
3333   
3334   gtk_print_settings_set (settings, "format-for-printer",
3335                           priv->format_for_printer);
3336
3337   
3338   gtk_print_settings_set_collate (settings,
3339                                   dialog_get_collate (dialog));
3340   
3341   gtk_print_settings_set_reverse (settings,
3342                                   dialog_get_reverse (dialog));
3343   
3344   gtk_print_settings_set_n_copies (settings,
3345                                    dialog_get_n_copies (dialog));
3346
3347   gtk_print_settings_set_scale (settings,
3348                                 dialog_get_scale (dialog));
3349   
3350   gtk_print_settings_set_page_set (settings,
3351                                    dialog_get_page_set (dialog));
3352   
3353   print_pages = dialog_get_print_pages (dialog);
3354   gtk_print_settings_set_print_pages (settings, print_pages);
3355
3356   ranges = dialog_get_page_ranges (dialog, &n_ranges);
3357   if (ranges)
3358     {
3359       gtk_print_settings_set_page_ranges  (settings, ranges, n_ranges);
3360       g_free (ranges);
3361     }
3362
3363   /* TODO: print when. How to handle? */
3364
3365   if (priv->current_printer)
3366     _gtk_printer_get_settings_from_options (priv->current_printer,
3367                                             priv->options,
3368                                             settings);
3369   
3370   return settings;
3371 }
3372
3373 /**
3374  * gtk_print_unix_dialog_add_custom_tab:
3375  * @dialog: a #GtkPrintUnixDialog
3376  * @child: the widget to put in the custom tab
3377  * @tab_label: the widget to use as tab label
3378  *
3379  * Adds a custom tab to the print dialog.
3380  *
3381  * Since: 2.10
3382  */
3383 void
3384 gtk_print_unix_dialog_add_custom_tab (GtkPrintUnixDialog *dialog,
3385                                       GtkWidget          *child,
3386                                       GtkWidget          *tab_label)
3387 {
3388   gtk_notebook_insert_page (GTK_NOTEBOOK (dialog->priv->notebook),
3389                             child, tab_label, 2);
3390   gtk_widget_show (child);
3391   gtk_widget_show (tab_label);
3392 }
3393
3394 /**
3395  * gtk_print_unix_dialog_set_manual_capabilities:
3396  * @dialog: a #GtkPrintUnixDialog
3397  * @capabilities: the printing capabilities of your application
3398  *
3399  * This lets you specify the printing capabilities your application
3400  * supports. For instance, if you can handle scaling the output then
3401  * you pass #GTK_PRINT_CAPABILITY_SCALE. If you don't pass that, then
3402  * the dialog will only let you select the scale if the printing
3403  * system automatically handles scaling.
3404  *
3405  * Since: 2.10
3406  */
3407 void
3408 gtk_print_unix_dialog_set_manual_capabilities (GtkPrintUnixDialog   *dialog,
3409                                                GtkPrintCapabilities  capabilities)
3410 {
3411   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3412
3413   priv->manual_capabilities = capabilities;
3414   update_dialog_from_capabilities (dialog);
3415
3416   if (priv->current_printer)
3417     {
3418       GtkTreeSelection *selection;
3419
3420       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
3421
3422       g_object_unref (priv->current_printer);
3423       priv->current_printer = NULL;
3424       priv->internal_printer_change = TRUE;
3425       selected_printer_changed (selection, dialog);
3426       priv->internal_printer_change = FALSE;
3427    }
3428 }
3429
3430 #define __GTK_PRINT_UNIX_DIALOG_C__
3431 #include "gtkaliasdef.c"
3432