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