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