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