]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintunixdialog.c
Do not assume that text is null-terminated as pointed out by Christopher
[~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 <ctype.h>
25 #include <stdio.h>
26 #include <math.h>
27
28 #include "gtkintl.h"
29 #include "gtkprivate.h"
30
31 #include "gtkspinbutton.h"
32 #include "gtkcellrendererpixbuf.h"
33 #include "gtkcellrenderertext.h"
34 #include "gtkstock.h"
35 #include "gtkiconfactory.h"
36 #include "gtkimage.h"
37 #include "gtktreeselection.h"
38 #include "gtknotebook.h"
39 #include "gtkscrolledwindow.h"
40 #include "gtkcombobox.h"
41 #include "gtktogglebutton.h"
42 #include "gtkradiobutton.h"
43 #include "gtkdrawingarea.h"
44 #include "gtkvbox.h"
45 #include "gtktable.h"
46 #include "gtkframe.h"
47 #include "gtkalignment.h"
48 #include "gtklabel.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   GtkWidget *all_pages_radio;
127   GtkWidget *current_page_radio;
128   GtkWidget *page_range_radio;
129   GtkWidget *page_range_entry;
130   
131   GtkWidget *copies_spin;
132   GtkWidget *collate_check;
133   GtkWidget *reverse_check;
134   GtkWidget *collate_image;
135   GtkWidget *page_layout_preview;
136   GtkWidget *scale_spin;
137   GtkWidget *page_set_combo;
138   GtkWidget *print_now_radio;
139   GtkWidget *print_at_radio;
140   GtkWidget *print_at_entry;
141   GtkWidget *print_hold_radio;
142   GtkWidget *preview_button;
143   gboolean updating_print_at;
144   GtkPrinterOptionWidget *pages_per_sheet;
145   GtkPrinterOptionWidget *duplex;
146   GtkPrinterOptionWidget *paper_type;
147   GtkPrinterOptionWidget *paper_source;
148   GtkPrinterOptionWidget *output_tray;
149   GtkPrinterOptionWidget *job_prio;
150   GtkPrinterOptionWidget *billing_info;
151   GtkPrinterOptionWidget *cover_before;
152   GtkPrinterOptionWidget *cover_after;
153
154   GtkWidget *conflicts_widget;
155
156   GtkWidget *job_page;
157   GtkWidget *finishing_table;
158   GtkWidget *finishing_page;
159   GtkWidget *image_quality_table;
160   GtkWidget *image_quality_page;
161   GtkWidget *color_table;
162   GtkWidget *color_page;
163
164   GtkWidget *advanced_vbox;
165   GtkWidget *advanced_page;
166
167   GtkWidget *extension_point;
168
169   /* These are set initially on selected printer (either default printer, 
170    * printer taken from set settings, or user-selected), but when any setting 
171    * is changed by the user it is cleared.
172    */
173   GtkPrintSettings *initial_settings;
174   
175   /* This is the initial printer set by set_settings. We look for it in the
176    * added printers. We clear this whenever the user manually changes
177    * to another printer, when the user changes a setting or when we find
178    * this printer.
179    */
180   char *waiting_for_printer;
181   gboolean internal_printer_change;
182   
183   GList *print_backends;
184   
185   GtkPrinter *current_printer;
186   guint request_details_tag;
187   GtkPrinterOptionSet *options;
188   gulong options_changed_handler;
189   gulong mark_conflicts_id;
190
191   gchar *format_for_printer;
192   
193   gint current_page;
194 };
195
196 G_DEFINE_TYPE (GtkPrintUnixDialog, gtk_print_unix_dialog, GTK_TYPE_DIALOG)
197
198 static gboolean
199 is_default_printer (GtkPrintUnixDialog *dialog,
200                     GtkPrinter         *printer)
201 {
202   GtkPrintUnixDialogPrivate *priv = dialog->priv;
203
204   if (priv->format_for_printer)
205     return strcmp (priv->format_for_printer,
206                    gtk_printer_get_name (printer)) == 0;
207  else
208    return gtk_printer_is_default (printer);
209 }
210
211 static void
212 gtk_print_unix_dialog_class_init (GtkPrintUnixDialogClass *class)
213 {
214   GObjectClass *object_class;
215   GtkWidgetClass *widget_class;
216
217   object_class = (GObjectClass *) class;
218   widget_class = (GtkWidgetClass *) class;
219
220   object_class->finalize = gtk_print_unix_dialog_finalize;
221   object_class->set_property = gtk_print_unix_dialog_set_property;
222   object_class->get_property = gtk_print_unix_dialog_get_property;
223
224   widget_class->style_set = gtk_print_unix_dialog_style_set;
225
226   g_object_class_install_property (object_class,
227                                    PROP_PAGE_SETUP,
228                                    g_param_spec_object ("page-setup",
229                                                         P_("Page Setup"),
230                                                         P_("The GtkPageSetup to use"),
231                                                         GTK_TYPE_PAGE_SETUP,
232                                                         GTK_PARAM_READWRITE));
233
234   g_object_class_install_property (object_class,
235                                    PROP_CURRENT_PAGE,
236                                    g_param_spec_int ("current-page",
237                                                      P_("Current Page"),
238                                                      P_("The current page in the document"),
239                                                      -1,
240                                                      G_MAXINT,
241                                                      -1,
242                                                      GTK_PARAM_READWRITE));
243
244   g_object_class_install_property (object_class,
245                                    PROP_PRINT_SETTINGS,
246                                    g_param_spec_object ("print-settings",
247                                                         P_("Print Settings"),
248                                                         P_("The GtkPrintSettings used for initializing the dialog"),
249                                                         GTK_TYPE_PRINT_SETTINGS,
250                                                         GTK_PARAM_READWRITE));
251
252   g_object_class_install_property (object_class,
253                                    PROP_SELECTED_PRINTER,
254                                    g_param_spec_object ("selected-printer",
255                                                         P_("Selected Printer"),
256                                                         P_("The GtkPrinter which is selected"),
257                                                         GTK_TYPE_PRINTER,
258                                                         GTK_PARAM_READABLE));
259   
260   
261   g_type_class_add_private (class, sizeof (GtkPrintUnixDialogPrivate));  
262 }
263
264 static void
265 gtk_print_unix_dialog_init (GtkPrintUnixDialog *dialog)
266 {
267   GtkPrintUnixDialogPrivate *priv = dialog->priv;
268
269   priv = dialog->priv = GTK_PRINT_UNIX_DIALOG_GET_PRIVATE (dialog); 
270   priv->print_backends = NULL;
271   priv->current_page = -1;
272
273   priv->page_setup = gtk_page_setup_new ();
274
275   g_signal_connect (dialog, 
276                     "destroy", 
277                     (GCallback) gtk_print_unix_dialog_destroy, 
278                     NULL);
279
280   priv->preview_button = gtk_button_new_from_stock (GTK_STOCK_PRINT_PREVIEW);
281   gtk_widget_show (priv->preview_button);
282    
283   gtk_dialog_add_action_widget (GTK_DIALOG (dialog), 
284                                 priv->preview_button, 
285                                 GTK_RESPONSE_APPLY);
286   gtk_dialog_add_buttons (GTK_DIALOG (dialog),
287                           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
288                           GTK_STOCK_PRINT, GTK_RESPONSE_OK,
289                           NULL);
290
291   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
292   gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
293
294   populate_dialog (dialog);  
295 }
296
297 static void
298 gtk_print_unix_dialog_destroy (GtkPrintUnixDialog *dialog)
299 {
300   /* Make sure we don't destroy custom widgets owned by the backends */
301   clear_per_printer_ui (dialog);  
302 }
303
304 static void
305 gtk_print_unix_dialog_finalize (GObject *object)
306 {
307   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
308   GtkPrintUnixDialogPrivate *priv = dialog->priv;
309   GtkPrintBackend *backend;
310   GList *node;
311
312   unschedule_idle_mark_conflicts (dialog);
313
314   if (priv->request_details_tag)
315     {
316       g_source_remove (priv->request_details_tag);
317       priv->request_details_tag = 0;
318     }
319   
320   if (priv->current_printer)
321     {
322       g_object_unref (priv->current_printer);
323       priv->current_printer = NULL;
324     }
325
326   if (priv->printer_list)
327     {
328       g_object_unref (priv->printer_list);
329       priv->printer_list = NULL;
330     }
331  
332   if (priv->printer_list_filter)
333     {
334       g_object_unref (priv->printer_list_filter);
335       priv->printer_list_filter = NULL;
336     }
337
338  
339   if (priv->options)
340     {
341       g_object_unref (priv->options);
342       priv->options = NULL;
343     }
344  
345  if (priv->page_setup)
346     {
347       g_object_unref (priv->page_setup);
348       priv->page_setup = NULL;
349     }
350
351   if (priv->initial_settings)
352     {
353       g_object_unref (priv->initial_settings);
354       priv->initial_settings = NULL;
355     }
356
357   g_free (priv->waiting_for_printer);
358   priv->waiting_for_printer = NULL;
359   
360   g_free (priv->format_for_printer);
361   priv->format_for_printer = NULL;
362
363   for (node = priv->print_backends; node != NULL; node = node->next)
364     {
365       backend = GTK_PRINT_BACKEND (node->data);
366
367       g_signal_handlers_disconnect_by_func (backend, printer_added_cb, dialog);
368       g_signal_handlers_disconnect_by_func (backend, printer_removed_cb, dialog);
369       g_signal_handlers_disconnect_by_func (backend, printer_status_cb, dialog);
370
371       gtk_print_backend_destroy (backend);
372       g_object_unref (backend);
373     }
374   
375   g_list_free (priv->print_backends);
376   priv->print_backends = NULL;
377   
378   G_OBJECT_CLASS (gtk_print_unix_dialog_parent_class)->finalize (object);
379 }
380
381 static void
382 printer_removed_cb (GtkPrintBackend    *backend, 
383                     GtkPrinter         *printer, 
384                     GtkPrintUnixDialog *dialog)
385 {
386   GtkPrintUnixDialogPrivate *priv = dialog->priv;
387   GtkTreeIter *iter;
388
389   iter = g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter");
390   gtk_list_store_remove (GTK_LIST_STORE (priv->printer_list), iter);
391 }
392
393 static void
394 printer_status_cb (GtkPrintBackend    *backend, 
395                    GtkPrinter         *printer, 
396                    GtkPrintUnixDialog *dialog)
397 {
398   GtkPrintUnixDialogPrivate *priv = dialog->priv;
399   GtkTreeIter *iter;
400
401   iter = g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter");
402
403   gtk_list_store_set (GTK_LIST_STORE (priv->printer_list), iter,
404                       PRINTER_LIST_COL_ICON, gtk_printer_get_icon_name (printer),
405                       PRINTER_LIST_COL_STATE, gtk_printer_get_state_message (printer),
406                       PRINTER_LIST_COL_JOBS, gtk_printer_get_job_count (printer),
407                       PRINTER_LIST_COL_LOCATION, gtk_printer_get_location (printer),
408                       -1);
409
410 }
411
412 static void
413 printer_added_cb (GtkPrintBackend    *backend, 
414                   GtkPrinter         *printer, 
415                   GtkPrintUnixDialog *dialog)
416 {
417   GtkPrintUnixDialogPrivate *priv = dialog->priv;
418   GtkTreeIter iter, filter_iter;
419   GtkTreeSelection *selection;
420   GtkTreePath *path;
421
422   gtk_list_store_append (GTK_LIST_STORE (priv->printer_list), &iter);
423   
424   g_object_set_data_full (G_OBJECT (printer), 
425                          "gtk-print-tree-iter", 
426                           gtk_tree_iter_copy (&iter),
427                           (GDestroyNotify) gtk_tree_iter_free);
428
429   gtk_list_store_set (GTK_LIST_STORE (priv->printer_list), &iter,
430                       PRINTER_LIST_COL_ICON, gtk_printer_get_icon_name (printer),
431                       PRINTER_LIST_COL_NAME, gtk_printer_get_name (printer),
432                       PRINTER_LIST_COL_STATE, gtk_printer_get_state_message (printer),
433                       PRINTER_LIST_COL_JOBS, gtk_printer_get_job_count (printer),
434                       PRINTER_LIST_COL_LOCATION, gtk_printer_get_location (printer),
435                       PRINTER_LIST_COL_PRINTER_OBJ, printer,
436                       -1);
437
438   gtk_tree_model_filter_convert_child_iter_to_iter (priv->printer_list_filter,
439                                                     &filter_iter, &iter);
440   path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->printer_list_filter), &filter_iter);
441
442   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
443   
444   if (priv->waiting_for_printer != NULL &&
445       strcmp (gtk_printer_get_name (printer),
446               priv->waiting_for_printer) == 0)
447     {
448       priv->internal_printer_change = TRUE;
449       gtk_tree_selection_select_iter (selection, &filter_iter);
450       gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->printer_treeview),
451                                     path, NULL, TRUE, 0.5, 0.0);
452       priv->internal_printer_change = FALSE;
453       g_free (priv->waiting_for_printer);
454       priv->waiting_for_printer = NULL;
455     }
456   else if (is_default_printer (dialog, printer) &&
457            gtk_tree_selection_count_selected_rows (selection) == 0)
458     {
459       priv->internal_printer_change = TRUE;
460       gtk_tree_selection_select_iter (selection, &filter_iter);
461       gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->printer_treeview),
462                                     path, NULL, TRUE, 0.5, 0.0);
463       priv->internal_printer_change = FALSE;
464     }
465
466   gtk_tree_path_free (path);
467 }
468
469 static void
470 printer_list_initialize (GtkPrintUnixDialog *dialog,
471                          GtkPrintBackend    *print_backend)
472 {
473   GList *list;
474   GList *node;
475
476   g_return_if_fail (print_backend != NULL);
477
478   g_signal_connect_object (print_backend, 
479                            "printer-added", 
480                            (GCallback) printer_added_cb, 
481                            G_OBJECT (dialog), 0);
482
483   g_signal_connect_object (print_backend, 
484                            "printer-removed", 
485                            (GCallback) printer_removed_cb, 
486                            G_OBJECT (dialog), 0);
487
488   g_signal_connect_object (print_backend, 
489                            "printer-status-changed", 
490                            (GCallback) printer_status_cb, 
491                            G_OBJECT (dialog), 0);
492
493   list = gtk_print_backend_get_printer_list (print_backend);
494
495   node = list;
496   while (node != NULL)
497     {
498       printer_added_cb (print_backend, node->data, dialog);
499       node = node->next;
500     }
501
502   g_list_free (list);
503 }
504
505 static void
506 load_print_backends (GtkPrintUnixDialog *dialog)
507 {
508   GtkPrintUnixDialogPrivate *priv = dialog->priv;
509   GList *node;
510
511   if (g_module_supported ())
512     priv->print_backends = gtk_print_backend_load_modules ();
513
514   for (node = priv->print_backends; node != NULL; node = node->next)
515     printer_list_initialize (dialog, GTK_PRINT_BACKEND (node->data));
516 }
517
518 static void
519 gtk_print_unix_dialog_set_property (GObject      *object,
520                                     guint         prop_id,
521                                     const GValue *value,
522                                     GParamSpec   *pspec)
523
524 {
525   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
526
527   switch (prop_id)
528     {
529     case PROP_PAGE_SETUP:
530       gtk_print_unix_dialog_set_page_setup (dialog, g_value_get_object (value));
531       break;
532     case PROP_CURRENT_PAGE:
533       gtk_print_unix_dialog_set_current_page (dialog, g_value_get_int (value));
534       break;
535     case PROP_PRINT_SETTINGS:
536       gtk_print_unix_dialog_set_settings (dialog, g_value_get_object (value));
537       break;
538     default:
539       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
540       break;
541     }
542 }
543
544 static void
545 gtk_print_unix_dialog_get_property (GObject    *object,
546                                     guint       prop_id,
547                                     GValue     *value,
548                                     GParamSpec *pspec)
549 {
550   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
551   GtkPrintUnixDialogPrivate *priv = dialog->priv;
552
553   switch (prop_id)
554     {
555     case PROP_PAGE_SETUP:
556       g_value_set_object (value, priv->page_setup);
557       break;
558     case PROP_CURRENT_PAGE:
559       g_value_set_int (value, priv->current_page);
560       break;
561     case PROP_PRINT_SETTINGS:
562       g_value_set_object (value, gtk_print_unix_dialog_get_settings (dialog));
563       break;
564     case PROP_SELECTED_PRINTER:
565       g_value_set_object (value, priv->current_printer);
566       break;
567     default:
568       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
569       break;
570     }
571 }
572
573 static gboolean
574 is_printer_active (GtkTreeModel       *model,
575                    GtkTreeIter        *iter,
576                    GtkPrintUnixDialog *dialog)
577 {
578   gboolean result;
579   GtkPrinter *printer;
580   GtkPrintUnixDialogPrivate *priv = dialog->priv;
581
582   gtk_tree_model_get (model,
583                       iter,
584                       PRINTER_LIST_COL_PRINTER_OBJ,
585                       &printer,
586                       -1);
587   
588   if (printer == NULL)
589     return FALSE;
590
591   result = gtk_printer_is_active (printer);
592   
593   if (result && 
594       priv->manual_capabilities & (GTK_PRINT_CAPABILITY_GENERATE_PDF |
595                                    GTK_PRINT_CAPABILITY_GENERATE_PS))
596     {
597        /* Check that the printer can handle at least one of the data 
598         * formats that the application supports.
599         */
600        result = ((priv->manual_capabilities & GTK_PRINT_CAPABILITY_GENERATE_PDF) &&
601                  gtk_printer_accepts_pdf (printer)) ||
602                 ((priv->manual_capabilities & GTK_PRINT_CAPABILITY_GENERATE_PS) &&
603                  gtk_printer_accepts_ps (printer));
604     }
605   
606   g_object_unref (printer);
607   
608   return result;
609 }
610
611 static gint
612 default_printer_list_sort_func (GtkTreeModel *model,
613                                 GtkTreeIter  *a,
614                                 GtkTreeIter  *b,
615                                 gpointer      user_data)
616 {
617   gchar *a_name;
618   gchar *b_name;
619   GtkPrinter *a_printer;
620   GtkPrinter *b_printer;
621   gint result;
622
623   gtk_tree_model_get (model, a, 
624                       PRINTER_LIST_COL_NAME, &a_name, 
625                       PRINTER_LIST_COL_PRINTER_OBJ, &a_printer,
626                       -1);
627   gtk_tree_model_get (model, b, 
628                       PRINTER_LIST_COL_NAME, &b_name,
629                       PRINTER_LIST_COL_PRINTER_OBJ, &b_printer,
630                       -1);
631
632   if (a_printer == NULL && b_printer == NULL)
633     result = 0;
634   else if (a_printer == NULL)
635    result = G_MAXINT;
636   else if (b_printer == NULL)
637    result = G_MININT;
638   else if (gtk_printer_is_virtual (a_printer) && gtk_printer_is_virtual (b_printer))
639     result = 0;
640   else if (gtk_printer_is_virtual (a_printer) && !gtk_printer_is_virtual (b_printer))
641     result = G_MININT;
642   else if (!gtk_printer_is_virtual (a_printer) && gtk_printer_is_virtual (b_printer))
643     result = G_MAXINT;
644   else if (a_name == NULL && b_name == NULL)
645     result = 0;
646   else if (a_name == NULL && b_name != NULL)
647     result = 1;
648   else if (a_name != NULL && b_name == NULL)
649     result = -1;
650   else
651     result = g_ascii_strcasecmp (a_name, b_name);
652
653   g_free (a_name);
654   g_free (b_name);
655   g_object_unref (a_printer);
656   g_object_unref (b_printer);
657
658   return result;
659 }
660
661
662 static void
663 create_printer_list_model (GtkPrintUnixDialog *dialog)
664 {
665   GtkPrintUnixDialogPrivate *priv = dialog->priv;
666   GtkListStore *model;
667   GtkTreeSortable *sort;
668
669   model = gtk_list_store_new (PRINTER_LIST_N_COLS,
670                               G_TYPE_STRING,
671                               G_TYPE_STRING, 
672                               G_TYPE_STRING, 
673                               G_TYPE_INT, 
674                               G_TYPE_STRING,
675                               G_TYPE_OBJECT);
676
677   priv->printer_list = (GtkTreeModel *)model;
678   priv->printer_list_filter = (GtkTreeModelFilter *) gtk_tree_model_filter_new ((GtkTreeModel *)model,
679                                                                                         NULL);
680
681   gtk_tree_model_filter_set_visible_func (priv->printer_list_filter,
682                                           (GtkTreeModelFilterVisibleFunc) is_printer_active,
683                                           dialog,
684                                           NULL);
685
686   sort = GTK_TREE_SORTABLE (model);
687   gtk_tree_sortable_set_default_sort_func (sort,
688                                            default_printer_list_sort_func,
689                                            NULL,
690                                            NULL);
691  
692   gtk_tree_sortable_set_sort_column_id (sort,
693                                         GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
694                                         GTK_SORT_ASCENDING);
695
696 }
697
698
699 static GtkWidget *
700 wrap_in_frame (const gchar *label, 
701                GtkWidget   *child)
702 {
703   GtkWidget *frame, *alignment, *label_widget;
704   gchar *bold_text;
705
706   label_widget = gtk_label_new ("");
707   gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
708   gtk_widget_show (label_widget);
709   
710   bold_text = g_markup_printf_escaped ("<b>%s</b>", label);
711   gtk_label_set_markup (GTK_LABEL (label_widget), bold_text);
712   g_free (bold_text);
713   
714   frame = gtk_vbox_new (FALSE, 6);
715   gtk_box_pack_start (GTK_BOX (frame), label_widget, FALSE, FALSE, 0);
716   
717   alignment = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
718   gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
719                              0, 0, 12, 0);
720   gtk_box_pack_start (GTK_BOX (frame), alignment, FALSE, FALSE, 0);
721
722   gtk_container_add (GTK_CONTAINER (alignment), child);
723
724   gtk_widget_show (frame);
725   gtk_widget_show (alignment);
726   
727   return frame;
728 }
729
730 static gboolean
731 setup_option (GtkPrintUnixDialog     *dialog,
732               const gchar            *option_name,
733               GtkPrinterOptionWidget *widget)
734 {
735   GtkPrintUnixDialogPrivate *priv = dialog->priv;
736   GtkPrinterOption *option;
737
738   option = gtk_printer_option_set_lookup (priv->options, option_name);
739   gtk_printer_option_widget_set_source (widget, option);
740
741   return option != NULL;
742 }
743
744 static void
745 add_option_to_extension_point (GtkPrinterOption *option,
746                                gpointer          data)
747 {
748   GtkWidget *extension_point = data;
749   GtkWidget *widget;
750
751   widget = gtk_printer_option_widget_new (option);
752   gtk_widget_show (widget);
753    
754   if (gtk_printer_option_widget_has_external_label (GTK_PRINTER_OPTION_WIDGET (widget)))
755     {
756       GtkWidget *label, *hbox;
757       
758       label = gtk_printer_option_widget_get_external_label (GTK_PRINTER_OPTION_WIDGET (widget));
759       gtk_widget_show (label);
760       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
761       gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
762       
763       hbox = gtk_hbox_new (FALSE, 12);
764       gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
765       gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
766       gtk_widget_show (hbox);
767       
768       gtk_box_pack_start (GTK_BOX (extension_point), hbox, FALSE, FALSE, 0);
769     }
770   else
771     gtk_box_pack_start (GTK_BOX (extension_point), widget, FALSE, FALSE, 0);
772 }
773
774 static void
775 add_option_to_table (GtkPrinterOption *option,
776                      gpointer          user_data)
777 {
778   GtkTable *table;
779   GtkWidget *label, *widget;
780   gint row;
781
782   table = GTK_TABLE (user_data);
783   
784   if (g_str_has_prefix (option->name, "gtk-"))
785     return;
786   
787   widget = gtk_printer_option_widget_new (option);
788   gtk_widget_show (widget);
789
790   row = table->nrows;
791   gtk_table_resize (table, table->nrows + 1, 2);
792   
793   if (gtk_printer_option_widget_has_external_label (GTK_PRINTER_OPTION_WIDGET (widget)))
794     {
795       label = gtk_printer_option_widget_get_external_label (GTK_PRINTER_OPTION_WIDGET (widget));
796       gtk_widget_show (label);
797
798       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
799       gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
800
801       gtk_table_attach (table, label,
802                         0, 1, row - 1 , row,  GTK_FILL, 0, 0, 0);
803       
804       gtk_table_attach (table, widget,
805                         1, 2, row - 1, row,  GTK_FILL, 0, 0, 0);
806     }
807   else
808     gtk_table_attach (table, widget,
809                       0, 2, row - 1, row,  GTK_FILL, 0, 0, 0);
810 }
811
812
813 static void
814 setup_page_table (GtkPrinterOptionSet *options,
815                   const gchar         *group,
816                   GtkWidget           *table,
817                   GtkWidget           *page)
818 {
819   gtk_printer_option_set_foreach_in_group (options, group,
820                                            add_option_to_table,
821                                            table);
822   if (GTK_TABLE (table)->nrows == 1)
823     gtk_widget_hide (page);
824   else
825     gtk_widget_show (page);
826 }
827
828 static void
829 update_print_at_option (GtkPrintUnixDialog *dialog)
830 {
831   GtkPrintUnixDialogPrivate *priv = dialog->priv;
832   GtkPrinterOption *option;
833   
834   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time");
835
836   if (option == NULL)
837     return;
838   
839   if (priv->updating_print_at)
840     return;
841   
842   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->print_at_radio)))
843     gtk_printer_option_set (option, "at");
844   else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->print_hold_radio)))
845     gtk_printer_option_set (option, "on-hold");
846   else
847     gtk_printer_option_set (option, "now");
848   
849   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time-text");
850   if (option != NULL)
851     {
852       const char *text = gtk_entry_get_text (GTK_ENTRY (priv->print_at_entry));
853       gtk_printer_option_set (option,text);
854     }
855 }
856
857
858 static gboolean
859 setup_print_at (GtkPrintUnixDialog *dialog)
860 {
861   GtkPrintUnixDialogPrivate *priv = dialog->priv;
862   GtkPrinterOption *option;
863   
864   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time");
865  
866   if (option == NULL)
867     {
868       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_now_radio),
869                                     TRUE);
870       gtk_widget_set_sensitive (priv->print_at_radio, FALSE);
871       gtk_widget_set_sensitive (priv->print_at_entry, FALSE);
872       gtk_widget_set_sensitive (priv->print_hold_radio, FALSE);
873       gtk_entry_set_text (GTK_ENTRY (priv->print_at_entry), "");
874       return FALSE;
875     }
876
877   priv->updating_print_at = TRUE;
878   
879   if (gtk_printer_option_has_choice (option, "at"))
880     {
881       gtk_widget_set_sensitive (priv->print_at_radio, TRUE);
882       gtk_widget_set_sensitive (priv->print_at_entry, TRUE);
883     }
884   else
885     {
886       gtk_widget_set_sensitive (priv->print_at_radio, FALSE);
887       gtk_widget_set_sensitive (priv->print_at_entry, FALSE);
888     }
889   
890   gtk_widget_set_sensitive (priv->print_hold_radio,
891                             gtk_printer_option_has_choice (option, "on-hold"));
892
893   update_print_at_option (dialog);
894
895   if (strcmp (option->value, "at") == 0)
896     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_at_radio),
897                                   TRUE);
898   else if (strcmp (option->value, "on-hold") == 0)
899     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_hold_radio),
900                                   TRUE);
901   else
902     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_now_radio),
903                                   TRUE);
904
905   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time-text");
906   if (option != NULL)
907     gtk_entry_set_text (GTK_ENTRY (priv->print_at_entry),
908                         option->value);
909   
910
911   priv->updating_print_at = FALSE;
912
913   return TRUE;
914 }
915              
916 static void
917 update_dialog_from_settings (GtkPrintUnixDialog *dialog)
918 {
919   GtkPrintUnixDialogPrivate *priv = dialog->priv;
920   GList *groups, *l;
921   gchar *group;
922   GtkWidget *table, *frame;
923   gboolean has_advanced, has_job;
924  
925   if (priv->current_printer == NULL)
926     {
927        clear_per_printer_ui (dialog);
928        gtk_widget_hide (priv->job_page);
929        gtk_widget_hide (priv->advanced_page);
930        gtk_widget_hide (priv->image_quality_page);
931        gtk_widget_hide (priv->finishing_page);
932        gtk_widget_hide (priv->color_page);
933        gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
934
935        return;
936     }
937  
938   setup_option (dialog, "gtk-n-up", priv->pages_per_sheet);
939   setup_option (dialog, "gtk-duplex", priv->duplex);
940   setup_option (dialog, "gtk-paper-type", priv->paper_type);
941   setup_option (dialog, "gtk-paper-source", priv->paper_source);
942   setup_option (dialog, "gtk-output-tray", priv->output_tray);
943
944   has_job = FALSE;
945   has_job |= setup_option (dialog, "gtk-job-prio", priv->job_prio);
946   has_job |= setup_option (dialog, "gtk-billing-info", priv->billing_info);
947   has_job |= setup_option (dialog, "gtk-cover-before", priv->cover_before);
948   has_job |= setup_option (dialog, "gtk-cover-after", priv->cover_after);
949   has_job |= setup_print_at (dialog);
950   
951   if (has_job)
952     gtk_widget_show (priv->job_page);
953   else
954     gtk_widget_hide (priv->job_page);
955
956   
957   setup_page_table (priv->options,
958                     "ImageQualityPage",
959                     priv->image_quality_table,
960                     priv->image_quality_page);
961   
962   setup_page_table (priv->options,
963                     "FinishingPage",
964                     priv->finishing_table,
965                     priv->finishing_page);
966
967   setup_page_table (priv->options,
968                     "ColorPage",
969                     priv->color_table,
970                     priv->color_page);
971
972   gtk_printer_option_set_foreach_in_group (priv->options,
973                                            "GtkPrintDialogExtension",
974                                            add_option_to_extension_point,
975                                            priv->extension_point);
976
977   /* Put the rest of the groups in the advanced page */
978   groups = gtk_printer_option_set_get_groups (priv->options);
979
980   has_advanced = FALSE;
981   for (l = groups; l != NULL; l = l->next)
982     {
983       group = l->data;
984
985       if (group == NULL)
986         continue;
987       
988       if (strcmp (group, "ImageQualityPage") == 0 ||
989           strcmp (group, "ColorPage") == 0 ||
990           strcmp (group, "FinishingPage") == 0 ||
991           strcmp (group, "GtkPrintDialogExtension") == 0)
992         continue;
993
994       table = gtk_table_new (1, 2, FALSE);
995       gtk_table_set_row_spacings (GTK_TABLE (table), 6);
996       gtk_table_set_col_spacings (GTK_TABLE (table), 12);
997       
998       gtk_printer_option_set_foreach_in_group (priv->options,
999                                                group,
1000                                                add_option_to_table,
1001                                                table);
1002       if (GTK_TABLE (table)->nrows == 1)
1003         gtk_widget_destroy (table);
1004       else
1005         {
1006           has_advanced = TRUE;
1007           frame = wrap_in_frame (group, table);
1008           gtk_widget_show (table);
1009           gtk_widget_show (frame);
1010           
1011           gtk_box_pack_start (GTK_BOX (priv->advanced_vbox),
1012                               frame, FALSE, FALSE, 0);
1013         }
1014     }
1015
1016   if (has_advanced)
1017     gtk_widget_show (priv->advanced_page);
1018   else
1019     gtk_widget_hide (priv->advanced_page);
1020
1021   
1022   g_list_foreach (groups, (GFunc) g_free, NULL);
1023   g_list_free (groups);
1024 }
1025
1026 static void
1027 update_dialog_from_capabilities (GtkPrintUnixDialog *dialog)
1028 {
1029   GtkPrintCapabilities caps;
1030   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1031   gboolean can_collate;
1032   const gchar *copies;
1033
1034   copies = gtk_entry_get_text (GTK_ENTRY (priv->copies_spin));
1035   can_collate = (*copies != '\0' && atoi (copies) > 1);
1036
1037   caps = priv->manual_capabilities | priv->printer_capabilities;
1038
1039   gtk_widget_set_sensitive (priv->page_set_combo,
1040                             caps & GTK_PRINT_CAPABILITY_PAGE_SET);
1041   gtk_widget_set_sensitive (priv->copies_spin,
1042                             caps & GTK_PRINT_CAPABILITY_COPIES);
1043   gtk_widget_set_sensitive (priv->collate_check,
1044                             can_collate && 
1045                             (caps & GTK_PRINT_CAPABILITY_COLLATE));
1046   gtk_widget_set_sensitive (priv->reverse_check,
1047                             caps & GTK_PRINT_CAPABILITY_REVERSE);
1048   gtk_widget_set_sensitive (priv->scale_spin,
1049                             caps & GTK_PRINT_CAPABILITY_SCALE);
1050   gtk_widget_set_sensitive (GTK_WIDGET (priv->pages_per_sheet),
1051                             caps & GTK_PRINT_CAPABILITY_NUMBER_UP);
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;
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_widget_set_tooltip_text (radio, _("Specify one or more page ranges,\n e.g. 1-3,7,11"));
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       while (isspace (*p)) p++;
1648
1649       if (*p == '-')
1650         {
1651           /* a half-open range like -2 */
1652           start = 1;
1653         }
1654       else
1655         {
1656           start = (int)strtol (p, &next, 10);
1657           if (start < 1)
1658             start = 1;
1659           p = next;
1660         }
1661       
1662       end = start;
1663
1664       while (isspace (*p)) p++;
1665
1666       if (*p == '-')
1667         {
1668           p++;
1669           end = (int)strtol (p, &next, 10);
1670           if (next == p) /* a half-open range like 2- */
1671             end = 0;
1672           else if (end < start)
1673             end = start;
1674         }
1675
1676       ranges[i].start = start - 1;
1677       ranges[i].end = end - 1;
1678       i++;
1679
1680       /* Skip until end or separator */
1681       while (*p && !is_range_separator (*p))
1682         p++;
1683
1684       /* if not at end, skip separator */
1685       if (*p)
1686         p++;
1687     }
1688
1689   *n_ranges_out = i;
1690   
1691   return ranges;
1692 }
1693
1694 static void
1695 dialog_set_page_ranges (GtkPrintUnixDialog *dialog,
1696                         GtkPageRange       *ranges,
1697                         gint                n_ranges)
1698 {
1699   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1700   gint i;
1701   GString *s = g_string_new ("");
1702
1703   for (i = 0; i < n_ranges; i++)
1704     {
1705       g_string_append_printf (s, "%d", ranges[i].start + 1);
1706       if (ranges[i].end > ranges[i].start)
1707         g_string_append_printf (s, "-%d", ranges[i].end + 1);
1708       else if (ranges[i].end == -1)
1709         g_string_append (s, "-");
1710       
1711       if (i != n_ranges - 1)
1712         g_string_append (s, ",");
1713     }
1714
1715   gtk_entry_set_text (GTK_ENTRY (priv->page_range_entry), s->str);
1716   
1717   g_string_free (s, TRUE);
1718 }
1719
1720
1721 static GtkPrintPages
1722 dialog_get_print_pages (GtkPrintUnixDialog *dialog)
1723 {
1724   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1725   
1726   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->all_pages_radio)))
1727     return GTK_PRINT_PAGES_ALL;
1728   else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->current_page_radio)))
1729     return GTK_PRINT_PAGES_CURRENT;
1730   else
1731     return GTK_PRINT_PAGES_RANGES;
1732 }
1733
1734 static void
1735 dialog_set_print_pages (GtkPrintUnixDialog *dialog, 
1736                         GtkPrintPages       pages)
1737 {
1738   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1739
1740   if (pages == GTK_PRINT_PAGES_RANGES)
1741     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->page_range_radio), TRUE);
1742   else if (pages == GTK_PRINT_PAGES_CURRENT)
1743     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->current_page_radio), TRUE);
1744   else
1745     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->all_pages_radio), TRUE);
1746 }
1747
1748 static gdouble
1749 dialog_get_scale (GtkPrintUnixDialog *dialog)
1750 {
1751   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->scale_spin))
1752     return gtk_spin_button_get_value (GTK_SPIN_BUTTON (dialog->priv->scale_spin));
1753   else
1754     return 100.0;
1755 }
1756
1757 static void
1758 dialog_set_scale (GtkPrintUnixDialog *dialog, 
1759                   gdouble             val)
1760 {
1761   gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->scale_spin), val);
1762 }
1763
1764 static GtkPageSet
1765 dialog_get_page_set (GtkPrintUnixDialog *dialog)
1766 {
1767   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->page_set_combo))
1768     return (GtkPageSet)gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->page_set_combo));
1769   else
1770     return GTK_PAGE_SET_ALL;
1771 }
1772
1773 static void
1774 dialog_set_page_set (GtkPrintUnixDialog *dialog, 
1775                      GtkPageSet          val)
1776 {
1777   gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->priv->page_set_combo),
1778                             (int)val);
1779 }
1780
1781 static gint
1782 dialog_get_n_copies (GtkPrintUnixDialog *dialog)
1783 {
1784   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->copies_spin))
1785     return gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->priv->copies_spin));
1786   return 1;
1787 }
1788
1789 static void
1790 dialog_set_n_copies (GtkPrintUnixDialog *dialog, 
1791                      gint                n_copies)
1792 {
1793   gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->copies_spin),
1794                              n_copies);
1795 }
1796
1797 static gboolean
1798 dialog_get_collate (GtkPrintUnixDialog *dialog)
1799 {
1800   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->collate_check))
1801     return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->collate_check));
1802   return FALSE;
1803 }
1804
1805 static void
1806 dialog_set_collate (GtkPrintUnixDialog *dialog, 
1807                     gboolean            collate)
1808 {
1809   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->collate_check),
1810                                 collate);
1811 }
1812
1813 static gboolean
1814 dialog_get_reverse (GtkPrintUnixDialog *dialog)
1815 {
1816   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->reverse_check))
1817     return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->reverse_check));
1818   return FALSE;
1819 }
1820
1821 static void
1822 dialog_set_reverse (GtkPrintUnixDialog *dialog, 
1823                     gboolean            reverse)
1824 {
1825   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->reverse_check),
1826                                 reverse);
1827 }
1828
1829 static gint 
1830 dialog_get_pages_per_sheet (GtkPrintUnixDialog *dialog)
1831 {
1832   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1833   const gchar *val;
1834   gint num;
1835
1836   val = gtk_printer_option_widget_get_value (priv->pages_per_sheet);
1837
1838   num = 1;
1839   
1840   if (val)
1841     {
1842       num = atoi(val);
1843       if (num < 1)
1844         num = 1;
1845     }
1846   
1847   return num;
1848 }
1849
1850
1851 static gboolean
1852 draw_page_cb (GtkWidget          *widget,
1853               GdkEventExpose     *event,
1854               GtkPrintUnixDialog *dialog)
1855 {
1856   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1857   cairo_t *cr;
1858   gdouble ratio;
1859   gint w, h, tmp, shadow_offset;
1860   gint pages_x, pages_y, i, x, y, layout_w, layout_h;
1861   gdouble page_width, page_height;
1862   GtkPageOrientation orientation;
1863   gboolean landscape;
1864   PangoLayout *layout;
1865   PangoFontDescription *font;
1866   gchar *text;
1867   GdkColor *color;
1868   
1869   orientation = gtk_page_setup_get_orientation (priv->page_setup);
1870   landscape =
1871     (orientation == GTK_PAGE_ORIENTATION_LANDSCAPE) ||
1872     (orientation == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE);
1873   
1874   cr = gdk_cairo_create (widget->window);
1875   
1876   ratio = G_SQRT2;
1877
1878   w = (EXAMPLE_PAGE_AREA_SIZE - 3) / ratio;
1879   h = w * ratio;
1880
1881   switch (dialog_get_pages_per_sheet (dialog))
1882     {
1883     default:
1884     case 1:
1885       pages_x = 1; pages_y = 1;
1886       break;
1887     case 2:
1888       landscape = !landscape;
1889       pages_x = 1; pages_y = 2;
1890       break;
1891     case 4:
1892       pages_x = 2; pages_y = 2;
1893       break;
1894     case 6:
1895       landscape = !landscape;
1896       pages_x = 2; pages_y = 3;
1897       break;
1898     case 9:
1899       pages_x = 3; pages_y = 3;
1900       break;
1901     case 16:
1902       pages_x = 4; pages_y = 4;
1903       break;
1904     }
1905
1906   if (landscape)
1907     {
1908       tmp = w;
1909       w = h;
1910       h = tmp;
1911
1912       tmp = pages_x;
1913       pages_x = pages_y;
1914       pages_y = tmp;
1915     }
1916   
1917   shadow_offset = 3;
1918   
1919   color = &widget->style->text[GTK_STATE_NORMAL];
1920   cairo_set_source_rgba (cr, color->red / 65535., color->green / 65535., color->blue / 65535, 0.5);
1921   cairo_rectangle (cr, shadow_offset + 1, shadow_offset + 1, w, h);
1922   cairo_fill (cr);
1923   
1924   gdk_cairo_set_source_color (cr, &widget->style->base[GTK_STATE_NORMAL]);
1925   cairo_rectangle (cr, 1, 1, w, h);
1926   cairo_fill (cr);
1927   cairo_set_line_width (cr, 1.0);
1928   cairo_rectangle (cr, 0.5, 0.5, w+1, h+1);
1929   
1930   gdk_cairo_set_source_color (cr, &widget->style->text[GTK_STATE_NORMAL]);
1931   cairo_stroke (cr);
1932
1933   i = 1;
1934
1935   page_width = (double)w / pages_x;
1936   page_height = (double)h / pages_y;
1937
1938   layout  = pango_cairo_create_layout (cr);
1939
1940   font = pango_font_description_new ();
1941   pango_font_description_set_family (font, "sans");
1942   pango_font_description_set_absolute_size (font, page_height * 0.4 * PANGO_SCALE);
1943   pango_layout_set_font_description (layout, font);
1944   pango_font_description_free (font);
1945
1946   pango_layout_set_width (layout, page_width * PANGO_SCALE);
1947   pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
1948   
1949   for (y = 0; y < pages_y; y++)
1950     {
1951       for (x = 0; x < pages_x; x++)
1952         {
1953           text = g_strdup_printf ("%d", i++);
1954           pango_layout_set_text (layout, text, -1);
1955           g_free (text);
1956           pango_layout_get_size (layout, &layout_w, &layout_h);
1957           cairo_save (cr);
1958           cairo_translate (cr,
1959                            x * page_width,
1960                            y * page_height + (page_height - layout_h / 1024.0) / 2
1961                            );
1962           
1963           pango_cairo_show_layout (cr, layout);
1964           cairo_restore (cr);
1965         }
1966     }
1967     
1968   cairo_destroy (cr);
1969
1970   return TRUE;
1971 }
1972
1973 static void
1974 redraw_page_layout_preview (GtkPrintUnixDialog *dialog)
1975 {
1976   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1977
1978   if (priv->page_layout_preview)
1979     gtk_widget_queue_draw (priv->page_layout_preview);
1980 }
1981
1982 static void
1983 create_page_setup_page (GtkPrintUnixDialog *dialog)
1984 {
1985   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1986   GtkWidget *main_vbox, *label, *hbox, *hbox2;
1987   GtkWidget *frame, *table, *widget;
1988   GtkWidget *combo, *spinbutton, *draw;
1989
1990   main_vbox = gtk_vbox_new (FALSE, 18);
1991   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
1992   gtk_widget_show (main_vbox);
1993
1994   hbox = gtk_hbox_new (FALSE, 18);
1995   gtk_widget_show (hbox);
1996   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
1997
1998   table = gtk_table_new (5, 2, FALSE);
1999   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2000   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2001   frame = wrap_in_frame (_("Layout"), table);
2002   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
2003   gtk_widget_show (table);
2004
2005   label = gtk_label_new_with_mnemonic (_("Pages per _side:"));
2006   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2007   gtk_widget_show (label);
2008   gtk_table_attach (GTK_TABLE (table), label,
2009                     0, 1, 0, 1,  GTK_FILL, 0,
2010                     0, 0);
2011
2012   widget = gtk_printer_option_widget_new (NULL);
2013   g_signal_connect_swapped (widget, "changed", G_CALLBACK (redraw_page_layout_preview), dialog);
2014   priv->pages_per_sheet = GTK_PRINTER_OPTION_WIDGET (widget);
2015   gtk_widget_show (widget);
2016   gtk_table_attach (GTK_TABLE (table), widget,
2017                     1, 2, 0, 1,  GTK_FILL, 0,
2018                     0, 0);
2019   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2020
2021   label = gtk_label_new_with_mnemonic (_("T_wo-sided:"));
2022   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2023   gtk_widget_show (label);
2024   gtk_table_attach (GTK_TABLE (table), label,
2025                     0, 1, 1, 2,  GTK_FILL, 0,
2026                     0, 0);
2027
2028   widget = gtk_printer_option_widget_new (NULL);
2029   priv->duplex = GTK_PRINTER_OPTION_WIDGET (widget);
2030   gtk_widget_show (widget);
2031   gtk_table_attach (GTK_TABLE (table), widget,
2032                     1, 2, 1, 2,  GTK_FILL, 0,
2033                     0, 0);
2034   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2035
2036   label = gtk_label_new_with_mnemonic (_("_Only print:"));
2037   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2038   gtk_widget_show (label);
2039   gtk_table_attach (GTK_TABLE (table), label,
2040                     0, 1, 2, 3,  GTK_FILL, 0,
2041                     0, 0);
2042
2043   combo = gtk_combo_box_new_text ();
2044   priv->page_set_combo = combo;
2045   gtk_widget_show (combo);
2046   gtk_table_attach (GTK_TABLE (table), combo,
2047                     1, 2, 2, 3,  GTK_FILL, 0,
2048                     0, 0);
2049   gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
2050   /* In enum order */
2051   gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("All sheets"));  
2052   gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Even sheets"));  
2053   gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Odd sheets"));  
2054   gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
2055
2056   label = gtk_label_new_with_mnemonic (_("Sc_ale:"));
2057   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2058   gtk_widget_show (label);
2059   gtk_table_attach (GTK_TABLE (table), label,
2060                     0, 1, 3, 4,  GTK_FILL, 0,
2061                     0, 0);
2062
2063   hbox2 = gtk_hbox_new (FALSE, 6);
2064   gtk_widget_show (hbox2);
2065   gtk_table_attach (GTK_TABLE (table), hbox2,
2066                     1, 2, 3, 4,  GTK_FILL, 0,
2067                     0, 0);
2068   
2069   spinbutton = gtk_spin_button_new_with_range (1.0, 1000.0, 1.0);
2070   priv->scale_spin = spinbutton;
2071   gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinbutton), 1);
2072   gtk_spin_button_set_value (GTK_SPIN_BUTTON (spinbutton), 100.0);
2073   gtk_box_pack_start (GTK_BOX (hbox2), spinbutton, FALSE, FALSE, 0);
2074   gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
2075   gtk_widget_show (spinbutton);
2076   label = gtk_label_new ("%"); /* FIXMEchpe does there exist any language where % needs to be translated? */
2077   gtk_widget_show (label);
2078   gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0);
2079
2080   table = gtk_table_new (4, 2, FALSE);
2081   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2082   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2083   frame = wrap_in_frame (_("Paper"), table);
2084   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 6);
2085   gtk_widget_show (table);
2086
2087   label = gtk_label_new_with_mnemonic (_("Paper _type:"));
2088   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2089   gtk_widget_show (label);
2090   gtk_table_attach (GTK_TABLE (table), label,
2091                     0, 1, 0, 1,  GTK_FILL, 0,
2092                     0, 0);
2093
2094   widget = gtk_printer_option_widget_new (NULL);
2095   priv->paper_type = GTK_PRINTER_OPTION_WIDGET (widget);
2096   gtk_widget_show (widget);
2097   gtk_table_attach (GTK_TABLE (table), widget,
2098                     1, 2, 0, 1,  GTK_FILL, 0,
2099                     0, 0);
2100   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2101
2102   label = gtk_label_new_with_mnemonic (_("Paper _source:"));
2103   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2104   gtk_widget_show (label);
2105   gtk_table_attach (GTK_TABLE (table), label,
2106                     0, 1, 1, 2,  GTK_FILL, 0,
2107                     0, 0);
2108
2109   widget = gtk_printer_option_widget_new (NULL);
2110   priv->paper_source = GTK_PRINTER_OPTION_WIDGET (widget);
2111   gtk_widget_show (widget);
2112   gtk_table_attach (GTK_TABLE (table), widget,
2113                     1, 2, 1, 2,  GTK_FILL, 0,
2114                     0, 0);
2115   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2116
2117   label = gtk_label_new_with_mnemonic (_("Output t_ray:"));
2118   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2119   gtk_widget_show (label);
2120   gtk_table_attach (GTK_TABLE (table), label,
2121                     0, 1, 2, 3,  GTK_FILL, 0,
2122                     0, 0);
2123
2124   widget = gtk_printer_option_widget_new (NULL);
2125   priv->output_tray = GTK_PRINTER_OPTION_WIDGET (widget);
2126   gtk_widget_show (widget);
2127   gtk_table_attach (GTK_TABLE (table), widget,
2128                     1, 2, 2, 3,  GTK_FILL, 0,
2129                     0, 0);
2130   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2131
2132   /* Add the page layout preview */
2133   hbox2 = gtk_hbox_new (FALSE, 0);
2134   gtk_widget_show (hbox2);
2135   gtk_box_pack_start (GTK_BOX (main_vbox), hbox2, TRUE, TRUE, 0);
2136
2137   draw = gtk_drawing_area_new ();
2138   priv->page_layout_preview = draw;
2139   gtk_widget_set_size_request (draw, 200, 200);
2140   g_signal_connect (draw, "expose-event", G_CALLBACK (draw_page_cb), dialog);
2141   gtk_widget_show (draw);
2142
2143   gtk_box_pack_start (GTK_BOX (hbox2), draw, TRUE, FALSE, 0);
2144   
2145   label = gtk_label_new (_("Page Setup"));
2146   gtk_widget_show (label);
2147   
2148   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
2149                             main_vbox, label);
2150 }
2151
2152 static void
2153 create_job_page (GtkPrintUnixDialog *dialog)
2154 {
2155   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2156   GtkWidget *main_table, *label;
2157   GtkWidget *frame, *table, *radio;
2158   GtkWidget *entry, *widget;
2159
2160   main_table = gtk_table_new (2, 2, FALSE);
2161   gtk_container_set_border_width (GTK_CONTAINER (main_table), 12);
2162   gtk_table_set_row_spacings (GTK_TABLE (main_table), 18);
2163   gtk_table_set_col_spacings (GTK_TABLE (main_table), 18);
2164
2165   table = gtk_table_new (2, 2, FALSE);
2166   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2167   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2168   frame = wrap_in_frame (_("Job Details"), table);
2169   gtk_table_attach (GTK_TABLE (main_table), frame,
2170                     0, 1, 0, 1,  GTK_FILL, 0,
2171                     0, 0);
2172   gtk_widget_show (table);
2173
2174   label = gtk_label_new_with_mnemonic (_("Pri_ority:"));
2175   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2176   gtk_widget_show (label);
2177   gtk_table_attach (GTK_TABLE (table), label,
2178                     0, 1, 0, 1,  GTK_FILL, 0,
2179                     0, 0);
2180
2181   widget = gtk_printer_option_widget_new (NULL);
2182   priv->job_prio = GTK_PRINTER_OPTION_WIDGET (widget);
2183   gtk_widget_show (widget);
2184   gtk_table_attach (GTK_TABLE (table), widget,
2185                     1, 2, 0, 1,  GTK_FILL, 0,
2186                     0, 0);
2187   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2188
2189   label = gtk_label_new_with_mnemonic (_("_Billing info:"));
2190   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2191   gtk_widget_show (label);
2192   gtk_table_attach (GTK_TABLE (table), label,
2193                     0, 1, 1, 2,  GTK_FILL, 0,
2194                     0, 0);
2195
2196   widget = gtk_printer_option_widget_new (NULL);
2197   priv->billing_info = GTK_PRINTER_OPTION_WIDGET (widget);
2198   gtk_widget_show (widget);
2199   gtk_table_attach (GTK_TABLE (table), widget,
2200                     1, 2, 1, 2,  GTK_FILL, 0,
2201                     0, 0);
2202   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2203
2204   table = gtk_table_new (2, 2, FALSE);
2205   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2206   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2207   frame = wrap_in_frame (_("Print Document"), table);
2208   gtk_table_attach (GTK_TABLE (main_table), frame,
2209                     0, 1, 1, 2,  GTK_FILL, 0,
2210                     0, 0);
2211   gtk_widget_show (table);
2212
2213   radio = gtk_radio_button_new_with_mnemonic (NULL, _("_Now"));
2214   priv->print_now_radio = radio;
2215   gtk_widget_show (radio);
2216   gtk_table_attach (GTK_TABLE (table), radio,
2217                     0, 2, 0, 1,  GTK_FILL, 0,
2218                     0, 0);
2219   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
2220                                               _("A_t:"));
2221   priv->print_at_radio = radio;
2222   gtk_widget_show (radio);
2223   gtk_table_attach (GTK_TABLE (table), radio,
2224                     0, 1, 1, 2,  GTK_FILL, 0,
2225                     0, 0);
2226
2227   entry = gtk_entry_new ();
2228   priv->print_at_entry = entry;
2229   gtk_widget_show (entry);
2230   gtk_table_attach (GTK_TABLE (table), entry,
2231                     1, 2, 1, 2,  GTK_FILL, 0,
2232                     0, 0);
2233
2234   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
2235                                               _("On _hold"));
2236   priv->print_hold_radio = radio;
2237   gtk_widget_show (radio);
2238   gtk_table_attach (GTK_TABLE (table), radio,
2239                     0, 2, 2, 3,  GTK_FILL, 0,
2240                     0, 0);
2241
2242   g_signal_connect_swapped (priv->print_now_radio, "toggled",
2243                             G_CALLBACK (update_print_at_option), dialog);
2244   g_signal_connect_swapped (priv->print_at_radio, "toggled",
2245                             G_CALLBACK (update_print_at_option), dialog);
2246   g_signal_connect_swapped (priv->print_at_entry, "changed",
2247                             G_CALLBACK (update_print_at_option), dialog);
2248   g_signal_connect_swapped (priv->print_hold_radio, "toggled",
2249                             G_CALLBACK (update_print_at_option), dialog);
2250
2251   table = gtk_table_new (2, 2, FALSE);
2252   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2253   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2254   frame = wrap_in_frame (_("Add Cover Page"), table);
2255   gtk_table_attach (GTK_TABLE (main_table), frame,
2256                     1, 2, 0, 1,  GTK_FILL, 0,
2257                     0, 0);
2258   gtk_widget_show (table);
2259
2260   label = gtk_label_new_with_mnemonic (_("Be_fore:"));
2261   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2262   gtk_widget_show (label);
2263   gtk_table_attach (GTK_TABLE (table), label,
2264                     0, 1, 0, 1,  GTK_FILL, 0,
2265                     0, 0);
2266
2267   widget = gtk_printer_option_widget_new (NULL);
2268   priv->cover_before = GTK_PRINTER_OPTION_WIDGET (widget);
2269   gtk_widget_show (widget);
2270   gtk_table_attach (GTK_TABLE (table), widget,
2271                     1, 2, 0, 1,  GTK_FILL, 0,
2272                     0, 0);
2273   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2274
2275   label = gtk_label_new_with_mnemonic (_("_After:"));
2276   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2277   gtk_widget_show (label);
2278   gtk_table_attach (GTK_TABLE (table), label,
2279                     0, 1, 1, 2,  GTK_FILL, 0,
2280                     0, 0);
2281
2282   widget = gtk_printer_option_widget_new (NULL);
2283   priv->cover_after = GTK_PRINTER_OPTION_WIDGET (widget);
2284   gtk_widget_show (widget);
2285   gtk_table_attach (GTK_TABLE (table), widget,
2286                     1, 2, 1, 2,  GTK_FILL, 0,
2287                     0, 0);
2288   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2289
2290   label = gtk_label_new (_("Job"));
2291   gtk_widget_show (label);
2292
2293   priv->job_page = main_table;
2294   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
2295                             main_table, label);
2296 }
2297
2298 static void 
2299 create_optional_page (GtkPrintUnixDialog  *dialog,
2300                       const gchar         *text,
2301                       GtkWidget          **table_out,
2302                       GtkWidget          **page_out)
2303 {
2304   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2305   GtkWidget *table, *label, *scrolled;
2306
2307   scrolled = gtk_scrolled_window_new (NULL, NULL);
2308   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
2309                                   GTK_POLICY_NEVER,
2310                                   GTK_POLICY_AUTOMATIC);
2311   
2312   table = gtk_table_new (1, 2, FALSE);
2313   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2314   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2315   gtk_container_set_border_width (GTK_CONTAINER (table), 12);
2316   gtk_widget_show (table);
2317
2318   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
2319                                          table);
2320   gtk_viewport_set_shadow_type (GTK_VIEWPORT (GTK_BIN(scrolled)->child),
2321                                 GTK_SHADOW_NONE);
2322   
2323   label = gtk_label_new (text);
2324   gtk_widget_show (label);
2325   
2326   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
2327                             scrolled, label);
2328
2329   *table_out = table;
2330   *page_out = scrolled;
2331 }
2332
2333 static void
2334 create_advanced_page (GtkPrintUnixDialog *dialog)
2335 {
2336   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2337   GtkWidget *main_vbox, *label, *scrolled;
2338
2339   scrolled = gtk_scrolled_window_new (NULL, NULL);
2340   priv->advanced_page = scrolled;
2341   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
2342                                   GTK_POLICY_NEVER,
2343                                   GTK_POLICY_AUTOMATIC);
2344
2345   main_vbox = gtk_vbox_new (FALSE, 18);
2346   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
2347   gtk_widget_show (main_vbox);
2348
2349   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
2350                                          main_vbox);
2351   gtk_viewport_set_shadow_type (GTK_VIEWPORT (GTK_BIN(scrolled)->child),
2352                                 GTK_SHADOW_NONE);
2353   
2354   priv->advanced_vbox = main_vbox;
2355   
2356   label = gtk_label_new (_("Advanced"));
2357   gtk_widget_show (label);
2358   
2359   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
2360                             scrolled, label);
2361 }
2362
2363
2364 static void
2365 populate_dialog (GtkPrintUnixDialog *print_dialog)
2366 {
2367   GtkPrintUnixDialogPrivate *priv = print_dialog->priv;
2368   GtkDialog *dialog = GTK_DIALOG (print_dialog);
2369   GtkWidget *vbox, *conflict_hbox, *image, *label;
2370
2371   gtk_dialog_set_has_separator (dialog, FALSE);
2372   gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
2373   gtk_box_set_spacing (GTK_BOX (dialog->vbox), 2); /* 2 * 5 + 2 = 12 */
2374   gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 5);
2375   gtk_box_set_spacing (GTK_BOX (dialog->action_area), 6);
2376
2377   vbox = gtk_vbox_new (FALSE, 6);
2378   gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
2379   gtk_box_pack_start (GTK_BOX (dialog->vbox), vbox, TRUE, TRUE, 0);
2380   gtk_widget_show (vbox);
2381
2382   priv->notebook = gtk_notebook_new ();
2383   gtk_box_pack_start (GTK_BOX (vbox), priv->notebook, TRUE, TRUE, 0);
2384   gtk_widget_show (priv->notebook);
2385
2386   create_printer_list_model (print_dialog);
2387
2388   create_main_page (print_dialog);
2389   create_page_setup_page (print_dialog);
2390   create_job_page (print_dialog);
2391   create_optional_page (print_dialog, _("Image Quality"),
2392                         &priv->image_quality_table,
2393                         &priv->image_quality_page);
2394   create_optional_page (print_dialog, _("Color"),
2395                         &priv->color_table,
2396                         &priv->color_page);
2397   create_optional_page (print_dialog, _("Finishing"),
2398                         &priv->finishing_table,
2399                         &priv->finishing_page);
2400   create_advanced_page (print_dialog);
2401
2402   priv->conflicts_widget = conflict_hbox = gtk_hbox_new (FALSE, 12);
2403   gtk_box_pack_end (GTK_BOX (vbox), conflict_hbox, FALSE, FALSE, 0);
2404   image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_MENU);
2405   gtk_widget_show (image);
2406   gtk_box_pack_start (GTK_BOX (conflict_hbox), image, FALSE, TRUE, 0);
2407   label = gtk_label_new (_("Some of the settings in the dialog conflict"));
2408   gtk_widget_show (label);
2409   gtk_box_pack_start (GTK_BOX (conflict_hbox), label, FALSE, TRUE, 0);
2410   
2411   load_print_backends (print_dialog);
2412 }
2413
2414 /**
2415  * gtk_print_unix_dialog_new:
2416  * @title: Title of the dialog, or %NULL
2417  * @parent: Transient parent of the dialog, or %NULL
2418  *
2419  * Creates a new #GtkPrintUnixDialog.
2420  *
2421  * Return value: a new #GtkPrintUnixDialog
2422  *
2423  * Since: 2.10
2424  **/
2425 GtkWidget *
2426 gtk_print_unix_dialog_new (const gchar *title,
2427                            GtkWindow   *parent)
2428 {
2429   GtkWidget *result;
2430   const gchar *_title = _("Print");
2431
2432   if (title)
2433     _title = title;
2434
2435   result = g_object_new (GTK_TYPE_PRINT_UNIX_DIALOG,
2436                          "transient-for", parent,
2437                          "title", _title,
2438                          "has-separator", FALSE,
2439                          NULL);
2440   
2441   return result;
2442 }
2443
2444 /**
2445  * gtk_print_unix_dialog_get_selected_printer:
2446  * @dialog: a #GtkPrintUnixDialog
2447  * 
2448  * Gets the currently selected printer.
2449  * 
2450  * Returns: the currently selected printer
2451  * 
2452  * Since: 2.10
2453  */
2454 GtkPrinter *
2455 gtk_print_unix_dialog_get_selected_printer (GtkPrintUnixDialog *dialog)
2456 {
2457   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
2458
2459   return dialog->priv->current_printer;
2460 }
2461
2462 /**
2463  * gtk_print_unix_dialog_set_page_setup:
2464  * @dialog: a #GtkPrintUnixDialog
2465  * @page_setup: a #GtkPageSetup
2466  * 
2467  * Sets the page setup of the #GtkPrintUnixDialog.
2468  *
2469  * Since: 2.10
2470  */
2471 void
2472 gtk_print_unix_dialog_set_page_setup (GtkPrintUnixDialog *dialog,
2473                                       GtkPageSetup       *page_setup)
2474 {
2475   GtkPrintUnixDialogPrivate *priv;
2476
2477   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
2478   g_return_if_fail (GTK_IS_PAGE_SETUP (page_setup));
2479
2480   priv = dialog->priv;
2481
2482   if (priv->page_setup != page_setup)
2483     {
2484       g_object_unref (priv->page_setup);
2485       priv->page_setup = g_object_ref (page_setup);
2486
2487       g_object_notify (G_OBJECT (dialog), "page-setup");
2488     }
2489 }
2490
2491 /**
2492  * gtk_print_unix_dialog_get_page_setup:
2493  * @dialog: a #GtkPrintUnixDialog
2494  * 
2495  * Gets the page setup that is used by the #GtkPrintUnixDialog.
2496  * 
2497  * Returns: the page setup of @dialog.
2498  *
2499  * Since: 2.10
2500  */
2501 GtkPageSetup *
2502 gtk_print_unix_dialog_get_page_setup (GtkPrintUnixDialog *dialog)
2503 {
2504   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
2505
2506   return dialog->priv->page_setup;
2507 }
2508
2509 /**
2510  * gtk_print_unix_dialog_set_current_page:
2511  * @dialog: a #GtkPrintUnixDialog
2512  * @current_page: the current page number.
2513  * 
2514  * Sets the current page number. If @current_page is not -1, this enables
2515  * the current page choice for the range of pages to print.
2516  *
2517  * Since: 2.10
2518  */
2519 void
2520 gtk_print_unix_dialog_set_current_page (GtkPrintUnixDialog *dialog,
2521                                         gint                current_page)
2522 {
2523   GtkPrintUnixDialogPrivate *priv;
2524
2525   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
2526
2527   priv = dialog->priv;
2528
2529   if (priv->current_page != current_page)
2530     {
2531       priv->current_page = current_page;
2532
2533       if (priv->current_page_radio)
2534         gtk_widget_set_sensitive (priv->current_page_radio, current_page != -1);
2535
2536       g_object_notify (G_OBJECT (dialog), "current-page");
2537     }
2538 }
2539
2540 /**
2541  * gtk_print_unix_dialog_get_current_page:
2542  * @dialog: a #GtkPrintUnixDialog
2543  * 
2544  * Gets the current page of the #GtkPrintDialog.
2545  * 
2546  * Returns: the current page of @dialog
2547  * 
2548  * Since: 2.10
2549  */
2550 gint
2551 gtk_print_unix_dialog_get_current_page (GtkPrintUnixDialog *dialog)
2552 {
2553   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), -1);
2554
2555   return dialog->priv->current_page;
2556 }
2557
2558 static gboolean
2559 set_active_printer (GtkPrintUnixDialog *dialog,
2560                     const gchar        *printer_name)
2561 {
2562   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2563   GtkTreeModel *model;
2564   GtkTreeIter iter, filter_iter;
2565   GtkTreeSelection *selection;
2566   GtkPrinter *printer;
2567
2568   model = GTK_TREE_MODEL (priv->printer_list);
2569
2570   if (gtk_tree_model_get_iter_first (model, &iter))
2571     {
2572       do
2573         {
2574           gtk_tree_model_get (GTK_TREE_MODEL (priv->printer_list), &iter,
2575                               PRINTER_LIST_COL_PRINTER_OBJ, &printer, -1);
2576           if (printer == NULL)
2577             continue;
2578           
2579           if (strcmp (gtk_printer_get_name (printer), printer_name) == 0)
2580             {
2581               gtk_tree_model_filter_convert_child_iter_to_iter (priv->printer_list_filter,
2582                                                                 &filter_iter, &iter);
2583               
2584               selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
2585               priv->internal_printer_change = TRUE;
2586               gtk_tree_selection_select_iter (selection, &filter_iter);
2587               priv->internal_printer_change = FALSE;
2588               g_free (priv->waiting_for_printer);
2589               priv->waiting_for_printer = NULL;
2590               
2591               g_object_unref (printer);
2592               return TRUE;
2593             }
2594               
2595           g_object_unref (printer);
2596           
2597         } while (gtk_tree_model_iter_next (model, &iter));
2598     }
2599   
2600   return FALSE;
2601 }
2602
2603 /**
2604  * gtk_print_unix_dialog_set_settings:
2605  * @dialog: a #GtkPrintUnixDialog
2606  * @settings: a #GtkPrintSettings, or %NULL
2607  * 
2608  * Sets the #GtkPrintSettings for the #GtkPrintUnixDialog. Typically,
2609  * this is used to restore saved print settings from a previous print
2610  * operation before the print dialog is shown.
2611  * 
2612  * Since: 2.10
2613  **/
2614 void
2615 gtk_print_unix_dialog_set_settings (GtkPrintUnixDialog *dialog,
2616                                     GtkPrintSettings   *settings)
2617 {
2618   GtkPrintUnixDialogPrivate *priv;
2619   const gchar *printer;
2620   GtkPageRange *ranges;
2621   gint num_ranges;
2622   
2623   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
2624   g_return_if_fail (settings == NULL || GTK_IS_PRINT_SETTINGS (settings));
2625
2626   priv = dialog->priv;
2627
2628   if (settings != NULL)
2629     {
2630       dialog_set_collate (dialog, gtk_print_settings_get_collate (settings));
2631       dialog_set_reverse (dialog, gtk_print_settings_get_reverse (settings));
2632       dialog_set_n_copies (dialog, gtk_print_settings_get_n_copies (settings));
2633       dialog_set_scale (dialog, gtk_print_settings_get_scale (settings));
2634       dialog_set_page_set (dialog, gtk_print_settings_get_page_set (settings));
2635       dialog_set_print_pages (dialog, gtk_print_settings_get_print_pages (settings));
2636       ranges = gtk_print_settings_get_page_ranges (settings, &num_ranges);
2637       if (ranges)
2638         {
2639           dialog_set_page_ranges (dialog, ranges, num_ranges);
2640           g_free (ranges);
2641         }
2642
2643       priv->format_for_printer =
2644         g_strdup (gtk_print_settings_get (settings, "format-for-printer"));
2645     }
2646
2647   if (priv->initial_settings)
2648     g_object_unref (priv->initial_settings);
2649
2650   priv->initial_settings = settings;
2651
2652   g_free (priv->waiting_for_printer);
2653   priv->waiting_for_printer = NULL;
2654   
2655   if (settings)
2656     {
2657       g_object_ref (settings);
2658
2659       printer = gtk_print_settings_get_printer (settings);
2660       
2661       if (printer && !set_active_printer (dialog, printer))
2662         priv->waiting_for_printer = g_strdup (printer); 
2663     }
2664
2665   g_object_notify (G_OBJECT (dialog), "print-settings");
2666 }
2667
2668 /**
2669  * gtk_print_unix_dialog_get_settings:
2670  * @dialog: a #GtkPrintUnixDialog
2671  * 
2672  * Gets a new #GtkPrintSettings object that represents the
2673  * current values in the print dialog. Note that this creates a
2674  * <emphasis>new object</emphasis>, and you need to unref it
2675  * if don't want to keep it.
2676  * 
2677  * Returns: a new #GtkPrintSettings object with the values from @dialog
2678  *
2679  * Since: 2.10
2680  */
2681 GtkPrintSettings *
2682 gtk_print_unix_dialog_get_settings (GtkPrintUnixDialog *dialog)
2683 {
2684   GtkPrintUnixDialogPrivate *priv;
2685   GtkPrintSettings *settings;
2686   GtkPrintPages print_pages;
2687   GtkPageRange *ranges;
2688   gint n_ranges;
2689
2690   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
2691
2692   priv = dialog->priv;
2693   settings = gtk_print_settings_new ();
2694
2695   if (priv->current_printer)
2696     gtk_print_settings_set_printer (settings,
2697                                     gtk_printer_get_name (priv->current_printer));
2698   else
2699     gtk_print_settings_set_printer (settings, "default");
2700   
2701   gtk_print_settings_set (settings, "format-for-printer",
2702                           priv->format_for_printer);
2703
2704   
2705   gtk_print_settings_set_collate (settings,
2706                                   dialog_get_collate (dialog));
2707   
2708   gtk_print_settings_set_reverse (settings,
2709                                   dialog_get_reverse (dialog));
2710   
2711   gtk_print_settings_set_n_copies (settings,
2712                                    dialog_get_n_copies (dialog));
2713
2714   gtk_print_settings_set_scale (settings,
2715                                 dialog_get_scale (dialog));
2716   
2717   gtk_print_settings_set_page_set (settings,
2718                                    dialog_get_page_set (dialog));
2719   
2720   print_pages = dialog_get_print_pages (dialog);
2721   gtk_print_settings_set_print_pages (settings, print_pages);
2722
2723   ranges = dialog_get_page_ranges (dialog, &n_ranges);
2724   if (ranges)
2725     {
2726       gtk_print_settings_set_page_ranges  (settings, ranges, n_ranges);
2727       g_free (ranges);
2728     }
2729
2730   /* TODO: print when. How to handle? */
2731
2732   if (priv->current_printer)
2733     _gtk_printer_get_settings_from_options (priv->current_printer,
2734                                             priv->options,
2735                                             settings);
2736   
2737   return settings;
2738 }
2739
2740 /**
2741  * gtk_print_unix_dialog_add_custom_tab:
2742  * @dialog: a #GtkPrintUnixDialog
2743  * @child: the widget to put in the custom tab
2744  * @tab_label: the widget to use as tab label
2745  *
2746  * Adds a custom tab to the print dialog.
2747  *
2748  * Since: 2.10
2749  */
2750 void
2751 gtk_print_unix_dialog_add_custom_tab (GtkPrintUnixDialog *dialog,
2752                                       GtkWidget          *child,
2753                                       GtkWidget          *tab_label)
2754 {
2755   gtk_notebook_insert_page (GTK_NOTEBOOK (dialog->priv->notebook),
2756                             child, tab_label, 2);
2757   gtk_widget_show (child);
2758   gtk_widget_show (tab_label);
2759 }
2760
2761 /**
2762  * gtk_print_unix_dialog_set_manual_capabilities:
2763  * @dialog: a #GtkPrintUnixDialog
2764  * @capabilities: the printing capabilities of your application
2765  *
2766  * This lets you specify the printing capabilities your application
2767  * supports. For instance, if you can handle scaling the output then
2768  * you pass #GTK_PRINT_CAPABILITY_SCALE. If you don't pass that, then
2769  * the dialog will only let you select the scale if the printing
2770  * system automatically handles scaling.
2771  *
2772  * Since: 2.10
2773  */
2774 void
2775 gtk_print_unix_dialog_set_manual_capabilities (GtkPrintUnixDialog   *dialog,
2776                                                GtkPrintCapabilities  capabilities)
2777 {
2778   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2779
2780   priv->manual_capabilities = capabilities;
2781   update_dialog_from_capabilities (dialog);
2782
2783   if (priv->current_printer)
2784     {
2785       GtkTreeSelection *selection;
2786
2787       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
2788
2789       g_object_unref (priv->current_printer);
2790       priv->current_printer = NULL;
2791       priv->internal_printer_change = TRUE;
2792       selected_printer_changed (selection, dialog);
2793       priv->internal_printer_change = FALSE;
2794    }
2795 }
2796
2797 #define __GTK_PRINT_UNIX_DIALOG_C__
2798 #include "gtkaliasdef.c"
2799