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