]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintunixdialog.c
9f4cd6123a566827ca60e0e3191d69a97413b5b3
[~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     printer_list_initialize (dialog, GTK_PRINT_BACKEND (node->data));
761 }
762
763 static void
764 gtk_print_unix_dialog_set_property (GObject      *object,
765                                     guint         prop_id,
766                                     const GValue *value,
767                                     GParamSpec   *pspec)
768
769 {
770   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
771
772   switch (prop_id)
773     {
774     case PROP_PAGE_SETUP:
775       gtk_print_unix_dialog_set_page_setup (dialog, g_value_get_object (value));
776       break;
777     case PROP_CURRENT_PAGE:
778       gtk_print_unix_dialog_set_current_page (dialog, g_value_get_int (value));
779       break;
780     case PROP_PRINT_SETTINGS:
781       gtk_print_unix_dialog_set_settings (dialog, g_value_get_object (value));
782       break;
783     default:
784       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
785       break;
786     }
787 }
788
789 static void
790 gtk_print_unix_dialog_get_property (GObject    *object,
791                                     guint       prop_id,
792                                     GValue     *value,
793                                     GParamSpec *pspec)
794 {
795   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
796   GtkPrintUnixDialogPrivate *priv = dialog->priv;
797
798   switch (prop_id)
799     {
800     case PROP_PAGE_SETUP:
801       g_value_set_object (value, priv->page_setup);
802       break;
803     case PROP_CURRENT_PAGE:
804       g_value_set_int (value, priv->current_page);
805       break;
806     case PROP_PRINT_SETTINGS:
807       g_value_take_object (value, gtk_print_unix_dialog_get_settings (dialog));
808       break;
809     case PROP_SELECTED_PRINTER:
810       g_value_set_object (value, priv->current_printer);
811       break;
812     default:
813       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
814       break;
815     }
816 }
817
818 static gboolean
819 is_printer_active (GtkTreeModel       *model,
820                    GtkTreeIter        *iter,
821                    GtkPrintUnixDialog *dialog)
822 {
823   gboolean result;
824   GtkPrinter *printer;
825   GtkPrintUnixDialogPrivate *priv = dialog->priv;
826
827   gtk_tree_model_get (model,
828                       iter,
829                       PRINTER_LIST_COL_PRINTER_OBJ,
830                       &printer,
831                       -1);
832   
833   if (printer == NULL)
834     return FALSE;
835
836   result = gtk_printer_is_active (printer);
837   
838   if (result && 
839       priv->manual_capabilities & (GTK_PRINT_CAPABILITY_GENERATE_PDF |
840                                    GTK_PRINT_CAPABILITY_GENERATE_PS))
841     {
842        /* Check that the printer can handle at least one of the data 
843         * formats that the application supports.
844         */
845        result = ((priv->manual_capabilities & GTK_PRINT_CAPABILITY_GENERATE_PDF) &&
846                  gtk_printer_accepts_pdf (printer)) ||
847                 ((priv->manual_capabilities & GTK_PRINT_CAPABILITY_GENERATE_PS) &&
848                  gtk_printer_accepts_ps (printer));
849     }
850   
851   g_object_unref (printer);
852   
853   return result;
854 }
855
856 static gint
857 default_printer_list_sort_func (GtkTreeModel *model,
858                                 GtkTreeIter  *a,
859                                 GtkTreeIter  *b,
860                                 gpointer      user_data)
861 {
862   gchar *a_name;
863   gchar *b_name;
864   GtkPrinter *a_printer;
865   GtkPrinter *b_printer;
866   gint result;
867
868   gtk_tree_model_get (model, a, 
869                       PRINTER_LIST_COL_NAME, &a_name, 
870                       PRINTER_LIST_COL_PRINTER_OBJ, &a_printer,
871                       -1);
872   gtk_tree_model_get (model, b, 
873                       PRINTER_LIST_COL_NAME, &b_name,
874                       PRINTER_LIST_COL_PRINTER_OBJ, &b_printer,
875                       -1);
876
877   if (a_printer == NULL && b_printer == NULL)
878     result = 0;
879   else if (a_printer == NULL)
880    result = G_MAXINT;
881   else if (b_printer == NULL)
882    result = G_MININT;
883   else if (gtk_printer_is_virtual (a_printer) && gtk_printer_is_virtual (b_printer))
884     result = 0;
885   else if (gtk_printer_is_virtual (a_printer) && !gtk_printer_is_virtual (b_printer))
886     result = G_MININT;
887   else if (!gtk_printer_is_virtual (a_printer) && gtk_printer_is_virtual (b_printer))
888     result = G_MAXINT;
889   else if (a_name == NULL && b_name == NULL)
890     result = 0;
891   else if (a_name == NULL && b_name != NULL)
892     result = 1;
893   else if (a_name != NULL && b_name == NULL)
894     result = -1;
895   else
896     result = g_ascii_strcasecmp (a_name, b_name);
897
898   g_free (a_name);
899   g_free (b_name);
900   g_object_unref (a_printer);
901   g_object_unref (b_printer);
902
903   return result;
904 }
905
906
907 static void
908 create_printer_list_model (GtkPrintUnixDialog *dialog)
909 {
910   GtkPrintUnixDialogPrivate *priv = dialog->priv;
911   GtkListStore *model;
912   GtkTreeSortable *sort;
913
914   model = gtk_list_store_new (PRINTER_LIST_N_COLS,
915                               G_TYPE_STRING,
916                               G_TYPE_STRING, 
917                               G_TYPE_STRING, 
918                               G_TYPE_INT, 
919                               G_TYPE_STRING,
920                               G_TYPE_OBJECT);
921
922   priv->printer_list = (GtkTreeModel *)model;
923   priv->printer_list_filter = (GtkTreeModelFilter *) gtk_tree_model_filter_new ((GtkTreeModel *)model,
924                                                                                         NULL);
925
926   gtk_tree_model_filter_set_visible_func (priv->printer_list_filter,
927                                           (GtkTreeModelFilterVisibleFunc) is_printer_active,
928                                           dialog,
929                                           NULL);
930
931   sort = GTK_TREE_SORTABLE (model);
932   gtk_tree_sortable_set_default_sort_func (sort,
933                                            default_printer_list_sort_func,
934                                            NULL,
935                                            NULL);
936  
937   gtk_tree_sortable_set_sort_column_id (sort,
938                                         GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
939                                         GTK_SORT_ASCENDING);
940
941 }
942
943
944 static GtkWidget *
945 wrap_in_frame (const gchar *label, 
946                GtkWidget   *child)
947 {
948   GtkWidget *frame, *alignment, *label_widget;
949   gchar *bold_text;
950
951   label_widget = gtk_label_new (NULL);
952   gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
953   gtk_widget_show (label_widget);
954   
955   bold_text = g_markup_printf_escaped ("<b>%s</b>", label);
956   gtk_label_set_markup (GTK_LABEL (label_widget), bold_text);
957   g_free (bold_text);
958   
959   frame = gtk_vbox_new (FALSE, 6);
960   gtk_box_pack_start (GTK_BOX (frame), label_widget, FALSE, FALSE, 0);
961   
962   alignment = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
963   gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
964                              0, 0, 12, 0);
965   gtk_box_pack_start (GTK_BOX (frame), alignment, FALSE, FALSE, 0);
966
967   gtk_container_add (GTK_CONTAINER (alignment), child);
968
969   gtk_widget_show (frame);
970   gtk_widget_show (alignment);
971   
972   return frame;
973 }
974
975 static gboolean
976 setup_option (GtkPrintUnixDialog     *dialog,
977               const gchar            *option_name,
978               GtkPrinterOptionWidget *widget)
979 {
980   GtkPrintUnixDialogPrivate *priv = dialog->priv;
981   GtkPrinterOption *option;
982
983   option = gtk_printer_option_set_lookup (priv->options, option_name);
984   gtk_printer_option_widget_set_source (widget, option);
985
986   return option != NULL;
987 }
988
989 static void
990 add_option_to_extension_point (GtkPrinterOption *option,
991                                gpointer          data)
992 {
993   GtkWidget *extension_point = data;
994   GtkWidget *widget;
995
996   widget = gtk_printer_option_widget_new (option);
997   gtk_widget_show (widget);
998    
999   if (gtk_printer_option_widget_has_external_label (GTK_PRINTER_OPTION_WIDGET (widget)))
1000     {
1001       GtkWidget *label, *hbox;
1002       
1003       label = gtk_printer_option_widget_get_external_label (GTK_PRINTER_OPTION_WIDGET (widget));
1004       gtk_widget_show (label);
1005       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1006       gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
1007       
1008       hbox = gtk_hbox_new (FALSE, 12);
1009       gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1010       gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
1011       gtk_widget_show (hbox);
1012       
1013       gtk_box_pack_start (GTK_BOX (extension_point), hbox, FALSE, FALSE, 0);
1014     }
1015   else
1016     gtk_box_pack_start (GTK_BOX (extension_point), widget, FALSE, FALSE, 0);
1017 }
1018
1019 static void
1020 add_option_to_table (GtkPrinterOption *option,
1021                      gpointer          user_data)
1022 {
1023   GtkTable *table;
1024   GtkWidget *label, *widget;
1025   gint row;
1026
1027   table = GTK_TABLE (user_data);
1028   
1029   if (g_str_has_prefix (option->name, "gtk-"))
1030     return;
1031   
1032   widget = gtk_printer_option_widget_new (option);
1033   gtk_widget_show (widget);
1034
1035   row = table->nrows;
1036   gtk_table_resize (table, table->nrows + 1, 2);
1037   
1038   if (gtk_printer_option_widget_has_external_label (GTK_PRINTER_OPTION_WIDGET (widget)))
1039     {
1040       label = gtk_printer_option_widget_get_external_label (GTK_PRINTER_OPTION_WIDGET (widget));
1041       gtk_widget_show (label);
1042
1043       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1044       gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
1045
1046       gtk_table_attach (table, label,
1047                         0, 1, row - 1 , row,  GTK_FILL, 0, 0, 0);
1048       
1049       gtk_table_attach (table, widget,
1050                         1, 2, row - 1, row,  GTK_FILL, 0, 0, 0);
1051     }
1052   else
1053     gtk_table_attach (table, widget,
1054                       0, 2, row - 1, row,  GTK_FILL, 0, 0, 0);
1055 }
1056
1057
1058 static void
1059 setup_page_table (GtkPrinterOptionSet *options,
1060                   const gchar         *group,
1061                   GtkWidget           *table,
1062                   GtkWidget           *page)
1063 {
1064   gtk_printer_option_set_foreach_in_group (options, group,
1065                                            add_option_to_table,
1066                                            table);
1067   if (GTK_TABLE (table)->nrows == 1)
1068     gtk_widget_hide (page);
1069   else
1070     gtk_widget_show (page);
1071 }
1072
1073 static void
1074 update_print_at_option (GtkPrintUnixDialog *dialog)
1075 {
1076   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1077   GtkPrinterOption *option;
1078   
1079   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time");
1080
1081   if (option == NULL)
1082     return;
1083   
1084   if (priv->updating_print_at)
1085     return;
1086
1087   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->print_at_radio)))
1088     gtk_printer_option_set (option, "at");
1089   else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->print_hold_radio)))
1090     gtk_printer_option_set (option, "on-hold");
1091   else
1092     gtk_printer_option_set (option, "now");
1093
1094   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time-text");
1095   if (option != NULL)
1096     {
1097       const char *text = gtk_entry_get_text (GTK_ENTRY (priv->print_at_entry));
1098       gtk_printer_option_set (option, text);
1099     }
1100 }
1101
1102
1103 static gboolean
1104 setup_print_at (GtkPrintUnixDialog *dialog)
1105 {
1106   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1107   GtkPrinterOption *option;
1108
1109   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time");
1110
1111   if (option == NULL)
1112     {
1113       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_now_radio),
1114                                     TRUE);
1115       gtk_widget_set_sensitive (priv->print_at_radio, FALSE);
1116       gtk_widget_set_sensitive (priv->print_at_entry, FALSE);
1117       gtk_widget_set_sensitive (priv->print_hold_radio, FALSE);
1118       gtk_entry_set_text (GTK_ENTRY (priv->print_at_entry), "");
1119       return FALSE;
1120     }
1121
1122   priv->updating_print_at = TRUE;
1123
1124   gtk_widget_set_sensitive (priv->print_at_entry, FALSE);
1125   gtk_widget_set_sensitive (priv->print_at_radio,
1126                             gtk_printer_option_has_choice (option, "at"));
1127
1128   gtk_widget_set_sensitive (priv->print_hold_radio,
1129                             gtk_printer_option_has_choice (option, "on-hold"));
1130
1131   update_print_at_option (dialog);
1132
1133   if (strcmp (option->value, "at") == 0)
1134     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_at_radio),
1135                                   TRUE);
1136   else if (strcmp (option->value, "on-hold") == 0)
1137     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_hold_radio),
1138                                   TRUE);
1139   else
1140     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_now_radio),
1141                                   TRUE);
1142
1143   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time-text");
1144   if (option != NULL)
1145     gtk_entry_set_text (GTK_ENTRY (priv->print_at_entry), option->value);
1146
1147
1148   priv->updating_print_at = FALSE;
1149
1150   return TRUE;
1151 }
1152
1153 static void
1154 update_dialog_from_settings (GtkPrintUnixDialog *dialog)
1155 {
1156   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1157   GList *groups, *l;
1158   gchar *group;
1159   GtkWidget *table, *frame;
1160   gboolean has_advanced, has_job;
1161  
1162   if (priv->current_printer == NULL)
1163     {
1164        clear_per_printer_ui (dialog);
1165        gtk_widget_hide (priv->job_page);
1166        gtk_widget_hide (priv->advanced_page);
1167        gtk_widget_hide (priv->image_quality_page);
1168        gtk_widget_hide (priv->finishing_page);
1169        gtk_widget_hide (priv->color_page);
1170        gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
1171
1172        return;
1173     }
1174  
1175   setup_option (dialog, "gtk-n-up", priv->pages_per_sheet);
1176   setup_option (dialog, "gtk-n-up-layout", priv->number_up_layout);
1177   setup_option (dialog, "gtk-duplex", priv->duplex);
1178   setup_option (dialog, "gtk-paper-type", priv->paper_type);
1179   setup_option (dialog, "gtk-paper-source", priv->paper_source);
1180   setup_option (dialog, "gtk-output-tray", priv->output_tray);
1181
1182   has_job = FALSE;
1183   has_job |= setup_option (dialog, "gtk-job-prio", priv->job_prio);
1184   has_job |= setup_option (dialog, "gtk-billing-info", priv->billing_info);
1185   has_job |= setup_option (dialog, "gtk-cover-before", priv->cover_before);
1186   has_job |= setup_option (dialog, "gtk-cover-after", priv->cover_after);
1187   has_job |= setup_print_at (dialog);
1188   
1189   if (has_job)
1190     gtk_widget_show (priv->job_page);
1191   else
1192     gtk_widget_hide (priv->job_page);
1193
1194   
1195   setup_page_table (priv->options,
1196                     "ImageQualityPage",
1197                     priv->image_quality_table,
1198                     priv->image_quality_page);
1199   
1200   setup_page_table (priv->options,
1201                     "FinishingPage",
1202                     priv->finishing_table,
1203                     priv->finishing_page);
1204
1205   setup_page_table (priv->options,
1206                     "ColorPage",
1207                     priv->color_table,
1208                     priv->color_page);
1209
1210   gtk_printer_option_set_foreach_in_group (priv->options,
1211                                            "GtkPrintDialogExtension",
1212                                            add_option_to_extension_point,
1213                                            priv->extension_point);
1214
1215   /* Put the rest of the groups in the advanced page */
1216   groups = gtk_printer_option_set_get_groups (priv->options);
1217
1218   has_advanced = FALSE;
1219   for (l = groups; l != NULL; l = l->next)
1220     {
1221       group = l->data;
1222
1223       if (group == NULL)
1224         continue;
1225       
1226       if (strcmp (group, "ImageQualityPage") == 0 ||
1227           strcmp (group, "ColorPage") == 0 ||
1228           strcmp (group, "FinishingPage") == 0 ||
1229           strcmp (group, "GtkPrintDialogExtension") == 0)
1230         continue;
1231
1232       table = gtk_table_new (1, 2, FALSE);
1233       gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1234       gtk_table_set_col_spacings (GTK_TABLE (table), 12);
1235       
1236       gtk_printer_option_set_foreach_in_group (priv->options,
1237                                                group,
1238                                                add_option_to_table,
1239                                                table);
1240       if (GTK_TABLE (table)->nrows == 1)
1241         gtk_widget_destroy (table);
1242       else
1243         {
1244           has_advanced = TRUE;
1245           frame = wrap_in_frame (group, table);
1246           gtk_widget_show (table);
1247           gtk_widget_show (frame);
1248           
1249           gtk_box_pack_start (GTK_BOX (priv->advanced_vbox),
1250                               frame, FALSE, FALSE, 0);
1251         }
1252     }
1253
1254   if (has_advanced)
1255     gtk_widget_show (priv->advanced_page);
1256   else
1257     gtk_widget_hide (priv->advanced_page);
1258
1259   
1260   g_list_foreach (groups, (GFunc) g_free, NULL);
1261   g_list_free (groups);
1262 }
1263
1264 static void
1265 update_dialog_from_capabilities (GtkPrintUnixDialog *dialog)
1266 {
1267   GtkPrintCapabilities caps;
1268   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1269   gboolean can_collate;
1270   const gchar *copies;
1271
1272   copies = gtk_entry_get_text (GTK_ENTRY (priv->copies_spin));
1273   can_collate = (*copies != '\0' && atoi (copies) > 1);
1274
1275   caps = priv->manual_capabilities | priv->printer_capabilities;
1276
1277   gtk_widget_set_sensitive (priv->page_set_combo,
1278                             caps & GTK_PRINT_CAPABILITY_PAGE_SET);
1279   gtk_widget_set_sensitive (priv->copies_spin,
1280                             caps & GTK_PRINT_CAPABILITY_COPIES);
1281   gtk_widget_set_sensitive (priv->collate_check,
1282                             can_collate && 
1283                             (caps & GTK_PRINT_CAPABILITY_COLLATE));
1284   gtk_widget_set_sensitive (priv->reverse_check,
1285                             caps & GTK_PRINT_CAPABILITY_REVERSE);
1286   gtk_widget_set_sensitive (priv->scale_spin,
1287                             caps & GTK_PRINT_CAPABILITY_SCALE);
1288   gtk_widget_set_sensitive (GTK_WIDGET (priv->pages_per_sheet),
1289                             caps & GTK_PRINT_CAPABILITY_NUMBER_UP);
1290
1291   if (caps & GTK_PRINT_CAPABILITY_PREVIEW)
1292     gtk_widget_show (priv->preview_button);
1293   else
1294     gtk_widget_hide (priv->preview_button);
1295
1296   update_collate_icon (NULL, dialog);
1297
1298   gtk_tree_model_filter_refilter (priv->printer_list_filter);
1299 }
1300
1301 static void
1302 mark_conflicts (GtkPrintUnixDialog *dialog)
1303 {
1304   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1305   GtkPrinter *printer;
1306   gboolean have_conflict;
1307
1308   have_conflict = FALSE;
1309
1310   printer = priv->current_printer;
1311
1312   if (printer)
1313     {
1314
1315       g_signal_handler_block (priv->options,
1316                               priv->options_changed_handler);
1317       
1318       gtk_printer_option_set_clear_conflicts (priv->options);
1319       
1320       have_conflict = _gtk_printer_mark_conflicts (printer,
1321                                                    priv->options);
1322       
1323       g_signal_handler_unblock (priv->options,
1324                                 priv->options_changed_handler);
1325     }
1326
1327   if (have_conflict)
1328     gtk_widget_show (priv->conflicts_widget);
1329   else
1330     gtk_widget_hide (priv->conflicts_widget);
1331 }
1332
1333 static gboolean
1334 mark_conflicts_callback (gpointer data)
1335 {
1336   GtkPrintUnixDialog *dialog = data;
1337   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1338
1339   priv->mark_conflicts_id = 0;
1340
1341   mark_conflicts (dialog);
1342
1343   return FALSE;
1344 }
1345
1346 static void
1347 unschedule_idle_mark_conflicts (GtkPrintUnixDialog *dialog)
1348 {
1349   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1350
1351   if (priv->mark_conflicts_id != 0)
1352     {
1353       g_source_remove (priv->mark_conflicts_id);
1354       priv->mark_conflicts_id = 0;
1355     }
1356 }
1357
1358 static void
1359 schedule_idle_mark_conflicts (GtkPrintUnixDialog *dialog)
1360 {
1361   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1362
1363   if (priv->mark_conflicts_id != 0)
1364     return;
1365
1366   priv->mark_conflicts_id = gdk_threads_add_idle (mark_conflicts_callback,
1367                                         dialog);
1368 }
1369
1370 static void
1371 options_changed_cb (GtkPrintUnixDialog *dialog)
1372 {
1373   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1374
1375   schedule_idle_mark_conflicts (dialog);
1376
1377   if (priv->initial_settings)
1378     {
1379       g_object_unref (priv->initial_settings);
1380       priv->initial_settings = NULL;
1381     }
1382
1383   g_free (priv->waiting_for_printer);
1384   priv->waiting_for_printer = NULL;
1385 }
1386
1387 static void
1388 remove_custom_widget (GtkWidget    *widget,
1389                       GtkContainer *container)
1390 {
1391   gtk_container_remove (container, widget);
1392 }
1393
1394 static void
1395 extension_point_clear_children (GtkContainer *container)
1396 {
1397   gtk_container_foreach (container,
1398                          (GtkCallback)remove_custom_widget,
1399                          container);
1400 }
1401
1402 static void
1403 clear_per_printer_ui (GtkPrintUnixDialog *dialog)
1404 {
1405   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1406
1407   gtk_container_foreach (GTK_CONTAINER (priv->finishing_table),
1408                          (GtkCallback)gtk_widget_destroy,
1409                          NULL);
1410   gtk_table_resize (GTK_TABLE (priv->finishing_table), 1, 2);
1411   gtk_container_foreach (GTK_CONTAINER (priv->image_quality_table),
1412                          (GtkCallback)gtk_widget_destroy,
1413                          NULL);
1414   gtk_table_resize (GTK_TABLE (priv->image_quality_table), 1, 2);
1415   gtk_container_foreach (GTK_CONTAINER (priv->color_table),
1416                          (GtkCallback)gtk_widget_destroy,
1417                          NULL);
1418   gtk_table_resize (GTK_TABLE (priv->color_table), 1, 2);
1419   gtk_container_foreach (GTK_CONTAINER (priv->advanced_vbox),
1420                          (GtkCallback)gtk_widget_destroy,
1421                          NULL);
1422   extension_point_clear_children (GTK_CONTAINER (priv->extension_point));
1423 }
1424
1425 static void
1426 printer_details_acquired (GtkPrinter         *printer,
1427                           gboolean            success,
1428                           GtkPrintUnixDialog *dialog)
1429 {
1430   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1431
1432   disconnect_printer_details_request (dialog);
1433   
1434   if (success)
1435     {
1436       GtkTreeSelection *selection;
1437       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
1438       
1439       selected_printer_changed (selection, dialog);
1440     }
1441 }
1442
1443 static void
1444 selected_printer_changed (GtkTreeSelection   *selection,
1445                           GtkPrintUnixDialog *dialog)
1446 {
1447   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1448   GtkPrinter *printer;
1449   GtkTreeIter iter, filter_iter;
1450
1451   /* Whenever the user selects a printer we stop looking for
1452      the printer specified in the initial settings */
1453   if (priv->waiting_for_printer &&
1454       !priv->internal_printer_change)
1455     {
1456       g_free (priv->waiting_for_printer);
1457       priv->waiting_for_printer = NULL;
1458     }
1459
1460   disconnect_printer_details_request (dialog);
1461
1462   printer = NULL;
1463   if (gtk_tree_selection_get_selected (selection, NULL, &filter_iter))
1464     {
1465       gtk_tree_model_filter_convert_iter_to_child_iter (priv->printer_list_filter,
1466                                                         &iter,
1467                                                         &filter_iter);
1468
1469       gtk_tree_model_get (priv->printer_list, &iter,
1470                           PRINTER_LIST_COL_PRINTER_OBJ, &printer,
1471                           -1);
1472     }
1473
1474   /* sets GTK_RESPONSE_OK button sensitive/insensitive depending on whether the printer 
1475    * accepts/rejects jobs */
1476   if (printer != NULL)
1477     {
1478       if (!gtk_printer_is_accepting_jobs (printer))
1479         {
1480           gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
1481         }
1482       else
1483         {
1484           if (priv->current_printer == printer && gtk_printer_has_details (printer))
1485             gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
1486         }
1487     }
1488   
1489   if (printer != NULL && !gtk_printer_has_details (printer))
1490     {
1491       gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
1492       priv->request_details_tag =
1493         g_signal_connect (printer, "details-acquired",
1494                           G_CALLBACK (printer_details_acquired), dialog);
1495       /* take the reference */
1496       priv->request_details_printer = printer;
1497       gtk_printer_request_details (printer);
1498       return;
1499     }
1500   
1501   if (printer == priv->current_printer)
1502     {
1503       if (printer)
1504         g_object_unref (printer);
1505       return;
1506     }
1507
1508   if (priv->options)
1509     {
1510       g_object_unref (priv->options);
1511       priv->options = NULL;  
1512
1513       clear_per_printer_ui (dialog);
1514     }
1515
1516   if (priv->current_printer)
1517     {
1518       g_object_unref (priv->current_printer);
1519     }
1520
1521   priv->printer_capabilities = 0;
1522   
1523   if (gtk_printer_is_accepting_jobs (printer))
1524     gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
1525   priv->current_printer = printer;
1526
1527   if (printer != NULL)
1528     {
1529       if (!priv->page_setup_set)
1530         {
1531           /* if no explicit page setup has been set, use the printer default */   
1532           GtkPageSetup *page_setup;
1533
1534           page_setup = gtk_printer_get_default_page_size (printer);
1535
1536           if (!page_setup)
1537             page_setup = gtk_page_setup_new ();
1538
1539           g_object_unref (priv->page_setup);
1540           priv->page_setup = page_setup;
1541         }
1542
1543       priv->printer_capabilities = gtk_printer_get_capabilities (printer);
1544       priv->options = _gtk_printer_get_options (printer, 
1545                                                 priv->initial_settings,
1546                                                 priv->page_setup,
1547                                                 priv->manual_capabilities);
1548   
1549       priv->options_changed_handler = 
1550         g_signal_connect_swapped (priv->options, "changed", G_CALLBACK (options_changed_cb), dialog);
1551     }
1552
1553   update_dialog_from_settings (dialog);
1554   update_dialog_from_capabilities (dialog);
1555
1556   g_object_notify ( G_OBJECT(dialog), "selected-printer");
1557 }
1558
1559 static void
1560 update_collate_icon (GtkToggleButton    *toggle_button,
1561                      GtkPrintUnixDialog *dialog)
1562 {
1563   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1564
1565   gtk_widget_queue_draw (priv->collate_image);
1566 }
1567
1568 static void
1569 paint_page (GtkWidget *widget,
1570             cairo_t   *cr, 
1571             gfloat     scale,
1572             gint       x_offset, 
1573             gint       y_offset,
1574             gchar     *text,
1575             gint       text_x)
1576 {
1577   gint x, y, width, height;
1578   gint text_y, linewidth;
1579
1580   x = x_offset * scale;
1581   y = y_offset * scale;
1582   width = 20 * scale;
1583   height = 26 * scale;
1584
1585   linewidth = 2;
1586   text_y = 21;
1587
1588   gdk_cairo_set_source_color (cr, &widget->style->base[GTK_STATE_NORMAL]);
1589   cairo_rectangle (cr, x, y, width, height);
1590   cairo_fill (cr);
1591
1592   gdk_cairo_set_source_color (cr, &widget->style->text[GTK_STATE_NORMAL]);
1593   cairo_set_line_width (cr, linewidth);
1594   cairo_rectangle (cr, x + linewidth/2.0, y + linewidth/2.0, width - linewidth, height - linewidth);
1595   cairo_stroke (cr);
1596
1597   cairo_select_font_face (cr, "Sans", 
1598                           CAIRO_FONT_SLANT_NORMAL,
1599                           CAIRO_FONT_WEIGHT_NORMAL);
1600   cairo_set_font_size (cr, (gint)(9 * scale));
1601   cairo_move_to (cr, x + (gint)(text_x * scale), y + (gint)(text_y * scale));
1602   cairo_show_text (cr, text);
1603 }
1604
1605
1606 static gboolean
1607 draw_collate_cb (GtkWidget          *widget,
1608                  GdkEventExpose     *event,
1609                  GtkPrintUnixDialog *dialog)
1610 {
1611   GtkSettings *settings;
1612   cairo_t *cr;
1613   gint size;
1614   gfloat scale;
1615   gboolean collate, reverse, rtl;
1616   gint copies;
1617   gint text_x;
1618
1619   collate = dialog_get_collate (dialog);
1620   reverse = dialog_get_reverse (dialog);
1621   copies = dialog_get_n_copies (dialog);
1622
1623   rtl = (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_RTL);
1624
1625   settings = gtk_widget_get_settings (widget);
1626   gtk_icon_size_lookup_for_settings (settings,
1627                                      GTK_ICON_SIZE_DIALOG,
1628                                      &size,
1629                                      NULL);
1630   scale = size / 48.0;
1631   text_x = rtl ? 4 : 11;
1632
1633   cr = gdk_cairo_create (widget->window);
1634
1635   cairo_translate (cr, widget->allocation.x, widget->allocation.y);
1636
1637   if (copies == 1)
1638     {
1639       paint_page (widget, cr, scale, rtl ? 40: 15, 5, reverse ? "1" : "2", text_x);
1640       paint_page (widget, cr, scale, rtl ? 50: 5, 15, reverse ? "2" : "1", text_x);
1641     }
1642   else
1643     {
1644       paint_page (widget, cr, scale, rtl ? 40: 15, 5, collate == reverse ? "1" : "2", text_x);
1645       paint_page (widget, cr, scale, rtl ? 50: 5, 15, reverse ? "2" : "1", text_x);
1646
1647       paint_page (widget, cr, scale, rtl ? 5 : 50, 5, reverse ? "1" : "2", text_x);
1648       paint_page (widget, cr, scale, rtl ? 15 : 40, 15, collate == reverse ? "2" : "1", text_x);
1649     }
1650
1651   cairo_destroy (cr);
1652
1653   return TRUE;
1654 }
1655
1656 static void
1657 gtk_print_unix_dialog_style_set (GtkWidget *widget,
1658                                  GtkStyle  *previous_style)
1659 {
1660   GTK_WIDGET_CLASS (gtk_print_unix_dialog_parent_class)->style_set (widget, previous_style);
1661
1662   if (gtk_widget_has_screen (widget))
1663     {
1664       GtkPrintUnixDialog *dialog = (GtkPrintUnixDialog *)widget;
1665       GtkPrintUnixDialogPrivate *priv = dialog->priv;
1666       GtkSettings *settings;
1667       gint size;
1668       gfloat scale;
1669       
1670       settings = gtk_widget_get_settings (widget);
1671       gtk_icon_size_lookup_for_settings (settings,
1672                                          GTK_ICON_SIZE_DIALOG,
1673                                          &size,
1674                                          NULL);
1675       scale = size / 48.0;
1676
1677       gtk_widget_set_size_request (priv->collate_image,
1678                                    (50 + 20) * scale,
1679                                    (15 + 26) * scale);
1680     }
1681 }
1682
1683 static void
1684 update_entry_sensitivity (GtkWidget *button,
1685                           GtkWidget *range)
1686 {
1687   gboolean active;
1688
1689   active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
1690
1691   gtk_widget_set_sensitive (range, active);
1692
1693   if (active)
1694     gtk_widget_grab_focus (range);
1695 }
1696
1697 static void
1698 emit_ok_response (GtkTreeView       *tree_view,
1699                   GtkTreePath       *path,
1700                   GtkTreeViewColumn *column,
1701                   gpointer          *user_data)
1702 {
1703   GtkPrintUnixDialog *print_dialog;
1704
1705   print_dialog = (GtkPrintUnixDialog *) user_data;
1706
1707   gtk_dialog_response (GTK_DIALOG (print_dialog), GTK_RESPONSE_OK);
1708 }
1709
1710 static void
1711 create_main_page (GtkPrintUnixDialog *dialog)
1712 {
1713   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1714   GtkWidget *main_vbox, *label, *vbox, *hbox;
1715   GtkWidget *scrolled, *treeview, *frame, *table;
1716   GtkWidget *entry, *spinbutton;
1717   GtkWidget *radio, *check, *image;
1718   GtkCellRenderer *renderer;
1719   GtkTreeViewColumn *column;
1720   GtkTreeSelection *selection;
1721   GtkWidget *custom_input;
1722   const gchar *range_tooltip;
1723
1724   main_vbox = gtk_vbox_new (FALSE, 18);
1725   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
1726   gtk_widget_show (main_vbox);
1727
1728   vbox = gtk_vbox_new (FALSE, 6);
1729   gtk_box_pack_start (GTK_BOX (main_vbox), vbox, TRUE, TRUE, 0);
1730   gtk_widget_show (vbox);
1731
1732   scrolled = gtk_scrolled_window_new (NULL, NULL);
1733   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1734                                   GTK_POLICY_AUTOMATIC,
1735                                   GTK_POLICY_AUTOMATIC);
1736   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
1737                                        GTK_SHADOW_IN);
1738   gtk_widget_show (scrolled);
1739   gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
1740
1741   treeview = gtk_tree_view_new_with_model ((GtkTreeModel *) priv->printer_list_filter);
1742   priv->printer_treeview = treeview;
1743   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), TRUE);
1744   gtk_tree_view_set_search_column (GTK_TREE_VIEW (treeview), PRINTER_LIST_COL_NAME);
1745   gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
1746   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
1747   gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1748   g_signal_connect (selection, "changed", G_CALLBACK (selected_printer_changed), dialog);
1749  
1750   renderer = gtk_cell_renderer_pixbuf_new ();
1751   column = gtk_tree_view_column_new_with_attributes ("",
1752                                                      renderer,
1753                                                      "icon-name",
1754                                                      PRINTER_LIST_COL_ICON,
1755                                                      NULL);
1756   gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, NULL, NULL);
1757   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1758
1759   renderer = gtk_cell_renderer_text_new ();
1760   column = gtk_tree_view_column_new_with_attributes (_("Printer"),
1761                                                      renderer,
1762                                                      "text",
1763                                                      PRINTER_LIST_COL_NAME,
1764                                                      NULL);
1765   gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, NULL, NULL);
1766   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1767   
1768   renderer = gtk_cell_renderer_text_new ();
1769   /* Translators: this is the header for the location column in the print dialog */
1770   column = gtk_tree_view_column_new_with_attributes (_("Location"),
1771                                                      renderer,
1772                                                      "text",
1773                                                      PRINTER_LIST_COL_LOCATION,
1774                                                      NULL);
1775   gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, NULL, NULL);
1776   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1777
1778   renderer = gtk_cell_renderer_text_new ();
1779   g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
1780   /* Translators: this is the header for the printer status column in the print dialog */
1781   column = gtk_tree_view_column_new_with_attributes (_("Status"),
1782                                                      renderer,
1783                                                      "text",
1784                                                      PRINTER_LIST_COL_STATE,
1785                                                      NULL);
1786   gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, NULL, NULL);
1787   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1788
1789   g_signal_connect (GTK_TREE_VIEW (treeview), "row-activated", G_CALLBACK (emit_ok_response), dialog);
1790   
1791   gtk_widget_show (treeview);
1792   gtk_container_add (GTK_CONTAINER (scrolled), treeview);
1793
1794   custom_input = gtk_hbox_new (FALSE, 18);
1795   gtk_widget_show (custom_input);
1796   gtk_box_pack_start (GTK_BOX (vbox), custom_input, FALSE, FALSE, 0);
1797   priv->extension_point = custom_input;
1798
1799   hbox = gtk_hbox_new (FALSE, 18);
1800   gtk_widget_show (hbox);
1801   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
1802
1803   table = gtk_table_new (3, 2, FALSE);
1804   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1805   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
1806   frame = wrap_in_frame (_("Range"), table);
1807   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
1808   gtk_widget_show (table);
1809
1810   radio = gtk_radio_button_new_with_mnemonic (NULL, _("_All Pages"));
1811   priv->all_pages_radio = radio;
1812   gtk_widget_show (radio);
1813   gtk_table_attach (GTK_TABLE (table), radio,
1814                     0, 2, 0, 1,  GTK_FILL, 0,
1815                     0, 0);
1816   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
1817                                               _("C_urrent Page"));
1818   if (priv->current_page == -1)
1819     gtk_widget_set_sensitive (radio, FALSE);    
1820   priv->current_page_radio = radio;
1821   gtk_widget_show (radio);
1822   gtk_table_attach (GTK_TABLE (table), radio,
1823                     0, 2, 1, 2,  GTK_FILL, 0,
1824                     0, 0);
1825  
1826   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)), _("Pag_es:"));
1827   range_tooltip = _("Specify one or more page ranges,\n e.g. 1-3,7,11");
1828   gtk_widget_set_tooltip_text (radio, range_tooltip);
1829  
1830   priv->page_range_radio = radio;
1831   gtk_widget_show (radio);
1832   gtk_table_attach (GTK_TABLE (table), radio,
1833                     0, 1, 2, 3,  GTK_FILL, 0,
1834                     0, 0);
1835   entry = gtk_entry_new ();
1836   gtk_widget_set_tooltip_text (entry, range_tooltip);
1837   atk_object_set_name (gtk_widget_get_accessible (entry), _("Pages"));
1838   atk_object_set_description (gtk_widget_get_accessible (entry), range_tooltip);
1839   priv->page_range_entry = entry;
1840   gtk_widget_show (entry);
1841   gtk_table_attach (GTK_TABLE (table), entry,
1842                     1, 2, 2, 3,  GTK_FILL, 0,
1843                     0, 0);
1844   g_signal_connect (radio, "toggled", G_CALLBACK (update_entry_sensitivity), entry);
1845   update_entry_sensitivity (radio, entry);
1846
1847   table = gtk_table_new (3, 2, FALSE);
1848   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1849   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
1850   frame = wrap_in_frame (_("Copies"), table);
1851   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
1852   gtk_widget_show (table);
1853
1854   /* FIXME chpe: too much space between Copies and spinbutton, put those 2 in a hbox and make it span 2 columns */
1855   label = gtk_label_new_with_mnemonic (_("Copie_s:"));
1856   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1857   gtk_widget_show (label);
1858   gtk_table_attach (GTK_TABLE (table), label,
1859                     0, 1, 0, 1,  GTK_FILL, 0,
1860                     0, 0);
1861   spinbutton = gtk_spin_button_new_with_range (1.0, 100.0, 1.0);
1862   priv->copies_spin = spinbutton;
1863   gtk_widget_show (spinbutton);
1864   gtk_table_attach (GTK_TABLE (table), spinbutton,
1865                     1, 2, 0, 1,  GTK_FILL, 0,
1866                     0, 0);
1867   gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
1868   g_signal_connect_swapped (spinbutton, "value-changed", 
1869                             G_CALLBACK (update_dialog_from_capabilities), dialog);
1870   g_signal_connect_swapped (spinbutton, "changed", 
1871                             G_CALLBACK (update_dialog_from_capabilities), dialog);
1872   
1873   check = gtk_check_button_new_with_mnemonic (_("C_ollate"));
1874   priv->collate_check = check;
1875   g_signal_connect (check, "toggled", G_CALLBACK (update_collate_icon), dialog);
1876   gtk_widget_show (check);
1877   gtk_table_attach (GTK_TABLE (table), check,
1878                     0, 1, 1, 2,  GTK_FILL, 0,
1879                     0, 0);
1880
1881   check = gtk_check_button_new_with_mnemonic (_("_Reverse"));
1882   g_signal_connect (check, "toggled", G_CALLBACK (update_collate_icon), dialog);
1883   priv->reverse_check = check;
1884   gtk_widget_show (check);
1885   gtk_table_attach (GTK_TABLE (table), check,
1886                     0, 1, 2, 3,  GTK_FILL, 0,
1887                     0, 0);
1888
1889   image = gtk_drawing_area_new ();
1890   GTK_WIDGET_SET_FLAGS (image, GTK_NO_WINDOW);
1891
1892   priv->collate_image = image;
1893   gtk_widget_show (image);
1894   gtk_widget_set_size_request (image, 70, 90);
1895   gtk_table_attach (GTK_TABLE (table), image,
1896                     1, 2, 1, 3, GTK_FILL, 0,
1897                     0, 0);
1898   g_signal_connect (image, "expose-event",
1899                     G_CALLBACK (draw_collate_cb), dialog);
1900
1901   label = gtk_label_new (_("General"));
1902   gtk_widget_show (label);
1903   
1904   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), main_vbox, label);
1905 }
1906
1907 static gboolean
1908 is_range_separator (gchar c)
1909 {
1910   return (c == ',' || c == ';' || c == ':');
1911 }
1912
1913 static GtkPageRange *
1914 dialog_get_page_ranges (GtkPrintUnixDialog *dialog,
1915                         gint               *n_ranges_out)
1916 {
1917   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1918   gint i, n_ranges;
1919   const gchar *text, *p;
1920   gchar *next;
1921   GtkPageRange *ranges;
1922   gint start, end;
1923   
1924   text = gtk_entry_get_text (GTK_ENTRY (priv->page_range_entry));
1925
1926   if (*text == 0)
1927     {
1928       *n_ranges_out = 0;
1929       return NULL;
1930     }
1931   
1932   n_ranges = 1;
1933   p = text;
1934   while (*p)
1935     {
1936       if (is_range_separator (*p))
1937         n_ranges++;
1938       p++;
1939     }
1940
1941   ranges = g_new0 (GtkPageRange, n_ranges);
1942   
1943   i = 0;
1944   p = text;
1945   while (*p)
1946     {
1947       while (isspace (*p)) p++;
1948
1949       if (*p == '-')
1950         {
1951           /* a half-open range like -2 */
1952           start = 1;
1953         }
1954       else
1955         {
1956           start = (int)strtol (p, &next, 10);
1957           if (start < 1)
1958             start = 1;
1959           p = next;
1960         }
1961       
1962       end = start;
1963
1964       while (isspace (*p)) p++;
1965
1966       if (*p == '-')
1967         {
1968           p++;
1969           end = (int)strtol (p, &next, 10);
1970           if (next == p) /* a half-open range like 2- */
1971             end = 0;
1972           else if (end < start)
1973             end = start;
1974         }
1975
1976       ranges[i].start = start - 1;
1977       ranges[i].end = end - 1;
1978       i++;
1979
1980       /* Skip until end or separator */
1981       while (*p && !is_range_separator (*p))
1982         p++;
1983
1984       /* if not at end, skip separator */
1985       if (*p)
1986         p++;
1987     }
1988
1989   *n_ranges_out = i;
1990   
1991   return ranges;
1992 }
1993
1994 static void
1995 dialog_set_page_ranges (GtkPrintUnixDialog *dialog,
1996                         GtkPageRange       *ranges,
1997                         gint                n_ranges)
1998 {
1999   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2000   gint i;
2001   GString *s = g_string_new (NULL);
2002
2003   for (i = 0; i < n_ranges; i++)
2004     {
2005       g_string_append_printf (s, "%d", ranges[i].start + 1);
2006       if (ranges[i].end > ranges[i].start)
2007         g_string_append_printf (s, "-%d", ranges[i].end + 1);
2008       else if (ranges[i].end == -1)
2009         g_string_append (s, "-");
2010       
2011       if (i != n_ranges - 1)
2012         g_string_append (s, ",");
2013     }
2014
2015   gtk_entry_set_text (GTK_ENTRY (priv->page_range_entry), s->str);
2016   
2017   g_string_free (s, TRUE);
2018 }
2019
2020
2021 static GtkPrintPages
2022 dialog_get_print_pages (GtkPrintUnixDialog *dialog)
2023 {
2024   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2025   
2026   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->all_pages_radio)))
2027     return GTK_PRINT_PAGES_ALL;
2028   else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->current_page_radio)))
2029     return GTK_PRINT_PAGES_CURRENT;
2030   else
2031     return GTK_PRINT_PAGES_RANGES;
2032 }
2033
2034 static void
2035 dialog_set_print_pages (GtkPrintUnixDialog *dialog, 
2036                         GtkPrintPages       pages)
2037 {
2038   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2039
2040   if (pages == GTK_PRINT_PAGES_RANGES)
2041     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->page_range_radio), TRUE);
2042   else if (pages == GTK_PRINT_PAGES_CURRENT)
2043     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->current_page_radio), TRUE);
2044   else
2045     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->all_pages_radio), TRUE);
2046 }
2047
2048 static gdouble
2049 dialog_get_scale (GtkPrintUnixDialog *dialog)
2050 {
2051   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->scale_spin))
2052     return gtk_spin_button_get_value (GTK_SPIN_BUTTON (dialog->priv->scale_spin));
2053   else
2054     return 100.0;
2055 }
2056
2057 static void
2058 dialog_set_scale (GtkPrintUnixDialog *dialog, 
2059                   gdouble             val)
2060 {
2061   gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->scale_spin), val);
2062 }
2063
2064 static GtkPageSet
2065 dialog_get_page_set (GtkPrintUnixDialog *dialog)
2066 {
2067   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->page_set_combo))
2068     return (GtkPageSet)gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->page_set_combo));
2069   else
2070     return GTK_PAGE_SET_ALL;
2071 }
2072
2073 static void
2074 dialog_set_page_set (GtkPrintUnixDialog *dialog, 
2075                      GtkPageSet          val)
2076 {
2077   gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->priv->page_set_combo),
2078                             (int)val);
2079 }
2080
2081 static gint
2082 dialog_get_n_copies (GtkPrintUnixDialog *dialog)
2083 {
2084   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->copies_spin))
2085     return gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->priv->copies_spin));
2086   return 1;
2087 }
2088
2089 static void
2090 dialog_set_n_copies (GtkPrintUnixDialog *dialog, 
2091                      gint                n_copies)
2092 {
2093   gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->copies_spin),
2094                              n_copies);
2095 }
2096
2097 static gboolean
2098 dialog_get_collate (GtkPrintUnixDialog *dialog)
2099 {
2100   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->collate_check))
2101     return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->collate_check));
2102   return FALSE;
2103 }
2104
2105 static void
2106 dialog_set_collate (GtkPrintUnixDialog *dialog, 
2107                     gboolean            collate)
2108 {
2109   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->collate_check),
2110                                 collate);
2111 }
2112
2113 static gboolean
2114 dialog_get_reverse (GtkPrintUnixDialog *dialog)
2115 {
2116   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->reverse_check))
2117     return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->reverse_check));
2118   return FALSE;
2119 }
2120
2121 static void
2122 dialog_set_reverse (GtkPrintUnixDialog *dialog, 
2123                     gboolean            reverse)
2124 {
2125   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->reverse_check),
2126                                 reverse);
2127 }
2128
2129 static gint 
2130 dialog_get_pages_per_sheet (GtkPrintUnixDialog *dialog)
2131 {
2132   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2133   const gchar *val;
2134   gint num;
2135
2136   val = gtk_printer_option_widget_get_value (priv->pages_per_sheet);
2137
2138   num = 1;
2139   
2140   if (val)
2141     {
2142       num = atoi(val);
2143       if (num < 1)
2144         num = 1;
2145     }
2146   
2147   return num;
2148 }
2149
2150 static GtkNumberUpLayout
2151 dialog_get_number_up_layout (GtkPrintUnixDialog *dialog)
2152 {
2153   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2154   GtkPrintCapabilities       caps;
2155   GtkNumberUpLayout          layout;
2156   const gchar               *val;
2157   GEnumClass                *enum_class;
2158   GEnumValue                *enum_value;
2159
2160   val = gtk_printer_option_widget_get_value (priv->number_up_layout);
2161
2162   caps = priv->manual_capabilities | priv->printer_capabilities;
2163
2164   if ((caps & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT) == 0)
2165     return GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
2166
2167   if (gtk_widget_get_direction (GTK_WIDGET (dialog)) == GTK_TEXT_DIR_LTR)
2168     layout = GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
2169   else
2170     layout = GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM;
2171
2172   if (val == NULL)
2173     return layout;
2174
2175   enum_class = g_type_class_ref (GTK_TYPE_NUMBER_UP_LAYOUT);
2176   enum_value = g_enum_get_value_by_nick (enum_class, val);
2177   if (enum_value)
2178     layout = enum_value->value;
2179   g_type_class_unref (enum_class);
2180
2181   return layout;
2182 }
2183
2184 static gboolean
2185 draw_page_cb (GtkWidget          *widget,
2186               GdkEventExpose     *event,
2187               GtkPrintUnixDialog *dialog)
2188 {
2189   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2190   cairo_t *cr;
2191   gdouble ratio;
2192   gint w, h, tmp, shadow_offset;
2193   gint pages_x, pages_y, i, x, y, layout_w, layout_h;
2194   gdouble page_width, page_height;
2195   GtkPageOrientation orientation;
2196   gboolean landscape;
2197   PangoLayout *layout;
2198   PangoFontDescription *font;
2199   gchar *text;
2200   GdkColor *color;
2201   GtkNumberUpLayout number_up_layout;
2202   gint start_x, end_x, start_y, end_y;
2203   gint dx, dy;
2204   gboolean horizontal;
2205   
2206   orientation = gtk_page_setup_get_orientation (priv->page_setup);
2207   landscape =
2208     (orientation == GTK_PAGE_ORIENTATION_LANDSCAPE) ||
2209     (orientation == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE);
2210
2211   number_up_layout = dialog_get_number_up_layout (dialog);
2212
2213   cr = gdk_cairo_create (widget->window);
2214   
2215   cairo_translate (cr, widget->allocation.x, widget->allocation.y);
2216
2217   ratio = G_SQRT2;
2218
2219   w = (EXAMPLE_PAGE_AREA_SIZE - 3) / ratio;
2220   h = w * ratio;
2221
2222   switch (dialog_get_pages_per_sheet (dialog))
2223     {
2224     default:
2225     case 1:
2226       pages_x = 1; pages_y = 1;
2227       break;
2228     case 2:
2229       landscape = !landscape;
2230       pages_x = 1; pages_y = 2;
2231       break;
2232     case 4:
2233       pages_x = 2; pages_y = 2;
2234       break;
2235     case 6:
2236       landscape = !landscape;
2237       pages_x = 2; pages_y = 3;
2238       break;
2239     case 9:
2240       pages_x = 3; pages_y = 3;
2241       break;
2242     case 16:
2243       pages_x = 4; pages_y = 4;
2244       break;
2245     }
2246
2247   if (landscape)
2248     {
2249       tmp = w;
2250       w = h;
2251       h = tmp;
2252
2253       tmp = pages_x;
2254       pages_x = pages_y;
2255       pages_y = tmp;
2256     }
2257   
2258   shadow_offset = 3;
2259   
2260   color = &widget->style->text[GTK_STATE_NORMAL];
2261   cairo_set_source_rgba (cr, color->red / 65535., color->green / 65535., color->blue / 65535, 0.5);
2262   cairo_rectangle (cr, shadow_offset + 1, shadow_offset + 1, w, h);
2263   cairo_fill (cr);
2264   
2265   gdk_cairo_set_source_color (cr, &widget->style->base[GTK_STATE_NORMAL]);
2266   cairo_rectangle (cr, 1, 1, w, h);
2267   cairo_fill (cr);
2268   cairo_set_line_width (cr, 1.0);
2269   cairo_rectangle (cr, 0.5, 0.5, w+1, h+1);
2270   
2271   gdk_cairo_set_source_color (cr, &widget->style->text[GTK_STATE_NORMAL]);
2272   cairo_stroke (cr);
2273
2274   i = 1;
2275
2276   page_width = (double)w / pages_x;
2277   page_height = (double)h / pages_y;
2278
2279   layout  = pango_cairo_create_layout (cr);
2280
2281   font = pango_font_description_new ();
2282   pango_font_description_set_family (font, "sans");
2283   pango_font_description_set_absolute_size (font, page_height * 0.4 * PANGO_SCALE);
2284   pango_layout_set_font_description (layout, font);
2285   pango_font_description_free (font);
2286
2287   pango_layout_set_width (layout, page_width * PANGO_SCALE);
2288   pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
2289   
2290   switch (number_up_layout)
2291     {
2292       default:
2293       case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM:
2294         start_x = 0;
2295         end_x = pages_x - 1;
2296         start_y = 0;
2297         end_y = pages_y - 1;
2298         dx = 1;
2299         dy = 1;
2300         horizontal = TRUE;
2301         break;
2302       case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP:
2303         start_x = 0;
2304         end_x = pages_x - 1;
2305         start_y = pages_y - 1;
2306         end_y = 0;
2307         dx = 1;
2308         dy = - 1;
2309         horizontal = TRUE;
2310         break;
2311       case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM:
2312         start_x = pages_x - 1;
2313         end_x = 0;
2314         start_y = 0;
2315         end_y = pages_y - 1;
2316         dx = - 1;
2317         dy = 1;
2318         horizontal = TRUE;
2319         break;
2320       case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP:
2321         start_x = pages_x - 1;
2322         end_x = 0;
2323         start_y = pages_y - 1;
2324         end_y = 0;
2325         dx = - 1;
2326         dy = - 1;
2327         horizontal = TRUE;
2328         break;
2329       case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT:
2330         start_x = 0;
2331         end_x = pages_x - 1;
2332         start_y = 0;
2333         end_y = pages_y - 1;
2334         dx = 1;
2335         dy = 1;
2336         horizontal = FALSE;
2337         break;
2338       case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_RIGHT_TO_LEFT:
2339         start_x = pages_x - 1;
2340         end_x = 0;
2341         start_y = 0;
2342         end_y = pages_y - 1;
2343         dx = - 1;
2344         dy = 1;
2345         horizontal = FALSE;
2346         break;
2347       case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT:
2348         start_x = 0;
2349         end_x = pages_x - 1;
2350         start_y = pages_y - 1;
2351         end_y = 0;
2352         dx = 1;
2353         dy = - 1;
2354         horizontal = FALSE;
2355         break;
2356       case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_RIGHT_TO_LEFT:
2357         start_x = pages_x - 1;
2358         end_x = 0;
2359         start_y = pages_y - 1;
2360         end_y = 0;
2361         dx = - 1;
2362         dy = - 1;
2363         horizontal = FALSE;
2364         break;
2365     }
2366
2367   if (horizontal)
2368     for (y = start_y; y != end_y + dy; y += dy)
2369       {
2370         for (x = start_x; x != end_x + dx; x += dx)
2371           {
2372             text = g_strdup_printf ("%d", i++);
2373             pango_layout_set_text (layout, text, -1);
2374             g_free (text);
2375             pango_layout_get_size (layout, &layout_w, &layout_h);
2376             cairo_save (cr);
2377             cairo_translate (cr,
2378                              x * page_width,
2379                              y * page_height + (page_height - layout_h / 1024.0) / 2);
2380
2381             pango_cairo_show_layout (cr, layout);
2382             cairo_restore (cr);
2383           }
2384       }
2385   else
2386     for (x = start_x; x != end_x + dx; x += dx)
2387       {
2388         for (y = start_y; y != end_y + dy; y += dy)
2389           {
2390             text = g_strdup_printf ("%d", i++);
2391             pango_layout_set_text (layout, text, -1);
2392             g_free (text);
2393             pango_layout_get_size (layout, &layout_w, &layout_h);
2394             cairo_save (cr);
2395             cairo_translate (cr,
2396                              x * page_width,
2397                              y * page_height + (page_height - layout_h / 1024.0) / 2);
2398
2399             pango_cairo_show_layout (cr, layout);
2400             cairo_restore (cr);
2401           }
2402       }
2403   
2404   g_object_unref (layout);
2405   cairo_destroy (cr);
2406
2407   return TRUE;
2408 }
2409
2410 static void
2411 redraw_page_layout_preview (GtkPrintUnixDialog *dialog)
2412 {
2413   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2414
2415   if (priv->page_layout_preview)
2416     gtk_widget_queue_draw (priv->page_layout_preview);
2417 }
2418
2419 static void
2420 update_number_up_layout (GtkPrintUnixDialog *dialog)
2421 {
2422   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2423   GtkPrintCapabilities       caps;
2424   GtkPrinterOptionSet       *set;
2425   GtkNumberUpLayout          layout;
2426   GtkPrinterOption          *option;
2427   GtkPrinterOption          *old_option;
2428
2429   set = priv->options;
2430
2431   caps = priv->manual_capabilities | priv->printer_capabilities;
2432
2433   if (caps & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT)
2434     {
2435       if (priv->number_up_layout_n_option == NULL)
2436         {
2437           priv->number_up_layout_n_option = gtk_printer_option_set_lookup (set, "gtk-n-up-layout");
2438           g_object_ref (priv->number_up_layout_n_option);
2439
2440           priv->number_up_layout_2_option = gtk_printer_option_new ("gtk-n-up-layout",
2441                                                                     _("Page Ordering"),
2442                                                                     GTK_PRINTER_OPTION_TYPE_PICKONE);
2443           gtk_printer_option_allocate_choices (priv->number_up_layout_2_option, 2);
2444
2445           priv->number_up_layout_2_option->choices[0] = priv->number_up_layout_n_option->choices[0];
2446           priv->number_up_layout_2_option->choices[1] = priv->number_up_layout_n_option->choices[2];
2447           priv->number_up_layout_2_option->choices_display[0] = g_strdup ( _("Left to right"));
2448           priv->number_up_layout_2_option->choices_display[1] = g_strdup ( _("Right to left"));
2449         }
2450
2451       layout = dialog_get_number_up_layout (dialog);
2452
2453       old_option = gtk_printer_option_set_lookup (set, "gtk-n-up-layout");
2454       if (old_option != NULL)
2455         gtk_printer_option_set_remove (set, old_option);
2456
2457       if (dialog_get_pages_per_sheet (dialog) != 1)
2458         {
2459           GEnumClass *enum_class;
2460           GEnumValue *enum_value;
2461           enum_class = g_type_class_ref (GTK_TYPE_NUMBER_UP_LAYOUT);
2462
2463           if (dialog_get_pages_per_sheet (dialog) == 2)
2464             {
2465               option = priv->number_up_layout_2_option;
2466
2467               if (layout == GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM ||
2468                   layout == GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP ||
2469                   layout == GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT ||
2470                   layout == GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT)
2471                 enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM);
2472               else
2473                 enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM);
2474             }
2475           else
2476             {
2477               option = priv->number_up_layout_n_option;
2478
2479               enum_value = g_enum_get_value (enum_class, layout);
2480             }
2481
2482           g_assert (enum_value != NULL);
2483           gtk_printer_option_set (option, enum_value->value_nick);
2484           g_type_class_unref (enum_class);
2485
2486           gtk_printer_option_set_add (set, option);
2487         }
2488     }
2489
2490   setup_option (dialog, "gtk-n-up-layout", priv->number_up_layout);
2491
2492   if (priv->number_up_layout != NULL)
2493     gtk_widget_set_sensitive (GTK_WIDGET (priv->number_up_layout),
2494                               (caps & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT) &&
2495                               (dialog_get_pages_per_sheet (dialog) > 1));
2496 }
2497
2498 static void
2499 create_page_setup_page (GtkPrintUnixDialog *dialog)
2500 {
2501   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2502   GtkWidget *main_vbox, *label, *hbox, *hbox2;
2503   GtkWidget *frame, *table, *widget;
2504   GtkWidget *combo, *spinbutton, *draw;
2505
2506   main_vbox = gtk_vbox_new (FALSE, 18);
2507   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
2508   gtk_widget_show (main_vbox);
2509
2510   hbox = gtk_hbox_new (FALSE, 18);
2511   gtk_widget_show (hbox);
2512   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
2513
2514   table = gtk_table_new (5, 2, FALSE);
2515   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2516   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2517   frame = wrap_in_frame (_("Layout"), table);
2518   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
2519   gtk_widget_show (table);
2520
2521   label = gtk_label_new_with_mnemonic (_("T_wo-sided:"));
2522   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2523   gtk_widget_show (label);
2524   gtk_table_attach (GTK_TABLE (table), label,
2525                     0, 1, 0, 1,  GTK_FILL, 0,
2526                     0, 0);
2527
2528   widget = gtk_printer_option_widget_new (NULL);
2529   priv->duplex = GTK_PRINTER_OPTION_WIDGET (widget);
2530   gtk_widget_show (widget);
2531   gtk_table_attach (GTK_TABLE (table), widget,
2532                     1, 2, 0, 1,  GTK_FILL, 0,
2533                     0, 0);
2534   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2535
2536   label = gtk_label_new_with_mnemonic (_("Pages per _side:"));
2537   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2538   gtk_widget_show (label);
2539   gtk_table_attach (GTK_TABLE (table), label,
2540                     0, 1, 1, 2,  GTK_FILL, 0,
2541                     0, 0);
2542
2543   widget = gtk_printer_option_widget_new (NULL);
2544   g_signal_connect_swapped (widget, "changed", G_CALLBACK (redraw_page_layout_preview), dialog);
2545   g_signal_connect_swapped (widget, "changed", G_CALLBACK (update_number_up_layout), dialog);
2546   priv->pages_per_sheet = GTK_PRINTER_OPTION_WIDGET (widget);
2547   gtk_widget_show (widget);
2548   gtk_table_attach (GTK_TABLE (table), widget,
2549                     1, 2, 1, 2,  GTK_FILL, 0,
2550                     0, 0);
2551   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2552
2553
2554   label = gtk_label_new_with_mnemonic (_("Page or_dering:"));
2555   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2556   gtk_widget_show (label);
2557   gtk_table_attach (GTK_TABLE (table), label,
2558                     0, 1, 2, 3,  GTK_FILL, 0,
2559                     0, 0);
2560
2561   widget = gtk_printer_option_widget_new (NULL);
2562   g_signal_connect_swapped (widget, "changed", G_CALLBACK (redraw_page_layout_preview), dialog);
2563   priv->number_up_layout = GTK_PRINTER_OPTION_WIDGET (widget);
2564   gtk_widget_show (widget);
2565   gtk_table_attach (GTK_TABLE (table), widget,
2566                     1, 2, 2, 3,  GTK_FILL, 0,
2567                     0, 0);
2568   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2569
2570   label = gtk_label_new_with_mnemonic (_("_Only print:"));
2571   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2572   gtk_widget_show (label);
2573   gtk_table_attach (GTK_TABLE (table), label,
2574                     0, 1, 3, 4,  GTK_FILL, 0,
2575                     0, 0);
2576
2577   combo = gtk_combo_box_new_text ();
2578   priv->page_set_combo = combo;
2579   gtk_widget_show (combo);
2580   gtk_table_attach (GTK_TABLE (table), combo,
2581                     1, 2, 3, 4,  GTK_FILL, 0,
2582                     0, 0);
2583   gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
2584   /* In enum order */
2585   gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("All sheets"));  
2586   gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Even sheets"));  
2587   gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Odd sheets"));  
2588   gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
2589
2590   label = gtk_label_new_with_mnemonic (_("Sc_ale:"));
2591   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2592   gtk_widget_show (label);
2593   gtk_table_attach (GTK_TABLE (table), label,
2594                     0, 1, 4, 5,  GTK_FILL, 0,
2595                     0, 0);
2596
2597   hbox2 = gtk_hbox_new (FALSE, 6);
2598   gtk_widget_show (hbox2);
2599   gtk_table_attach (GTK_TABLE (table), hbox2,
2600                     1, 2, 4, 5,  GTK_FILL, 0,
2601                     0, 0);
2602   
2603   spinbutton = gtk_spin_button_new_with_range (1.0, 1000.0, 1.0);
2604   priv->scale_spin = spinbutton;
2605   gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinbutton), 1);
2606   gtk_spin_button_set_value (GTK_SPIN_BUTTON (spinbutton), 100.0);
2607   gtk_box_pack_start (GTK_BOX (hbox2), spinbutton, FALSE, FALSE, 0);
2608   gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
2609   gtk_widget_show (spinbutton);
2610   label = gtk_label_new ("%"); /* FIXMEchpe does there exist any language where % needs to be translated? */
2611   gtk_widget_show (label);
2612   gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0);
2613
2614   table = gtk_table_new (4, 2, FALSE);
2615   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2616   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2617   frame = wrap_in_frame (_("Paper"), table);
2618   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 6);
2619   gtk_widget_show (table);
2620
2621   label = gtk_label_new_with_mnemonic (_("Paper _type:"));
2622   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2623   gtk_widget_show (label);
2624   gtk_table_attach (GTK_TABLE (table), label,
2625                     0, 1, 0, 1,  GTK_FILL, 0,
2626                     0, 0);
2627
2628   widget = gtk_printer_option_widget_new (NULL);
2629   priv->paper_type = GTK_PRINTER_OPTION_WIDGET (widget);
2630   gtk_widget_show (widget);
2631   gtk_table_attach (GTK_TABLE (table), widget,
2632                     1, 2, 0, 1,  GTK_FILL, 0,
2633                     0, 0);
2634   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2635
2636   label = gtk_label_new_with_mnemonic (_("Paper _source:"));
2637   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2638   gtk_widget_show (label);
2639   gtk_table_attach (GTK_TABLE (table), label,
2640                     0, 1, 1, 2,  GTK_FILL, 0,
2641                     0, 0);
2642
2643   widget = gtk_printer_option_widget_new (NULL);
2644   priv->paper_source = GTK_PRINTER_OPTION_WIDGET (widget);
2645   gtk_widget_show (widget);
2646   gtk_table_attach (GTK_TABLE (table), widget,
2647                     1, 2, 1, 2,  GTK_FILL, 0,
2648                     0, 0);
2649   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2650
2651   label = gtk_label_new_with_mnemonic (_("Output t_ray:"));
2652   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2653   gtk_widget_show (label);
2654   gtk_table_attach (GTK_TABLE (table), label,
2655                     0, 1, 2, 3,  GTK_FILL, 0,
2656                     0, 0);
2657
2658   widget = gtk_printer_option_widget_new (NULL);
2659   priv->output_tray = GTK_PRINTER_OPTION_WIDGET (widget);
2660   gtk_widget_show (widget);
2661   gtk_table_attach (GTK_TABLE (table), widget,
2662                     1, 2, 2, 3,  GTK_FILL, 0,
2663                     0, 0);
2664   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2665
2666   /* Add the page layout preview */
2667   hbox2 = gtk_hbox_new (FALSE, 0);
2668   gtk_widget_show (hbox2);
2669   gtk_box_pack_start (GTK_BOX (main_vbox), hbox2, TRUE, TRUE, 0);
2670
2671   draw = gtk_drawing_area_new ();
2672   GTK_WIDGET_SET_FLAGS (draw, GTK_NO_WINDOW);
2673   priv->page_layout_preview = draw;
2674   gtk_widget_set_size_request (draw, 200, 200);
2675   g_signal_connect (draw, "expose-event", G_CALLBACK (draw_page_cb), dialog);
2676   gtk_widget_show (draw);
2677
2678   gtk_box_pack_start (GTK_BOX (hbox2), draw, TRUE, FALSE, 0);
2679   
2680   label = gtk_label_new (_("Page Setup"));
2681   gtk_widget_show (label);
2682   
2683   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
2684                             main_vbox, label);
2685 }
2686
2687 static void
2688 create_job_page (GtkPrintUnixDialog *dialog)
2689 {
2690   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2691   GtkWidget *main_table, *label;
2692   GtkWidget *frame, *table, *radio;
2693   GtkWidget *entry, *widget;
2694   const gchar *at_tooltip;
2695   const gchar *on_hold_tooltip;
2696
2697   main_table = gtk_table_new (2, 2, FALSE);
2698   gtk_container_set_border_width (GTK_CONTAINER (main_table), 12);
2699   gtk_table_set_row_spacings (GTK_TABLE (main_table), 18);
2700   gtk_table_set_col_spacings (GTK_TABLE (main_table), 18);
2701
2702   table = gtk_table_new (2, 2, FALSE);
2703   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2704   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2705   frame = wrap_in_frame (_("Job Details"), table);
2706   gtk_table_attach (GTK_TABLE (main_table), frame,
2707                     0, 1, 0, 1,  GTK_FILL, 0,
2708                     0, 0);
2709   gtk_widget_show (table);
2710
2711   label = gtk_label_new_with_mnemonic (_("Pri_ority:"));
2712   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2713   gtk_widget_show (label);
2714   gtk_table_attach (GTK_TABLE (table), label,
2715                     0, 1, 0, 1,  GTK_FILL, 0,
2716                     0, 0);
2717
2718   widget = gtk_printer_option_widget_new (NULL);
2719   priv->job_prio = GTK_PRINTER_OPTION_WIDGET (widget);
2720   gtk_widget_show (widget);
2721   gtk_table_attach (GTK_TABLE (table), widget,
2722                     1, 2, 0, 1,  GTK_FILL, 0,
2723                     0, 0);
2724   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2725
2726   label = gtk_label_new_with_mnemonic (_("_Billing info:"));
2727   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2728   gtk_widget_show (label);
2729   gtk_table_attach (GTK_TABLE (table), label,
2730                     0, 1, 1, 2,  GTK_FILL, 0,
2731                     0, 0);
2732
2733   widget = gtk_printer_option_widget_new (NULL);
2734   priv->billing_info = GTK_PRINTER_OPTION_WIDGET (widget);
2735   gtk_widget_show (widget);
2736   gtk_table_attach (GTK_TABLE (table), widget,
2737                     1, 2, 1, 2,  GTK_FILL, 0,
2738                     0, 0);
2739   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2740
2741   table = gtk_table_new (2, 2, FALSE);
2742   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2743   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2744   frame = wrap_in_frame (_("Print Document"), table);
2745   gtk_table_attach (GTK_TABLE (main_table), frame,
2746                     0, 1, 1, 2,  GTK_FILL, 0,
2747                     0, 0);
2748   gtk_widget_show (table);
2749
2750   /* Translators: this is one of the choices for the print at option
2751    * in the print dialog
2752    */
2753   radio = gtk_radio_button_new_with_mnemonic (NULL, _("_Now"));
2754   priv->print_now_radio = radio;
2755   gtk_widget_show (radio);
2756   gtk_table_attach (GTK_TABLE (table), radio,
2757                     0, 2, 0, 1,  GTK_FILL, 0,
2758                     0, 0);
2759   /* Translators: this is one of the choices for the print at option
2760    * in the print dialog. It also serves as the label for an entry that
2761    * allows the user to enter a time.
2762    */
2763   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
2764                                               _("A_t:"));
2765
2766   /* Translators: Ability to parse the am/pm format depends on actual locale.
2767    * You can remove the am/pm values below for your locale if they are not
2768    * supported.
2769    */
2770   at_tooltip = _("Specify the time of print,\n e.g. 15:30, 2:35 pm, 14:15:20, 11:46:30 am, 4 pm");
2771   gtk_widget_set_tooltip_text (radio, at_tooltip);
2772   priv->print_at_radio = radio;
2773   gtk_widget_show (radio);
2774   gtk_table_attach (GTK_TABLE (table), radio,
2775                     0, 1, 1, 2,  GTK_FILL, 0,
2776                     0, 0);
2777
2778   entry = gtk_entry_new ();
2779   gtk_widget_set_tooltip_text (entry, at_tooltip);
2780   atk_object_set_name (gtk_widget_get_accessible (entry), _("Time of print"));
2781   atk_object_set_description (gtk_widget_get_accessible (entry), at_tooltip);
2782   priv->print_at_entry = entry;
2783   gtk_widget_show (entry);
2784   gtk_table_attach (GTK_TABLE (table), entry,
2785                     1, 2, 1, 2,  GTK_FILL, 0,
2786                     0, 0);
2787
2788   g_signal_connect (radio, "toggled", G_CALLBACK (update_entry_sensitivity), entry);
2789   update_entry_sensitivity (radio, entry);
2790
2791   /* Translators: this is one of the choices for the print at option
2792    * in the print dialog. It means that the print job will not be
2793    * printed until it explicitly gets 'released'.
2794    */
2795   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
2796                                               _("On _hold"));
2797   on_hold_tooltip = _("Hold the job until it is explicitly released");
2798   gtk_widget_set_tooltip_text (radio, on_hold_tooltip);
2799   priv->print_hold_radio = radio;
2800   gtk_widget_show (radio);
2801   gtk_table_attach (GTK_TABLE (table), radio,
2802                     0, 2, 2, 3,  GTK_FILL, 0,
2803                     0, 0);
2804
2805   g_signal_connect_swapped (priv->print_now_radio, "toggled",
2806                             G_CALLBACK (update_print_at_option), dialog);
2807   g_signal_connect_swapped (priv->print_at_radio, "toggled",
2808                             G_CALLBACK (update_print_at_option), dialog);
2809   g_signal_connect_swapped (priv->print_at_entry, "changed",
2810                             G_CALLBACK (update_print_at_option), dialog);
2811   g_signal_connect_swapped (priv->print_hold_radio, "toggled",
2812                             G_CALLBACK (update_print_at_option), dialog);
2813
2814   table = gtk_table_new (2, 2, FALSE);
2815   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2816   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2817   frame = wrap_in_frame (_("Add Cover Page"), table);
2818   gtk_table_attach (GTK_TABLE (main_table), frame,
2819                     1, 2, 0, 1,  GTK_FILL, 0,
2820                     0, 0);
2821   gtk_widget_show (table);
2822
2823   /* Translators, this is the label used for the option in the print 
2824    * dialog that controls the front cover page.
2825    */
2826   label = gtk_label_new_with_mnemonic (_("Be_fore:"));
2827   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2828   gtk_widget_show (label);
2829   gtk_table_attach (GTK_TABLE (table), label,
2830                     0, 1, 0, 1,  GTK_FILL, 0,
2831                     0, 0);
2832
2833   widget = gtk_printer_option_widget_new (NULL);
2834   priv->cover_before = GTK_PRINTER_OPTION_WIDGET (widget);
2835   gtk_widget_show (widget);
2836   gtk_table_attach (GTK_TABLE (table), widget,
2837                     1, 2, 0, 1,  GTK_FILL, 0,
2838                     0, 0);
2839   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2840
2841   /* Translators, this is the label used for the option in the print 
2842    * dialog that controls the back cover page.
2843    */
2844   label = gtk_label_new_with_mnemonic (_("_After:"));
2845   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2846   gtk_widget_show (label);
2847   gtk_table_attach (GTK_TABLE (table), label,
2848                     0, 1, 1, 2,  GTK_FILL, 0,
2849                     0, 0);
2850
2851   widget = gtk_printer_option_widget_new (NULL);
2852   priv->cover_after = GTK_PRINTER_OPTION_WIDGET (widget);
2853   gtk_widget_show (widget);
2854   gtk_table_attach (GTK_TABLE (table), widget,
2855                     1, 2, 1, 2,  GTK_FILL, 0,
2856                     0, 0);
2857   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2858
2859   /* Translators: this is the tab label for the notebook tab containing
2860    * job-specific options in the print dialog
2861    */
2862   label = gtk_label_new (_("Job"));
2863   gtk_widget_show (label);
2864
2865   priv->job_page = main_table;
2866   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
2867                             main_table, label);
2868 }
2869
2870 static void 
2871 create_optional_page (GtkPrintUnixDialog  *dialog,
2872                       const gchar         *text,
2873                       GtkWidget          **table_out,
2874                       GtkWidget          **page_out)
2875 {
2876   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2877   GtkWidget *table, *label, *scrolled;
2878
2879   scrolled = gtk_scrolled_window_new (NULL, NULL);
2880   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
2881                                   GTK_POLICY_NEVER,
2882                                   GTK_POLICY_AUTOMATIC);
2883   
2884   table = gtk_table_new (1, 2, FALSE);
2885   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2886   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2887   gtk_container_set_border_width (GTK_CONTAINER (table), 12);
2888   gtk_widget_show (table);
2889
2890   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
2891                                          table);
2892   gtk_viewport_set_shadow_type (GTK_VIEWPORT (GTK_BIN(scrolled)->child),
2893                                 GTK_SHADOW_NONE);
2894   
2895   label = gtk_label_new (text);
2896   gtk_widget_show (label);
2897   
2898   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
2899                             scrolled, label);
2900
2901   *table_out = table;
2902   *page_out = scrolled;
2903 }
2904
2905 static void
2906 create_advanced_page (GtkPrintUnixDialog *dialog)
2907 {
2908   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2909   GtkWidget *main_vbox, *label, *scrolled;
2910
2911   scrolled = gtk_scrolled_window_new (NULL, NULL);
2912   priv->advanced_page = scrolled;
2913   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
2914                                   GTK_POLICY_NEVER,
2915                                   GTK_POLICY_AUTOMATIC);
2916
2917   main_vbox = gtk_vbox_new (FALSE, 18);
2918   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
2919   gtk_widget_show (main_vbox);
2920
2921   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
2922                                          main_vbox);
2923   gtk_viewport_set_shadow_type (GTK_VIEWPORT (GTK_BIN(scrolled)->child),
2924                                 GTK_SHADOW_NONE);
2925   
2926   priv->advanced_vbox = main_vbox;
2927   
2928   label = gtk_label_new (_("Advanced"));
2929   gtk_widget_show (label);
2930   
2931   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
2932                             scrolled, label);
2933 }
2934
2935
2936 static void
2937 populate_dialog (GtkPrintUnixDialog *print_dialog)
2938 {
2939   GtkPrintUnixDialogPrivate *priv = print_dialog->priv;
2940   GtkDialog *dialog = GTK_DIALOG (print_dialog);
2941   GtkWidget *vbox, *conflict_hbox, *image, *label;
2942
2943   gtk_dialog_set_has_separator (dialog, FALSE);
2944   gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
2945   gtk_box_set_spacing (GTK_BOX (dialog->vbox), 2); /* 2 * 5 + 2 = 12 */
2946   gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 5);
2947   gtk_box_set_spacing (GTK_BOX (dialog->action_area), 6);
2948
2949   vbox = gtk_vbox_new (FALSE, 6);
2950   gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
2951   gtk_box_pack_start (GTK_BOX (dialog->vbox), vbox, TRUE, TRUE, 0);
2952   gtk_widget_show (vbox);
2953
2954   priv->notebook = gtk_notebook_new ();
2955   gtk_box_pack_start (GTK_BOX (vbox), priv->notebook, TRUE, TRUE, 0);
2956   gtk_widget_show (priv->notebook);
2957
2958   create_printer_list_model (print_dialog);
2959
2960   create_main_page (print_dialog);
2961   create_page_setup_page (print_dialog);
2962   create_job_page (print_dialog);
2963   create_optional_page (print_dialog, _("Image Quality"),
2964                         &priv->image_quality_table,
2965                         &priv->image_quality_page);
2966   create_optional_page (print_dialog, _("Color"),
2967                         &priv->color_table,
2968                         &priv->color_page);
2969   create_optional_page (print_dialog, _("Finishing"),
2970                         &priv->finishing_table,
2971                         &priv->finishing_page);
2972   create_advanced_page (print_dialog);
2973
2974   priv->conflicts_widget = conflict_hbox = gtk_hbox_new (FALSE, 12);
2975   gtk_box_pack_end (GTK_BOX (vbox), conflict_hbox, FALSE, FALSE, 0);
2976   image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_MENU);
2977   gtk_widget_show (image);
2978   gtk_box_pack_start (GTK_BOX (conflict_hbox), image, FALSE, TRUE, 0);
2979   label = gtk_label_new (_("Some of the settings in the dialog conflict"));
2980   gtk_widget_show (label);
2981   gtk_box_pack_start (GTK_BOX (conflict_hbox), label, FALSE, TRUE, 0);
2982   
2983   load_print_backends (print_dialog);
2984 }
2985
2986 /**
2987  * gtk_print_unix_dialog_new:
2988  * @title: Title of the dialog, or %NULL
2989  * @parent: Transient parent of the dialog, or %NULL
2990  *
2991  * Creates a new #GtkPrintUnixDialog.
2992  *
2993  * Return value: a new #GtkPrintUnixDialog
2994  *
2995  * Since: 2.10
2996  **/
2997 GtkWidget *
2998 gtk_print_unix_dialog_new (const gchar *title,
2999                            GtkWindow   *parent)
3000 {
3001   GtkWidget *result;
3002   const gchar *_title = _("Print");
3003
3004   if (title)
3005     _title = title;
3006
3007   result = g_object_new (GTK_TYPE_PRINT_UNIX_DIALOG,
3008                          "transient-for", parent,
3009                          "title", _title,
3010                          "has-separator", FALSE,
3011                          NULL);
3012   
3013   return result;
3014 }
3015
3016 /**
3017  * gtk_print_unix_dialog_get_selected_printer:
3018  * @dialog: a #GtkPrintUnixDialog
3019  * 
3020  * Gets the currently selected printer.
3021  * 
3022  * Returns: the currently selected printer
3023  * 
3024  * Since: 2.10
3025  */
3026 GtkPrinter *
3027 gtk_print_unix_dialog_get_selected_printer (GtkPrintUnixDialog *dialog)
3028 {
3029   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
3030
3031   return dialog->priv->current_printer;
3032 }
3033
3034 /**
3035  * gtk_print_unix_dialog_set_page_setup:
3036  * @dialog: a #GtkPrintUnixDialog
3037  * @page_setup: a #GtkPageSetup
3038  * 
3039  * Sets the page setup of the #GtkPrintUnixDialog.
3040  *
3041  * Since: 2.10
3042  */
3043 void
3044 gtk_print_unix_dialog_set_page_setup (GtkPrintUnixDialog *dialog,
3045                                       GtkPageSetup       *page_setup)
3046 {
3047   GtkPrintUnixDialogPrivate *priv;
3048
3049   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
3050   g_return_if_fail (GTK_IS_PAGE_SETUP (page_setup));
3051
3052   priv = dialog->priv;
3053
3054   if (priv->page_setup != page_setup)
3055     {
3056       g_object_unref (priv->page_setup);
3057       priv->page_setup = g_object_ref (page_setup);
3058
3059       priv->page_setup_set = TRUE;
3060
3061       g_object_notify (G_OBJECT (dialog), "page-setup");
3062     }
3063 }
3064
3065 /**
3066  * gtk_print_unix_dialog_get_page_setup:
3067  * @dialog: a #GtkPrintUnixDialog
3068  * 
3069  * Gets the page setup that is used by the #GtkPrintUnixDialog.
3070  * 
3071  * Returns: the page setup of @dialog.
3072  *
3073  * Since: 2.10
3074  */
3075 GtkPageSetup *
3076 gtk_print_unix_dialog_get_page_setup (GtkPrintUnixDialog *dialog)
3077 {
3078   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
3079
3080   return dialog->priv->page_setup;
3081 }
3082
3083 /**
3084  * gtk_print_unix_dialog_set_current_page:
3085  * @dialog: a #GtkPrintUnixDialog
3086  * @current_page: the current page number.
3087  * 
3088  * Sets the current page number. If @current_page is not -1, this enables
3089  * the current page choice for the range of pages to print.
3090  *
3091  * Since: 2.10
3092  */
3093 void
3094 gtk_print_unix_dialog_set_current_page (GtkPrintUnixDialog *dialog,
3095                                         gint                current_page)
3096 {
3097   GtkPrintUnixDialogPrivate *priv;
3098
3099   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
3100
3101   priv = dialog->priv;
3102
3103   if (priv->current_page != current_page)
3104     {
3105       priv->current_page = current_page;
3106
3107       if (priv->current_page_radio)
3108         gtk_widget_set_sensitive (priv->current_page_radio, current_page != -1);
3109
3110       g_object_notify (G_OBJECT (dialog), "current-page");
3111     }
3112 }
3113
3114 /**
3115  * gtk_print_unix_dialog_get_current_page:
3116  * @dialog: a #GtkPrintUnixDialog
3117  * 
3118  * Gets the current page of the #GtkPrintDialog.
3119  * 
3120  * Returns: the current page of @dialog
3121  * 
3122  * Since: 2.10
3123  */
3124 gint
3125 gtk_print_unix_dialog_get_current_page (GtkPrintUnixDialog *dialog)
3126 {
3127   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), -1);
3128
3129   return dialog->priv->current_page;
3130 }
3131
3132 static gboolean
3133 set_active_printer (GtkPrintUnixDialog *dialog,
3134                     const gchar        *printer_name)
3135 {
3136   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3137   GtkTreeModel *model;
3138   GtkTreeIter iter, filter_iter;
3139   GtkTreeSelection *selection;
3140   GtkPrinter *printer;
3141
3142   model = GTK_TREE_MODEL (priv->printer_list);
3143
3144   if (gtk_tree_model_get_iter_first (model, &iter))
3145     {
3146       do
3147         {
3148           gtk_tree_model_get (GTK_TREE_MODEL (priv->printer_list), &iter,
3149                               PRINTER_LIST_COL_PRINTER_OBJ, &printer, -1);
3150           if (printer == NULL)
3151             continue;
3152           
3153           if (strcmp (gtk_printer_get_name (printer), printer_name) == 0)
3154             {
3155               gtk_tree_model_filter_convert_child_iter_to_iter (priv->printer_list_filter,
3156                                                                 &filter_iter, &iter);
3157               
3158               selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
3159               priv->internal_printer_change = TRUE;
3160               gtk_tree_selection_select_iter (selection, &filter_iter);
3161               priv->internal_printer_change = FALSE;
3162               g_free (priv->waiting_for_printer);
3163               priv->waiting_for_printer = NULL;
3164               
3165               g_object_unref (printer);
3166               return TRUE;
3167             }
3168               
3169           g_object_unref (printer);
3170           
3171         } while (gtk_tree_model_iter_next (model, &iter));
3172     }
3173   
3174   return FALSE;
3175 }
3176
3177 /**
3178  * gtk_print_unix_dialog_set_settings:
3179  * @dialog: a #GtkPrintUnixDialog
3180  * @settings: a #GtkPrintSettings, or %NULL
3181  * 
3182  * Sets the #GtkPrintSettings for the #GtkPrintUnixDialog. Typically,
3183  * this is used to restore saved print settings from a previous print
3184  * operation before the print dialog is shown.
3185  * 
3186  * Since: 2.10
3187  **/
3188 void
3189 gtk_print_unix_dialog_set_settings (GtkPrintUnixDialog *dialog,
3190                                     GtkPrintSettings   *settings)
3191 {
3192   GtkPrintUnixDialogPrivate *priv;
3193   const gchar *printer;
3194   GtkPageRange *ranges;
3195   gint num_ranges;
3196   
3197   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
3198   g_return_if_fail (settings == NULL || GTK_IS_PRINT_SETTINGS (settings));
3199
3200   priv = dialog->priv;
3201
3202   if (settings != NULL)
3203     {
3204       dialog_set_collate (dialog, gtk_print_settings_get_collate (settings));
3205       dialog_set_reverse (dialog, gtk_print_settings_get_reverse (settings));
3206       dialog_set_n_copies (dialog, gtk_print_settings_get_n_copies (settings));
3207       dialog_set_scale (dialog, gtk_print_settings_get_scale (settings));
3208       dialog_set_page_set (dialog, gtk_print_settings_get_page_set (settings));
3209       dialog_set_print_pages (dialog, gtk_print_settings_get_print_pages (settings));
3210       ranges = gtk_print_settings_get_page_ranges (settings, &num_ranges);
3211       if (ranges)
3212         {
3213           dialog_set_page_ranges (dialog, ranges, num_ranges);
3214           g_free (ranges);
3215         }
3216
3217       priv->format_for_printer =
3218         g_strdup (gtk_print_settings_get (settings, "format-for-printer"));
3219     }
3220
3221   if (priv->initial_settings)
3222     g_object_unref (priv->initial_settings);
3223
3224   priv->initial_settings = settings;
3225
3226   g_free (priv->waiting_for_printer);
3227   priv->waiting_for_printer = NULL;
3228   
3229   if (settings)
3230     {
3231       g_object_ref (settings);
3232
3233       printer = gtk_print_settings_get_printer (settings);
3234       
3235       if (printer && !set_active_printer (dialog, printer))
3236         priv->waiting_for_printer = g_strdup (printer); 
3237     }
3238
3239   g_object_notify (G_OBJECT (dialog), "print-settings");
3240 }
3241
3242 /**
3243  * gtk_print_unix_dialog_get_settings:
3244  * @dialog: a #GtkPrintUnixDialog
3245  * 
3246  * Gets a new #GtkPrintSettings object that represents the
3247  * current values in the print dialog. Note that this creates a
3248  * <emphasis>new object</emphasis>, and you need to unref it
3249  * if don't want to keep it.
3250  * 
3251  * Returns: a new #GtkPrintSettings object with the values from @dialog
3252  *
3253  * Since: 2.10
3254  */
3255 GtkPrintSettings *
3256 gtk_print_unix_dialog_get_settings (GtkPrintUnixDialog *dialog)
3257 {
3258   GtkPrintUnixDialogPrivate *priv;
3259   GtkPrintSettings *settings;
3260   GtkPrintPages print_pages;
3261   GtkPageRange *ranges;
3262   gint n_ranges;
3263
3264   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
3265
3266   priv = dialog->priv;
3267   settings = gtk_print_settings_new ();
3268
3269   if (priv->current_printer)
3270     gtk_print_settings_set_printer (settings,
3271                                     gtk_printer_get_name (priv->current_printer));
3272   else
3273     gtk_print_settings_set_printer (settings, "default");
3274   
3275   gtk_print_settings_set (settings, "format-for-printer",
3276                           priv->format_for_printer);
3277
3278   
3279   gtk_print_settings_set_collate (settings,
3280                                   dialog_get_collate (dialog));
3281   
3282   gtk_print_settings_set_reverse (settings,
3283                                   dialog_get_reverse (dialog));
3284   
3285   gtk_print_settings_set_n_copies (settings,
3286                                    dialog_get_n_copies (dialog));
3287
3288   gtk_print_settings_set_scale (settings,
3289                                 dialog_get_scale (dialog));
3290   
3291   gtk_print_settings_set_page_set (settings,
3292                                    dialog_get_page_set (dialog));
3293   
3294   print_pages = dialog_get_print_pages (dialog);
3295   gtk_print_settings_set_print_pages (settings, print_pages);
3296
3297   ranges = dialog_get_page_ranges (dialog, &n_ranges);
3298   if (ranges)
3299     {
3300       gtk_print_settings_set_page_ranges  (settings, ranges, n_ranges);
3301       g_free (ranges);
3302     }
3303
3304   /* TODO: print when. How to handle? */
3305
3306   if (priv->current_printer)
3307     _gtk_printer_get_settings_from_options (priv->current_printer,
3308                                             priv->options,
3309                                             settings);
3310   
3311   return settings;
3312 }
3313
3314 /**
3315  * gtk_print_unix_dialog_add_custom_tab:
3316  * @dialog: a #GtkPrintUnixDialog
3317  * @child: the widget to put in the custom tab
3318  * @tab_label: the widget to use as tab label
3319  *
3320  * Adds a custom tab to the print dialog.
3321  *
3322  * Since: 2.10
3323  */
3324 void
3325 gtk_print_unix_dialog_add_custom_tab (GtkPrintUnixDialog *dialog,
3326                                       GtkWidget          *child,
3327                                       GtkWidget          *tab_label)
3328 {
3329   gtk_notebook_insert_page (GTK_NOTEBOOK (dialog->priv->notebook),
3330                             child, tab_label, 2);
3331   gtk_widget_show (child);
3332   gtk_widget_show (tab_label);
3333 }
3334
3335 /**
3336  * gtk_print_unix_dialog_set_manual_capabilities:
3337  * @dialog: a #GtkPrintUnixDialog
3338  * @capabilities: the printing capabilities of your application
3339  *
3340  * This lets you specify the printing capabilities your application
3341  * supports. For instance, if you can handle scaling the output then
3342  * you pass #GTK_PRINT_CAPABILITY_SCALE. If you don't pass that, then
3343  * the dialog will only let you select the scale if the printing
3344  * system automatically handles scaling.
3345  *
3346  * Since: 2.10
3347  */
3348 void
3349 gtk_print_unix_dialog_set_manual_capabilities (GtkPrintUnixDialog   *dialog,
3350                                                GtkPrintCapabilities  capabilities)
3351 {
3352   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3353
3354   priv->manual_capabilities = capabilities;
3355   update_dialog_from_capabilities (dialog);
3356
3357   if (priv->current_printer)
3358     {
3359       GtkTreeSelection *selection;
3360
3361       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
3362
3363       g_object_unref (priv->current_printer);
3364       priv->current_printer = NULL;
3365       priv->internal_printer_change = TRUE;
3366       selected_printer_changed (selection, dialog);
3367       priv->internal_printer_change = FALSE;
3368    }
3369 }
3370
3371 #define __GTK_PRINT_UNIX_DIALOG_C__
3372 #include "gtkaliasdef.c"
3373