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