]> Pileus Git - ~andy/gtk/blob - gtk/gtkpagesetupunixdialog.c
ff0ed19d4e5352953cc1e526504ce76b3f37c300
[~andy/gtk] / gtk / gtkpagesetupunixdialog.c
1 /* GtkPageSetupUnixDialog 
2  * Copyright (C) 2006 Alexander Larsson <alexl@redhat.com>
3  * Copyright © 2006, 2007, 2008 Christian Persch
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
22 #include "config.h"
23 #include <string.h>
24 #include <locale.h>
25
26 #include "gtkintl.h"
27 #include "gtkprivate.h"
28
29 #include "gtkliststore.h"
30 #include "gtkstock.h"
31 #include "gtktreeviewcolumn.h"
32 #include "gtktreeselection.h"
33 #include "gtktreemodel.h"
34 #include "gtkbutton.h"
35 #include "gtkscrolledwindow.h"
36 #include "gtkvbox.h"
37 #include "gtkhbox.h"
38 #include "gtkframe.h"
39 #include "gtkeventbox.h"
40 #include "gtkcombobox.h"
41 #include "gtktogglebutton.h"
42 #include "gtkradiobutton.h"
43 #include "gtklabel.h"
44 #include "gtktable.h"
45 #include "gtkcelllayout.h"
46 #include "gtkcellrenderertext.h"
47 #include "gtkalignment.h"
48 #include "gtkspinbutton.h"
49 #include "gtkbbox.h"
50 #include "gtkhbbox.h"
51
52 #include "gtkpagesetupunixdialog.h"
53 #include "gtkcustompaperunixdialog.h"
54 #include "gtkprintbackend.h"
55 #include "gtkpapersize.h"
56 #include "gtkprintutils.h"
57
58 /**
59  * SECTION:gtkpagesetupunixdialog
60  * @Short_description: A page setup dialog
61  * @Title: GtkPageSetupUnixDialog
62  *
63  * #GtkPageSetupUnixDialog implements a page setup dialog for platforms
64  * which don't provide a native page setup dialog, like Unix. It can
65  * be used very much like any other GTK+ dialog, at the cost of
66  * the portability offered by the <link
67  * linkend="gtk-High-level-Printing-API">high-level printing API</link>
68  *
69  * Printing support was added in GTK+ 2.10.
70  */
71
72
73 struct GtkPageSetupUnixDialogPrivate
74 {
75   GtkListStore *printer_list;
76   GtkListStore *page_setup_list;
77   GtkListStore *custom_paper_list;
78   
79   GList *print_backends;
80
81   GtkWidget *printer_combo;
82   GtkWidget *paper_size_combo;
83   GtkWidget *paper_size_label;
84
85   GtkWidget *portrait_radio;
86   GtkWidget *reverse_portrait_radio;
87   GtkWidget *landscape_radio;
88   GtkWidget *reverse_landscape_radio;
89
90   guint request_details_tag;
91   GtkPrinter *request_details_printer;
92   
93   GtkPrintSettings *print_settings;
94
95   /* Save last setup so we can re-set it after selecting manage custom sizes */
96   GtkPageSetup *last_setup;
97
98   gchar *waiting_for_printer;
99 };
100
101 enum {
102   PRINTER_LIST_COL_NAME,
103   PRINTER_LIST_COL_PRINTER,
104   PRINTER_LIST_N_COLS
105 };
106
107 enum {
108   PAGE_SETUP_LIST_COL_PAGE_SETUP,
109   PAGE_SETUP_LIST_COL_IS_SEPARATOR,
110   PAGE_SETUP_LIST_N_COLS
111 };
112
113 G_DEFINE_TYPE (GtkPageSetupUnixDialog, gtk_page_setup_unix_dialog, GTK_TYPE_DIALOG)
114
115 #define GTK_PAGE_SETUP_UNIX_DIALOG_GET_PRIVATE(o)  \
116    (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_PAGE_SETUP_UNIX_DIALOG, GtkPageSetupUnixDialogPrivate))
117
118 static void gtk_page_setup_unix_dialog_finalize  (GObject                *object);
119 static void populate_dialog                      (GtkPageSetupUnixDialog *dialog);
120 static void fill_paper_sizes_from_printer        (GtkPageSetupUnixDialog *dialog,
121                                                   GtkPrinter             *printer);
122 static void printer_added_cb                     (GtkPrintBackend        *backend,
123                                                   GtkPrinter             *printer,
124                                                   GtkPageSetupUnixDialog *dialog);
125 static void printer_removed_cb                   (GtkPrintBackend        *backend,
126                                                   GtkPrinter             *printer,
127                                                   GtkPageSetupUnixDialog *dialog);
128 static void printer_status_cb                    (GtkPrintBackend        *backend,
129                                                   GtkPrinter             *printer,
130                                                   GtkPageSetupUnixDialog *dialog);
131
132
133
134 static const gchar const common_paper_sizes[][16] = {
135   "na_letter",
136   "na_legal",
137   "iso_a4",
138   "iso_a5",
139   "roc_16k",
140   "iso_b5",
141   "jis_b5",
142   "na_number-10",
143   "iso_dl",
144   "jpn_chou3",
145   "na_ledger",
146   "iso_a3",
147 };
148
149
150 static void
151 gtk_page_setup_unix_dialog_class_init (GtkPageSetupUnixDialogClass *class)
152 {
153   GObjectClass *object_class;
154   GtkWidgetClass *widget_class;
155
156   object_class = (GObjectClass *) class;
157   widget_class = (GtkWidgetClass *) class;
158
159   object_class->finalize = gtk_page_setup_unix_dialog_finalize;
160
161   g_type_class_add_private (class, sizeof (GtkPageSetupUnixDialogPrivate));
162 }
163
164 static void
165 gtk_page_setup_unix_dialog_init (GtkPageSetupUnixDialog *dialog)
166 {
167   GtkPageSetupUnixDialogPrivate *priv;
168   GtkTreeIter iter;
169   gchar *tmp;
170
171   priv = dialog->priv = GTK_PAGE_SETUP_UNIX_DIALOG_GET_PRIVATE (dialog);
172
173   priv->print_backends = NULL;
174
175   priv->printer_list = gtk_list_store_new (PRINTER_LIST_N_COLS,
176                                                    G_TYPE_STRING,
177                                                    G_TYPE_OBJECT);
178
179   gtk_list_store_append (priv->printer_list, &iter);
180   tmp = g_strdup_printf ("<b>%s</b>\n%s", _("Any Printer"), _("For portable documents"));
181   gtk_list_store_set (priv->printer_list, &iter,
182                       PRINTER_LIST_COL_NAME, tmp,
183                       PRINTER_LIST_COL_PRINTER, NULL,
184                       -1);
185   g_free (tmp);
186
187   priv->page_setup_list = gtk_list_store_new (PAGE_SETUP_LIST_N_COLS,
188                                                       G_TYPE_OBJECT,
189                                                       G_TYPE_BOOLEAN);
190
191   priv->custom_paper_list = gtk_list_store_new (1, G_TYPE_OBJECT);
192   _gtk_print_load_custom_papers (priv->custom_paper_list);
193
194   populate_dialog (dialog);
195   
196   gtk_dialog_add_buttons (GTK_DIALOG (dialog), 
197                           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
198                           GTK_STOCK_APPLY, GTK_RESPONSE_OK,
199                           NULL);
200   gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
201                                            GTK_RESPONSE_OK,
202                                            GTK_RESPONSE_CANCEL,
203                                            -1);
204
205   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
206 }
207
208 static void
209 gtk_page_setup_unix_dialog_finalize (GObject *object)
210 {
211   GtkPageSetupUnixDialog *dialog = GTK_PAGE_SETUP_UNIX_DIALOG (object);
212   GtkPageSetupUnixDialogPrivate *priv = dialog->priv;
213   GtkPrintBackend *backend;
214   GList *node;
215   
216   if (priv->request_details_tag)
217     {
218       g_signal_handler_disconnect (priv->request_details_printer,
219                                    priv->request_details_tag);
220       g_object_unref (priv->request_details_printer);
221       priv->request_details_printer = NULL;
222       priv->request_details_tag = 0;
223     }
224   
225   if (priv->printer_list)
226     {
227       g_object_unref (priv->printer_list);
228       priv->printer_list = NULL;
229     }
230
231   if (priv->page_setup_list)
232     {
233       g_object_unref (priv->page_setup_list);
234       priv->page_setup_list = NULL;
235     }
236
237   if (priv->custom_paper_list)
238     {
239       g_object_unref (priv->custom_paper_list);
240       priv->custom_paper_list = NULL;
241     }
242
243   if (priv->print_settings)
244     {
245       g_object_unref (priv->print_settings);
246       priv->print_settings = NULL;
247     }
248
249   g_free (priv->waiting_for_printer);
250   priv->waiting_for_printer = NULL;
251
252   for (node = priv->print_backends; node != NULL; node = node->next)
253     {
254       backend = GTK_PRINT_BACKEND (node->data);
255
256       g_signal_handlers_disconnect_by_func (backend, printer_added_cb, dialog);
257       g_signal_handlers_disconnect_by_func (backend, printer_removed_cb, dialog);
258       g_signal_handlers_disconnect_by_func (backend, printer_status_cb, dialog);
259
260       gtk_print_backend_destroy (backend);
261       g_object_unref (backend);
262     }
263   
264   g_list_free (priv->print_backends);
265   priv->print_backends = NULL;
266
267   G_OBJECT_CLASS (gtk_page_setup_unix_dialog_parent_class)->finalize (object);
268 }
269
270 static void
271 printer_added_cb (GtkPrintBackend        *backend, 
272                   GtkPrinter             *printer, 
273                   GtkPageSetupUnixDialog *dialog)
274 {
275   GtkPageSetupUnixDialogPrivate *priv = dialog->priv;
276   GtkTreeIter iter;
277   gchar *str;
278   const gchar *location;
279
280   if (gtk_printer_is_virtual (printer))
281     return;
282
283   location = gtk_printer_get_location (printer);
284   if (location == NULL)
285     location = "";
286   str = g_strdup_printf ("<b>%s</b>\n%s",
287                          gtk_printer_get_name (printer),
288                          location);
289
290   gtk_list_store_append (priv->printer_list, &iter);
291   gtk_list_store_set (priv->printer_list, &iter,
292                       PRINTER_LIST_COL_NAME, str,
293                       PRINTER_LIST_COL_PRINTER, printer,
294                       -1);
295
296   g_object_set_data_full (G_OBJECT (printer),
297                           "gtk-print-tree-iter",
298                           gtk_tree_iter_copy (&iter),
299                           (GDestroyNotify) gtk_tree_iter_free);
300   g_free (str);
301
302   if (priv->waiting_for_printer != NULL &&
303       strcmp (priv->waiting_for_printer,
304               gtk_printer_get_name (printer)) == 0)
305     {
306       gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->printer_combo),
307                                      &iter);
308       priv->waiting_for_printer = NULL;
309     }
310 }
311
312 static void
313 printer_removed_cb (GtkPrintBackend        *backend, 
314                     GtkPrinter             *printer, 
315                     GtkPageSetupUnixDialog *dialog)
316 {
317   GtkPageSetupUnixDialogPrivate *priv = dialog->priv;
318   GtkTreeIter *iter;
319
320   iter = g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter");
321   gtk_list_store_remove (GTK_LIST_STORE (priv->printer_list), iter);
322 }
323
324
325 static void
326 printer_status_cb (GtkPrintBackend        *backend, 
327                    GtkPrinter             *printer, 
328                    GtkPageSetupUnixDialog *dialog)
329 {
330   GtkPageSetupUnixDialogPrivate *priv = dialog->priv;
331   GtkTreeIter *iter;
332   gchar *str;
333   const gchar *location;
334   
335   iter = g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter");
336
337   location = gtk_printer_get_location (printer);
338   if (location == NULL)
339     location = "";
340   str = g_strdup_printf ("<b>%s</b>\n%s",
341                          gtk_printer_get_name (printer),
342                          location);
343   gtk_list_store_set (priv->printer_list, iter,
344                       PRINTER_LIST_COL_NAME, str,
345                       -1);
346   g_free (str);
347 }
348
349 static void
350 printer_list_initialize (GtkPageSetupUnixDialog *dialog,
351                          GtkPrintBackend        *print_backend)
352 {
353   GList *list, *node;
354   
355   g_return_if_fail (print_backend != NULL);
356
357   g_signal_connect_object (print_backend, 
358                            "printer-added", 
359                            (GCallback) printer_added_cb, 
360                            G_OBJECT (dialog), 0);
361
362   g_signal_connect_object (print_backend, 
363                            "printer-removed", 
364                            (GCallback) printer_removed_cb, 
365                            G_OBJECT (dialog), 0);
366
367   g_signal_connect_object (print_backend, 
368                            "printer-status-changed", 
369                            (GCallback) printer_status_cb, 
370                            G_OBJECT (dialog), 0);
371
372   list = gtk_print_backend_get_printer_list (print_backend);
373
374   node = list;
375   while (node != NULL)
376     {
377       printer_added_cb (print_backend, node->data, dialog);
378       node = node->next;
379     }
380
381   g_list_free (list);
382   
383 }
384
385 static void
386 load_print_backends (GtkPageSetupUnixDialog *dialog)
387 {
388   GtkPageSetupUnixDialogPrivate *priv = dialog->priv;
389   GList *node;
390
391   if (g_module_supported ())
392     priv->print_backends = gtk_print_backend_load_modules ();
393
394   for (node = priv->print_backends; node != NULL; node = node->next)
395     printer_list_initialize (dialog, GTK_PRINT_BACKEND (node->data));
396 }
397
398 static gboolean
399 paper_size_row_is_separator (GtkTreeModel *model,
400                              GtkTreeIter  *iter,
401                              gpointer      data)
402 {
403   gboolean separator;
404
405   gtk_tree_model_get (model, iter, PAGE_SETUP_LIST_COL_IS_SEPARATOR, &separator, -1);
406   return separator;
407 }
408
409 static GtkPageSetup *
410 get_current_page_setup (GtkPageSetupUnixDialog *dialog)
411 {
412   GtkPageSetupUnixDialogPrivate *priv = dialog->priv;
413   GtkPageSetup *current_page_setup;
414   GtkComboBox *combo_box;
415   GtkTreeIter iter;
416
417   current_page_setup = NULL;
418   
419   combo_box = GTK_COMBO_BOX (priv->paper_size_combo);
420   if (gtk_combo_box_get_active_iter (combo_box, &iter))
421     gtk_tree_model_get (GTK_TREE_MODEL (priv->page_setup_list), &iter,
422                         PAGE_SETUP_LIST_COL_PAGE_SETUP, &current_page_setup, -1);
423
424   if (current_page_setup)
425     return current_page_setup;
426
427   /* No selected page size, return the default one.
428    * This is used to set the first page setup when the dialog is created
429    * as there is no selection on the first printer_changed.
430    */ 
431   return gtk_page_setup_new ();
432 }
433
434 static gboolean
435 page_setup_is_equal (GtkPageSetup *a, 
436                      GtkPageSetup *b)
437 {
438   return
439     gtk_paper_size_is_equal (gtk_page_setup_get_paper_size (a),
440                              gtk_page_setup_get_paper_size (b)) &&
441     gtk_page_setup_get_top_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_top_margin (b, GTK_UNIT_MM) &&
442     gtk_page_setup_get_bottom_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_bottom_margin (b, GTK_UNIT_MM) &&
443     gtk_page_setup_get_left_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_left_margin (b, GTK_UNIT_MM) &&
444     gtk_page_setup_get_right_margin (a, GTK_UNIT_MM) == gtk_page_setup_get_right_margin (b, GTK_UNIT_MM);
445 }
446
447 static gboolean
448 page_setup_is_same_size (GtkPageSetup *a,
449                          GtkPageSetup *b)
450 {
451   return gtk_paper_size_is_equal (gtk_page_setup_get_paper_size (a),
452                                   gtk_page_setup_get_paper_size (b));
453 }
454
455 static gboolean
456 set_paper_size (GtkPageSetupUnixDialog *dialog,
457                 GtkPageSetup           *page_setup,
458                 gboolean                size_only,
459                 gboolean                add_item)
460 {
461   GtkPageSetupUnixDialogPrivate *priv = dialog->priv;
462   GtkTreeModel *model;
463   GtkTreeIter iter;
464   GtkPageSetup *list_page_setup;
465
466   model = GTK_TREE_MODEL (priv->page_setup_list);
467
468   if (gtk_tree_model_get_iter_first (model, &iter))
469     {
470       do
471         {
472           gtk_tree_model_get (GTK_TREE_MODEL (priv->page_setup_list), &iter,
473                               PAGE_SETUP_LIST_COL_PAGE_SETUP, &list_page_setup, -1);
474           if (list_page_setup == NULL)
475             continue;
476           
477           if ((size_only && page_setup_is_same_size (page_setup, list_page_setup)) ||
478               (!size_only && page_setup_is_equal (page_setup, list_page_setup)))
479             {
480               gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->paper_size_combo),
481                                              &iter);
482               g_object_unref (list_page_setup);
483               return TRUE;
484             }
485               
486           g_object_unref (list_page_setup);
487           
488         } while (gtk_tree_model_iter_next (model, &iter));
489     }
490
491   if (add_item)
492     {
493       gtk_list_store_append (priv->page_setup_list, &iter);
494       gtk_list_store_set (priv->page_setup_list, &iter,
495                           PAGE_SETUP_LIST_COL_IS_SEPARATOR, TRUE,
496                           -1);
497       gtk_list_store_append (priv->page_setup_list, &iter);
498       gtk_list_store_set (priv->page_setup_list, &iter,
499                           PAGE_SETUP_LIST_COL_PAGE_SETUP, page_setup,
500                           -1);
501       gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->paper_size_combo),
502                                      &iter);
503       return TRUE;
504     }
505
506   return FALSE;
507 }
508
509 static void
510 fill_custom_paper_sizes (GtkPageSetupUnixDialog *dialog)
511 {
512   GtkPageSetupUnixDialogPrivate *priv = dialog->priv;
513   GtkTreeIter iter, paper_iter;
514   GtkTreeModel *model;
515
516   model = GTK_TREE_MODEL (priv->custom_paper_list);
517   if (gtk_tree_model_get_iter_first (model, &iter))
518     {
519       gtk_list_store_append (priv->page_setup_list, &paper_iter);
520       gtk_list_store_set (priv->page_setup_list, &paper_iter,
521                           PAGE_SETUP_LIST_COL_IS_SEPARATOR, TRUE,
522                           -1);
523       do
524         {
525           GtkPageSetup *page_setup;
526           gtk_tree_model_get (model, &iter, 0, &page_setup, -1);
527
528           gtk_list_store_append (priv->page_setup_list, &paper_iter);
529           gtk_list_store_set (priv->page_setup_list, &paper_iter,
530                               PAGE_SETUP_LIST_COL_PAGE_SETUP, page_setup,
531                               -1);
532
533           g_object_unref (page_setup);
534         } while (gtk_tree_model_iter_next (model, &iter));
535     }
536   
537   gtk_list_store_append (priv->page_setup_list, &paper_iter);
538   gtk_list_store_set (priv->page_setup_list, &paper_iter,
539                       PAGE_SETUP_LIST_COL_IS_SEPARATOR, TRUE,
540                       -1);
541   gtk_list_store_append (priv->page_setup_list, &paper_iter);
542   gtk_list_store_set (priv->page_setup_list, &paper_iter,
543                       PAGE_SETUP_LIST_COL_PAGE_SETUP, NULL,
544                       -1);
545 }
546
547 static void
548 fill_paper_sizes_from_printer (GtkPageSetupUnixDialog *dialog,
549                                GtkPrinter             *printer)
550 {
551   GtkPageSetupUnixDialogPrivate *priv = dialog->priv;
552   GList *list, *l;
553   GtkPageSetup *current_page_setup, *page_setup;
554   GtkPaperSize *paper_size;
555   GtkTreeIter iter;
556   gint i;
557
558   gtk_list_store_clear (priv->page_setup_list);
559
560   if (printer == NULL)
561     {
562       for (i = 0; i < G_N_ELEMENTS (common_paper_sizes); i++)
563         {
564           page_setup = gtk_page_setup_new ();
565           paper_size = gtk_paper_size_new (common_paper_sizes[i]);
566           gtk_page_setup_set_paper_size_and_default_margins (page_setup, paper_size);
567           gtk_paper_size_free (paper_size);
568           
569           gtk_list_store_append (priv->page_setup_list, &iter);
570           gtk_list_store_set (priv->page_setup_list, &iter,
571                               PAGE_SETUP_LIST_COL_PAGE_SETUP, page_setup,
572                               -1);
573           g_object_unref (page_setup);
574         }
575     }
576   else
577     {
578       list = gtk_printer_list_papers (printer);
579       /* TODO: We should really sort this list so interesting size
580          are at the top */
581       for (l = list; l != NULL; l = l->next)
582         {
583           page_setup = l->data;
584           gtk_list_store_append (priv->page_setup_list, &iter);
585           gtk_list_store_set (priv->page_setup_list, &iter,
586                               PAGE_SETUP_LIST_COL_PAGE_SETUP, page_setup,
587                               -1);
588           g_object_unref (page_setup);
589         }
590       g_list_free (list);
591     }
592
593   fill_custom_paper_sizes (dialog);
594   
595   current_page_setup = NULL;
596
597   /* When selecting a different printer, select its default paper size */
598   if (printer != NULL)
599     current_page_setup = gtk_printer_get_default_page_size (printer);
600
601   if (current_page_setup == NULL)
602     current_page_setup = get_current_page_setup (dialog);
603
604   if (!set_paper_size (dialog, current_page_setup, FALSE, FALSE))
605     set_paper_size (dialog, current_page_setup, TRUE, TRUE);
606   
607   if (current_page_setup)
608     g_object_unref (current_page_setup);
609 }
610
611 static void
612 printer_changed_finished_callback (GtkPrinter             *printer,
613                                    gboolean                success,
614                                    GtkPageSetupUnixDialog *dialog)
615 {
616   GtkPageSetupUnixDialogPrivate *priv = dialog->priv;
617
618   g_signal_handler_disconnect (priv->request_details_printer,
619                                priv->request_details_tag);
620   g_object_unref (priv->request_details_printer);
621   priv->request_details_tag = 0;
622   priv->request_details_printer = NULL;
623   
624   if (success)
625     fill_paper_sizes_from_printer (dialog, printer);
626
627 }
628
629 static void
630 printer_changed_callback (GtkComboBox            *combo_box,
631                           GtkPageSetupUnixDialog *dialog)
632 {
633   GtkPageSetupUnixDialogPrivate *priv = dialog->priv;
634   GtkPrinter *printer;
635   GtkTreeIter iter;
636
637   /* If we're waiting for a specific printer but the user changed
638    * to another printer, cancel that wait. 
639    */
640   if (priv->waiting_for_printer)
641     {
642       g_free (priv->waiting_for_printer);
643       priv->waiting_for_printer = NULL;
644     }
645   
646   if (priv->request_details_tag)
647     {
648       g_signal_handler_disconnect (priv->request_details_printer,
649                                    priv->request_details_tag);
650       g_object_unref (priv->request_details_printer);
651       priv->request_details_printer = NULL;
652       priv->request_details_tag = 0;
653     }
654   
655   if (gtk_combo_box_get_active_iter (combo_box, &iter))
656     {
657       gtk_tree_model_get (gtk_combo_box_get_model (combo_box), &iter,
658                           PRINTER_LIST_COL_PRINTER, &printer, -1);
659
660       if (printer == NULL || gtk_printer_has_details (printer))
661         fill_paper_sizes_from_printer (dialog, printer);
662       else
663         {
664           priv->request_details_printer = g_object_ref (printer);
665           priv->request_details_tag =
666             g_signal_connect (printer, "details-acquired",
667                               G_CALLBACK (printer_changed_finished_callback), dialog);
668           gtk_printer_request_details (printer);
669
670         }
671
672       if (printer)
673         g_object_unref (printer);
674
675       if (priv->print_settings)
676         {
677           const char *name = NULL;
678
679           if (printer)
680             name = gtk_printer_get_name (printer);
681           
682           gtk_print_settings_set (priv->print_settings,
683                                   "format-for-printer", name);
684         }
685     }
686 }
687
688 /* We do this munging because we don't want to show zero digits
689    after the decimal point, and not to many such digits if they
690    are nonzero. I wish printf let you specify max precision for %f... */
691 static gchar *
692 double_to_string (gdouble d, 
693                   GtkUnit unit)
694 {
695   gchar *val, *p;
696   struct lconv *locale_data;
697   const gchar *decimal_point;
698   gint decimal_point_len;
699
700   locale_data = localeconv ();
701   decimal_point = locale_data->decimal_point;
702   decimal_point_len = strlen (decimal_point);
703   
704   /* Max two decimal digits for inch, max one for mm */
705   if (unit == GTK_UNIT_INCH)
706     val = g_strdup_printf ("%.2f", d);
707   else
708     val = g_strdup_printf ("%.1f", d);
709
710   if (strstr (val, decimal_point))
711     {
712       p = val + strlen (val) - 1;
713       while (*p == '0')
714         p--;
715       if (p - val + 1 >= decimal_point_len &&
716           strncmp (p - (decimal_point_len - 1), decimal_point, decimal_point_len) == 0)
717         p -= decimal_point_len;
718       p[1] = '\0';
719     }
720
721   return val;
722 }
723
724
725 static void
726 custom_paper_dialog_response_cb (GtkDialog *custom_paper_dialog,
727                                  gint       response_id,
728                                  gpointer   user_data)
729 {
730   GtkPageSetupUnixDialog *page_setup_dialog = GTK_PAGE_SETUP_UNIX_DIALOG (user_data);
731   GtkPageSetupUnixDialogPrivate *priv = page_setup_dialog->priv;
732
733   _gtk_print_load_custom_papers (priv->custom_paper_list);
734
735   /* Update printer page list */
736   printer_changed_callback (GTK_COMBO_BOX (priv->printer_combo), page_setup_dialog);
737
738   gtk_widget_destroy (GTK_WIDGET (custom_paper_dialog));
739 }
740
741 static void
742 paper_size_changed (GtkComboBox            *combo_box,
743                     GtkPageSetupUnixDialog *dialog)
744 {
745   GtkPageSetupUnixDialogPrivate *priv = dialog->priv;
746   GtkTreeIter iter;
747   GtkPageSetup *page_setup, *last_page_setup;
748   GtkUnit unit;
749   gchar *str, *w, *h;
750   gchar *top, *bottom, *left, *right;
751   GtkLabel *label;
752   const gchar *unit_str;
753
754   label = GTK_LABEL (priv->paper_size_label);
755    
756   if (gtk_combo_box_get_active_iter (combo_box, &iter))
757     {
758       gtk_tree_model_get (gtk_combo_box_get_model (combo_box),
759                           &iter, PAGE_SETUP_LIST_COL_PAGE_SETUP, &page_setup, -1);
760
761       if (page_setup == NULL)
762         {
763           GtkWidget *custom_paper_dialog;
764
765           /* Change from "manage" menu item to last value */
766           if (priv->last_setup)
767             last_page_setup = g_object_ref (priv->last_setup);
768           else
769             last_page_setup = gtk_page_setup_new (); /* "good" default */
770           set_paper_size (dialog, last_page_setup, FALSE, TRUE);
771           g_object_unref (last_page_setup);
772
773           /* And show the custom paper dialog */
774           custom_paper_dialog = _gtk_custom_paper_unix_dialog_new (GTK_WINDOW (dialog), NULL);
775           g_signal_connect (custom_paper_dialog, "response", G_CALLBACK (custom_paper_dialog_response_cb), dialog);
776           gtk_window_present (GTK_WINDOW (custom_paper_dialog));
777
778           return;
779         }
780
781       if (priv->last_setup)
782         g_object_unref (priv->last_setup);
783
784       priv->last_setup = g_object_ref (page_setup);
785       
786       unit = _gtk_print_get_default_user_units ();
787
788       if (unit == GTK_UNIT_MM)
789         unit_str = _("mm");
790       else
791         unit_str = _("inch");
792         
793
794       w = double_to_string (gtk_page_setup_get_paper_width (page_setup, unit),
795                             unit);
796       h = double_to_string (gtk_page_setup_get_paper_height (page_setup, unit),
797                             unit);
798       str = g_strdup_printf ("%s x %s %s", w, h, unit_str);
799       g_free (w);
800       g_free (h);
801       
802       gtk_label_set_text (label, str);
803       g_free (str);
804
805       top = double_to_string (gtk_page_setup_get_top_margin (page_setup, unit), unit);
806       bottom = double_to_string (gtk_page_setup_get_bottom_margin (page_setup, unit), unit);
807       left = double_to_string (gtk_page_setup_get_left_margin (page_setup, unit), unit);
808       right = double_to_string (gtk_page_setup_get_right_margin (page_setup, unit), unit);
809
810       str = g_strdup_printf (_("Margins:\n"
811                                " Left: %s %s\n"
812                                " Right: %s %s\n"
813                                " Top: %s %s\n"
814                                " Bottom: %s %s"
815                                ),
816                              left, unit_str,
817                              right, unit_str,
818                              top, unit_str,
819                              bottom, unit_str);
820       g_free (top);
821       g_free (bottom);
822       g_free (left);
823       g_free (right);
824       
825       gtk_widget_set_tooltip_text (priv->paper_size_label, str);
826       g_free (str);
827       
828       g_object_unref (page_setup);
829     }
830   else
831     {
832       gtk_label_set_text (label, "");
833       gtk_widget_set_tooltip_text (priv->paper_size_label, NULL);
834       if (priv->last_setup)
835         g_object_unref (priv->last_setup);
836       priv->last_setup = NULL;
837     }
838 }
839
840 static void
841 page_name_func (GtkCellLayout   *cell_layout,
842                 GtkCellRenderer *cell,
843                 GtkTreeModel    *tree_model,
844                 GtkTreeIter     *iter,
845                 gpointer         data)
846 {
847   GtkPageSetup *page_setup;
848   GtkPaperSize *paper_size;
849   
850   gtk_tree_model_get (tree_model, iter,
851                       PAGE_SETUP_LIST_COL_PAGE_SETUP, &page_setup, -1);
852   if (page_setup)
853     {
854       paper_size = gtk_page_setup_get_paper_size (page_setup);
855       g_object_set (cell, "text",  gtk_paper_size_get_display_name (paper_size), NULL);
856       g_object_unref (page_setup);
857     }
858   else
859     g_object_set (cell, "text",  _("Manage Custom Sizes..."), NULL);
860       
861 }
862
863 static GtkWidget *
864 create_radio_button (GSList      *group,
865                      const gchar *stock_id)
866 {
867   GtkWidget *radio_button, *image, *label, *hbox;
868   GtkStockItem item;
869
870   radio_button = gtk_radio_button_new (group);
871   image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_LARGE_TOOLBAR);
872   gtk_stock_lookup (stock_id, &item);
873   label = gtk_label_new (item.label);
874   hbox = gtk_hbox_new (0, 6);
875   gtk_container_add (GTK_CONTAINER (radio_button), hbox);
876   gtk_container_add (GTK_CONTAINER (hbox), image);
877   gtk_container_add (GTK_CONTAINER (hbox), label);
878
879   gtk_widget_show_all (radio_button);
880
881   return radio_button;
882 }
883
884 static void
885 populate_dialog (GtkPageSetupUnixDialog *ps_dialog)
886 {
887   GtkPageSetupUnixDialogPrivate *priv = ps_dialog->priv;
888   GtkDialog *dialog = GTK_DIALOG (ps_dialog);
889   GtkWidget *table, *label, *combo, *radio_button;
890   GtkWidget *action_area, *content_area;
891   GtkCellRenderer *cell;
892
893   gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
894
895   content_area = gtk_dialog_get_content_area (dialog);
896   action_area = gtk_dialog_get_action_area (dialog);
897
898   gtk_dialog_set_has_separator (dialog, FALSE);
899   gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
900   gtk_box_set_spacing (GTK_BOX (content_area), 2); /* 2 * 5 + 2 = 12 */
901   gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
902   gtk_box_set_spacing (GTK_BOX (action_area), 6);
903
904   table = gtk_table_new (5, 4, FALSE);
905   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
906   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
907   gtk_container_set_border_width (GTK_CONTAINER (table), 5);
908   gtk_box_pack_start (GTK_BOX (content_area), table, TRUE, TRUE, 0);
909   gtk_widget_show (table);
910
911   label = gtk_label_new_with_mnemonic (_("_Format for:"));
912   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
913   gtk_table_attach (GTK_TABLE (table), label,
914                     0, 1, 0, 1,
915                     GTK_FILL, 0, 0, 0);
916   gtk_widget_show (label);
917
918   combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (priv->printer_list));
919   priv->printer_combo = combo;
920
921   cell = gtk_cell_renderer_text_new ();
922   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
923   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell,
924                                   "markup", PRINTER_LIST_COL_NAME,
925                                   NULL);
926
927   gtk_table_attach (GTK_TABLE (table), combo,
928                     1, 4, 0, 1,
929                     GTK_FILL | GTK_EXPAND, 0, 0, 0);
930   gtk_widget_show (combo);
931   gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
932
933   label = gtk_label_new_with_mnemonic (_("_Paper size:"));
934   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
935   gtk_table_attach (GTK_TABLE (table), label,
936                     0, 1, 1, 2,
937                     GTK_FILL, 0, 0, 0);
938   gtk_widget_show (label);
939
940   combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (priv->page_setup_list));
941   priv->paper_size_combo = combo;
942   gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo), 
943                                         paper_size_row_is_separator, NULL, NULL);
944   
945   cell = gtk_cell_renderer_text_new ();
946   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
947   gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo), cell,
948                                       page_name_func, NULL, NULL);
949
950   gtk_table_attach (GTK_TABLE (table), combo,
951                     1, 4, 1, 2,
952                     GTK_FILL | GTK_EXPAND, 0, 0, 0);
953   gtk_widget_show (combo);
954   gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
955
956   label = gtk_label_new (NULL);
957   priv->paper_size_label = label;
958   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
959   gtk_table_attach (GTK_TABLE (table), label,
960                     1, 4, 2, 3,
961                     GTK_FILL, 0, 0, 0);
962   gtk_widget_show (label);
963
964   label = gtk_label_new_with_mnemonic (_("_Orientation:"));
965   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
966   gtk_table_attach (GTK_TABLE (table), label,
967                     0, 1, 3, 4,
968                     GTK_FILL, 0, 0, 0);
969   gtk_widget_show (label);
970
971   radio_button = create_radio_button (NULL, GTK_STOCK_ORIENTATION_PORTRAIT);
972   priv->portrait_radio = radio_button;
973   gtk_table_attach (GTK_TABLE (table), radio_button,
974                     1, 2, 3, 4,
975                     GTK_EXPAND|GTK_FILL, 0, 0, 0);
976   gtk_label_set_mnemonic_widget (GTK_LABEL (label), radio_button);
977
978   radio_button = create_radio_button (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio_button)),
979                                       GTK_STOCK_ORIENTATION_REVERSE_PORTRAIT);
980   priv->reverse_portrait_radio = radio_button;
981   gtk_table_attach (GTK_TABLE (table), radio_button,
982                     2, 3, 3, 4,
983                     GTK_EXPAND|GTK_FILL, 0, 0, 0);
984
985   radio_button = create_radio_button (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio_button)),
986                                       GTK_STOCK_ORIENTATION_LANDSCAPE);
987   priv->landscape_radio = radio_button;
988   gtk_table_attach (GTK_TABLE (table), radio_button,
989                     1, 2, 4, 5,
990                     GTK_EXPAND|GTK_FILL, 0, 0, 0);
991   gtk_widget_show (radio_button);
992
993   gtk_table_set_row_spacing (GTK_TABLE (table), 3, 0);
994   
995   radio_button = create_radio_button (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio_button)),
996                                       GTK_STOCK_ORIENTATION_REVERSE_LANDSCAPE);
997   priv->reverse_landscape_radio = radio_button;
998   gtk_table_attach (GTK_TABLE (table), radio_button,
999                     2, 3, 4, 5,
1000                     GTK_EXPAND|GTK_FILL, 0, 0, 0);
1001
1002
1003   g_signal_connect (priv->paper_size_combo, "changed", G_CALLBACK (paper_size_changed), ps_dialog);
1004   g_signal_connect (priv->printer_combo, "changed", G_CALLBACK (printer_changed_callback), ps_dialog);
1005   gtk_combo_box_set_active (GTK_COMBO_BOX (priv->printer_combo), 0);
1006
1007   load_print_backends (ps_dialog);
1008 }
1009
1010 /**
1011  * gtk_page_setup_unix_dialog_new:
1012  * @title: (allow-none): the title of the dialog, or %NULL
1013  * @parent: (allow-none): transient parent of the dialog, or %NULL
1014  *
1015  * Creates a new page setup dialog.
1016  *
1017  * Returns: the new #GtkPageSetupUnixDialog
1018  *
1019  * Since: 2.10
1020  */
1021 GtkWidget *
1022 gtk_page_setup_unix_dialog_new (const gchar *title,
1023                                 GtkWindow   *parent)
1024 {
1025   GtkWidget *result;
1026
1027   if (title == NULL)
1028     title = _("Page Setup");
1029   
1030   result = g_object_new (GTK_TYPE_PAGE_SETUP_UNIX_DIALOG,
1031                          "title", title,
1032                          NULL);
1033
1034   if (parent)
1035     gtk_window_set_transient_for (GTK_WINDOW (result), parent);
1036
1037   return result;
1038 }
1039
1040 static GtkPageOrientation
1041 get_orientation (GtkPageSetupUnixDialog *dialog)
1042 {
1043   GtkPageSetupUnixDialogPrivate *priv = dialog->priv;
1044
1045   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->portrait_radio)))
1046     return GTK_PAGE_ORIENTATION_PORTRAIT;
1047   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->landscape_radio)))
1048     return GTK_PAGE_ORIENTATION_LANDSCAPE;
1049   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->reverse_landscape_radio)))
1050     return GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE;
1051   return GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT;
1052 }
1053
1054 static void
1055 set_orientation (GtkPageSetupUnixDialog *dialog, 
1056                  GtkPageOrientation      orientation)
1057 {
1058   GtkPageSetupUnixDialogPrivate *priv = dialog->priv;
1059
1060   switch (orientation)
1061     {
1062     case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
1063       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->reverse_portrait_radio), TRUE);
1064       break;
1065     case GTK_PAGE_ORIENTATION_PORTRAIT:
1066       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->portrait_radio), TRUE);
1067       break;
1068     case GTK_PAGE_ORIENTATION_LANDSCAPE:
1069       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->landscape_radio), TRUE);
1070       break;
1071     case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
1072       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->reverse_landscape_radio), TRUE);
1073       break;
1074     }
1075 }
1076
1077 /**
1078  * gtk_page_setup_unix_dialog_set_page_setup:
1079  * @dialog: a #GtkPageSetupUnixDialog
1080  * @page_setup: a #GtkPageSetup
1081  * 
1082  * Sets the #GtkPageSetup from which the page setup
1083  * dialog takes its values.
1084  *
1085  * Since: 2.10
1086  **/
1087 void
1088 gtk_page_setup_unix_dialog_set_page_setup (GtkPageSetupUnixDialog *dialog,
1089                                            GtkPageSetup           *page_setup)
1090 {
1091   if (page_setup)
1092     {
1093       set_paper_size (dialog, page_setup, FALSE, TRUE);
1094       set_orientation (dialog, gtk_page_setup_get_orientation (page_setup));
1095     }
1096 }
1097
1098 /**
1099  * gtk_page_setup_unix_dialog_get_page_setup:
1100  * @dialog: a #GtkPageSetupUnixDialog
1101  * 
1102  * Gets the currently selected page setup from the dialog. 
1103  * 
1104  * Returns: the current page setup 
1105  *
1106  * Since: 2.10
1107  **/
1108 GtkPageSetup *
1109 gtk_page_setup_unix_dialog_get_page_setup (GtkPageSetupUnixDialog *dialog)
1110 {
1111   GtkPageSetup *page_setup;
1112   
1113   page_setup = get_current_page_setup (dialog);
1114
1115   gtk_page_setup_set_orientation (page_setup, get_orientation (dialog));
1116
1117   return page_setup;
1118 }
1119
1120 static gboolean
1121 set_active_printer (GtkPageSetupUnixDialog *dialog,
1122                     const gchar            *printer_name)
1123 {
1124   GtkPageSetupUnixDialogPrivate *priv = dialog->priv;
1125   GtkTreeModel *model;
1126   GtkTreeIter iter;
1127   GtkPrinter *printer;
1128
1129   model = GTK_TREE_MODEL (priv->printer_list);
1130
1131   if (gtk_tree_model_get_iter_first (model, &iter))
1132     {
1133       do
1134         {
1135           gtk_tree_model_get (GTK_TREE_MODEL (priv->printer_list), &iter,
1136                               PRINTER_LIST_COL_PRINTER, &printer, -1);
1137           if (printer == NULL)
1138             continue;
1139           
1140           if (strcmp (gtk_printer_get_name (printer), printer_name) == 0)
1141             {
1142               gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->printer_combo),
1143                                              &iter);
1144               g_object_unref (printer);
1145               return TRUE;
1146             }
1147               
1148           g_object_unref (printer);
1149           
1150         } while (gtk_tree_model_iter_next (model, &iter));
1151     }
1152   
1153   return FALSE;
1154 }
1155
1156 /**
1157  * gtk_page_setup_unix_dialog_set_print_settings:
1158  * @dialog: a #GtkPageSetupUnixDialog
1159  * @print_settings: a #GtkPrintSettings
1160  * 
1161  * Sets the #GtkPrintSettings from which the page setup dialog
1162  * takes its values.
1163  * 
1164  * Since: 2.10
1165  **/
1166 void
1167 gtk_page_setup_unix_dialog_set_print_settings (GtkPageSetupUnixDialog *dialog,
1168                                                GtkPrintSettings       *print_settings)
1169 {
1170   GtkPageSetupUnixDialogPrivate *priv = dialog->priv;
1171   const gchar *format_for_printer;
1172
1173   if (priv->print_settings == print_settings) return;
1174
1175   if (priv->print_settings)
1176     g_object_unref (priv->print_settings);
1177
1178   priv->print_settings = print_settings;
1179
1180   if (print_settings)
1181     {
1182       g_object_ref (print_settings);
1183
1184       format_for_printer = gtk_print_settings_get (print_settings, "format-for-printer");
1185
1186       /* Set printer if in list, otherwise set when 
1187        * that printer is added 
1188        */
1189       if (format_for_printer &&
1190           !set_active_printer (dialog, format_for_printer))
1191         priv->waiting_for_printer = g_strdup (format_for_printer); 
1192     }
1193 }
1194
1195 /**
1196  * gtk_page_setup_unix_dialog_get_print_settings:
1197  * @dialog: a #GtkPageSetupUnixDialog
1198  * 
1199  * Gets the current print settings from the dialog.
1200  * 
1201  * Returns: the current print settings
1202  *
1203  * Since: 2.10
1204  **/
1205 GtkPrintSettings *
1206 gtk_page_setup_unix_dialog_get_print_settings (GtkPageSetupUnixDialog *dialog)
1207 {
1208   GtkPageSetupUnixDialogPrivate *priv = dialog->priv;
1209
1210   return priv->print_settings;
1211 }