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