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