]> Pileus Git - ~andy/gtk/blob - gtk/gtkpapersize.c
Rename GdkQuartzWindow.h and .c to GdkQuartzNSWindow.h and .c
[~andy/gtk] / gtk / gtkpapersize.c
1 /* GTK - The GIMP Toolkit
2  * gtkpapersize.c: Paper Size
3  * Copyright (C) 2006, Red Hat, Inc.
4  * Copyright © 2006, 2007 Christian Persch
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include "config.h"
23 #include <string.h>
24 #include <stdlib.h>
25 #include <locale.h>
26 #if defined(HAVE__NL_PAPER_HEIGHT) && defined(HAVE__NL_PAPER_WIDTH)
27 #include <langinfo.h>
28 #endif
29
30 #include "gtkpapersize.h"
31 #include "gtkprintutils.h"
32 #include "gtkprintoperation.h"  /* for GtkPrintError */
33 #include "gtkintl.h"
34
35 #include "paper_names_offsets.c"
36
37
38 /**
39  * SECTION:gtkpapersize
40  * @Short_description: Support for named paper sizes
41  * @Title: GtkPaperSize
42  * @See_also:#GtkPageSetup
43  *
44  * GtkPaperSize handles paper sizes. It uses the standard called
45  * <ulink url="http://www.pwg.org/standards.html">"PWG 5101.1-2002 PWG: Standard for Media Standardized Names"</ulink>
46  * to name the paper sizes (and to get the data for the page sizes).
47  * In addition to standard paper sizes, GtkPaperSize allows to
48  * construct custom paper sizes with arbitrary dimensions.
49  *
50  * The #GtkPaperSize object stores not only the dimensions (width
51  * and height) of a paper size and its name, it also provides
52  * default <link linkend="print-margins">print margins</link>.
53  *
54  * Printing support has been added in GTK+ 2.10.
55  */
56
57
58 struct _GtkPaperSize
59 {
60   const PaperInfo *info;
61
62   /* If these are not set we fall back to info */
63   gchar *name;
64   gchar *display_name;
65   gchar *ppd_name;
66   
67   gdouble width, height; /* Stored in mm */
68   gboolean is_custom;
69 };
70
71 G_DEFINE_BOXED_TYPE (GtkPaperSize, gtk_paper_size,
72                      gtk_paper_size_copy,
73                      gtk_paper_size_free)
74
75 static const PaperInfo *
76 lookup_paper_info (const gchar *name)
77 {
78   int lower = 0;
79   int upper = G_N_ELEMENTS (standard_names_offsets) - 1;
80   int mid;
81   int cmp;
82
83   do 
84     {
85        mid = (lower + upper) / 2;
86        cmp = strcmp (name, paper_names + standard_names_offsets[mid].name);
87        if (cmp < 0)
88          upper = mid - 1;
89        else if (cmp > 0)
90          lower = mid + 1;
91        else
92          return &standard_names_offsets[mid];
93     }
94   while (lower <= upper);
95
96   return NULL;
97 }
98
99 static gboolean
100 parse_media_size (const gchar *size,
101                   gdouble     *width_mm, 
102                   gdouble     *height_mm)
103 {
104   const char *p;
105   char *e;
106   double short_dim, long_dim;
107
108   p = size;
109   
110   short_dim = g_ascii_strtod (p, &e);
111
112   if (p == e || *e != 'x')
113     return FALSE;
114
115   p = e + 1; /* Skip x */
116
117   long_dim = g_ascii_strtod (p, &e);
118
119   if (p == e)
120     return FALSE;
121
122   p = e;
123
124   if (strcmp (p, "in") == 0)
125     {
126       short_dim = short_dim * MM_PER_INCH;
127       long_dim = long_dim * MM_PER_INCH;
128     }
129   else if (strcmp (p, "mm") != 0)
130     return FALSE;
131
132   if (width_mm)
133     *width_mm = short_dim;
134   if (height_mm)
135     *height_mm = long_dim;
136   
137   return TRUE;  
138 }
139
140 static gboolean
141 parse_full_media_size_name (const gchar  *full_name,
142                             gchar       **name,
143                             gdouble      *width_mm, 
144                             gdouble      *height_mm)
145 {
146   const char *p;
147   const char *end_of_name;
148   
149   /* From the spec:
150    media-size-self-describing-name =
151         ( class-in "_" size-name "_" short-dim "x" long-dim "in" ) |
152         ( class-mm "_" size-name "_" short-dim "x" long-dim "mm" )
153    class-in = "custom" | "na" | "asme" | "roc" | "oe"
154    class-mm = "custom" | "iso" | "jis" | "jpn" | "prc" | "om"
155    size-name = ( lowalpha | digit ) *( lowalpha | digit | "-" )
156    short-dim = dim
157    long-dim = dim
158    dim = integer-part [fraction-part] | "0" fraction-part
159    integer-part = non-zero-digit *digit
160    fraction-part = "." *digit non-zero-digit
161    lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
162               "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
163               "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
164    non-zero-digit = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
165    digit    = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
166  */
167
168   p = strchr (full_name, '_');
169   if (p == NULL)
170     return FALSE;
171
172   p++; /* Skip _ */
173   
174   p = strchr (p, '_');
175   if (p == NULL)
176     return FALSE;
177
178   end_of_name = p;
179
180   p++; /* Skip _ */
181
182   if (!parse_media_size (p, width_mm, height_mm))
183     return FALSE;
184
185   if (name)
186     *name = g_strndup (full_name, end_of_name - full_name);
187   
188   return TRUE;  
189 }
190
191 static GtkPaperSize *
192 gtk_paper_size_new_from_info (const PaperInfo *info)
193 {
194   GtkPaperSize *size;
195   
196   size = g_slice_new0 (GtkPaperSize);
197   size->info = info;
198   size->width = info->width;
199   size->height = info->height;
200   
201   return size;
202 }
203
204 /**
205  * gtk_paper_size_new:
206  * @name: (allow-none): a paper size name, or %NULL
207  *
208  * Creates a new #GtkPaperSize object by parsing a
209  * <ulink url="ftp://ftp.pwg.org/pub/pwg/candidates/cs-pwgmsn10-20020226-5101.1.pdf">PWG 5101.1-2002</ulink>
210  * paper name.
211  *
212  * If @name is %NULL, the default paper size is returned,
213  * see gtk_paper_size_get_default().
214  * 
215  * Return value: a new #GtkPaperSize, use gtk_paper_size_free()
216  * to free it
217  *
218  * Since: 2.10
219  */
220 GtkPaperSize *
221 gtk_paper_size_new (const gchar *name)
222 {
223   GtkPaperSize *size;
224   char *short_name;
225   double width, height;
226   const PaperInfo *info;
227
228   if (name == NULL)
229     name = gtk_paper_size_get_default ();
230   
231   if (parse_full_media_size_name (name, &short_name, &width, &height))
232     {
233       size = g_slice_new0 (GtkPaperSize);
234
235       size->width = width;
236       size->height = height;
237       size->name = short_name;
238       size->display_name = g_strdup (short_name);
239       if (strncmp (short_name, "custom", 6) == 0)
240         size->is_custom = TRUE;
241     }
242   else
243     {
244       info = lookup_paper_info (name);
245       if (info != NULL)
246         size = gtk_paper_size_new_from_info (info);
247       else
248         {
249           g_warning ("Unknown paper size %s\n", name);
250           size = g_slice_new0 (GtkPaperSize);
251           size->name = g_strdup (name);
252           size->display_name = g_strdup (name);
253           /* Default to A4 size */
254           size->width = 210;
255           size->height = 297;
256         }
257     }
258   
259   return size;
260 }
261
262 /**
263  * gtk_paper_size_new_from_ppd:
264  * @ppd_name: a PPD paper name
265  * @ppd_display_name: the corresponding human-readable name
266  * @width: the paper width, in points
267  * @height: the paper height in points
268  * 
269  * Creates a new #GtkPaperSize object by using 
270  * PPD information. 
271  * 
272  * If @ppd_name is not a recognized PPD paper name, 
273  * @ppd_display_name, @width and @height are used to 
274  * construct a custom #GtkPaperSize object.
275  *
276  * Return value: a new #GtkPaperSize, use gtk_paper_size_free()
277  * to free it
278  *
279  * Since: 2.10
280  */
281 GtkPaperSize *
282 gtk_paper_size_new_from_ppd (const gchar *ppd_name,
283                              const gchar *ppd_display_name,
284                              gdouble      width,
285                              gdouble      height)
286 {
287   char *name;
288   const char *lookup_ppd_name;
289   char *freeme;
290   GtkPaperSize *size;
291   int i;
292
293   lookup_ppd_name = ppd_name;
294   
295   freeme = NULL;
296   /* Strip out Traverse suffix in matching. */
297   if (g_str_has_suffix (ppd_name, ".Transverse"))
298     {
299       lookup_ppd_name = freeme =
300         g_strndup (ppd_name, strlen (ppd_name) - strlen (".Transverse"));
301     }
302   
303   for (i = 0; i < G_N_ELEMENTS(standard_names_offsets); i++)
304     {
305       if (standard_names_offsets[i].ppd_name != -1 &&
306           strcmp (paper_names + standard_names_offsets[i].ppd_name, lookup_ppd_name) == 0)
307         {
308           size = gtk_paper_size_new_from_info (&standard_names_offsets[i]);
309           goto out;
310         }
311     }
312   
313   for (i = 0; i < G_N_ELEMENTS(extra_ppd_names_offsets); i++)
314     {
315       if (strcmp (paper_names + extra_ppd_names_offsets[i].ppd_name, lookup_ppd_name) == 0)
316         {
317           size = gtk_paper_size_new (paper_names + extra_ppd_names_offsets[i].standard_name);
318           goto out;
319         }
320     }
321
322   name = g_strconcat ("ppd_", ppd_name, NULL);
323   size = gtk_paper_size_new_custom (name, ppd_display_name, width, height, GTK_UNIT_POINTS);
324   g_free (name);
325
326  out:
327
328   if (size->info == NULL ||
329       size->info->ppd_name == -1 ||
330       strcmp (paper_names + size->info->ppd_name, ppd_name) != 0)
331     size->ppd_name = g_strdup (ppd_name);
332   
333   g_free (freeme);
334   
335   return size;
336 }
337
338 /**
339  * gtk_paper_size_new_custom:
340  * @name: the paper name 
341  * @display_name: the human-readable name
342  * @width: the paper width, in units of @unit
343  * @height: the paper height, in units of @unit
344  * @unit: the unit for @width and @height
345  * 
346  * Creates a new #GtkPaperSize object with the
347  * given parameters.
348  * 
349  * Return value: a new #GtkPaperSize object, use gtk_paper_size_free()
350  * to free it
351  *
352  * Since: 2.10
353  */
354 GtkPaperSize *
355 gtk_paper_size_new_custom (const gchar *name, 
356                            const gchar *display_name,
357                            gdouble      width, 
358                            gdouble      height, 
359                            GtkUnit      unit)
360 {
361   GtkPaperSize *size;
362   g_return_val_if_fail (name != NULL, NULL);
363   g_return_val_if_fail (unit != GTK_UNIT_PIXEL, NULL);
364
365   size = g_slice_new0 (GtkPaperSize);
366   
367   size->name = g_strdup (name);
368   size->display_name = g_strdup (display_name);
369   size->is_custom = TRUE;
370   
371   size->width = _gtk_print_convert_to_mm (width, unit);
372   size->height = _gtk_print_convert_to_mm (height, unit);
373   
374   return size;
375 }
376
377 /**
378  * gtk_paper_size_copy:
379  * @other: a #GtkPaperSize
380  * 
381  * Copies an existing #GtkPaperSize.
382  * 
383  * Return value: a copy of @other
384  *
385  * Since: 2.10
386  */
387 GtkPaperSize *
388 gtk_paper_size_copy (GtkPaperSize *other)
389 {
390   GtkPaperSize *size;
391
392   size = g_slice_new0 (GtkPaperSize);
393
394   size->info = other->info;
395   if (other->name)
396     size->name = g_strdup (other->name);
397   if (other->display_name)
398     size->display_name = g_strdup (other->display_name);
399   if (other->ppd_name)
400     size->ppd_name = g_strdup (other->ppd_name);
401   
402   size->width = other->width;
403   size->height = other->height;
404   size->is_custom = other->is_custom;
405
406   return size;
407 }
408
409 /**
410  * gtk_paper_size_free:
411  * @size: a #GtkPaperSize
412  * 
413  * Free the given #GtkPaperSize object.
414  *
415  * Since: 2.10
416  */
417 void
418 gtk_paper_size_free (GtkPaperSize *size)
419 {
420   g_free (size->name);
421   g_free (size->display_name);
422   g_free (size->ppd_name);
423
424   g_slice_free (GtkPaperSize, size);
425 }
426
427 /**
428  * gtk_paper_size_is_equal:
429  * @size1: a #GtkPaperSize object
430  * @size2: another #GtkPaperSize object
431  * 
432  * Compares two #GtkPaperSize objects.
433  * 
434  * Return value: %TRUE, if @size1 and @size2 
435  * represent the same paper size
436  *
437  * Since: 2.10
438  */
439 gboolean
440 gtk_paper_size_is_equal (GtkPaperSize *size1,
441                          GtkPaperSize *size2)
442 {
443   if (size1->info != NULL && size2->info != NULL)
444     return size1->info == size2->info;
445   
446   return strcmp (gtk_paper_size_get_name (size1),
447                  gtk_paper_size_get_name (size2)) == 0;
448 }
449
450 GList * _gtk_load_custom_papers (void);
451
452 /**
453  * gtk_paper_size_get_paper_sizes:
454  * @include_custom: whether to include custom paper sizes
455  *     as defined in the page setup dialog
456  *
457  * Creates a list of known paper sizes.
458  *
459  * Return value:  (element-type GtkPaperSize) (transfer full): a newly allocated list of newly
460  *    allocated #GtkPaperSize objects
461  *
462  * Since: 2.12
463  */
464 GList *
465 gtk_paper_size_get_paper_sizes (gboolean include_custom)
466 {
467   GList *list = NULL;
468   guint i;
469 #ifdef G_OS_UNIX                /* _gtk_load_custom_papers() only on Unix so far  */
470   if (include_custom)
471     {
472       GList *page_setups, *l;
473
474       page_setups = _gtk_load_custom_papers ();
475       for (l = page_setups; l != NULL; l = l->next)
476         {
477           GtkPageSetup *setup = (GtkPageSetup *) l->data;
478           GtkPaperSize *size;
479
480           size = gtk_page_setup_get_paper_size (setup);
481           list = g_list_prepend (list, gtk_paper_size_copy (size));
482         }
483
484       g_list_foreach (page_setups, (GFunc) g_object_unref, NULL);
485       g_list_free (page_setups);
486     }
487 #endif
488   for (i = 0; i < G_N_ELEMENTS (standard_names_offsets); ++i)
489     {
490        GtkPaperSize *size;
491
492        size = gtk_paper_size_new_from_info (&standard_names_offsets[i]);
493        list = g_list_prepend (list, size);
494     }
495
496   return g_list_reverse (list);
497 }
498
499
500 /**
501  * gtk_paper_size_get_name:
502  * @size: a #GtkPaperSize object
503  * 
504  * Gets the name of the #GtkPaperSize.
505  * 
506  * Return value: the name of @size
507  *
508  * Since: 2.10
509  */
510 G_CONST_RETURN gchar *
511 gtk_paper_size_get_name (GtkPaperSize *size)
512 {
513   if (size->name)
514     return size->name;
515   g_assert (size->info != NULL);
516   return paper_names + size->info->name;
517 }
518
519 /**
520  * gtk_paper_size_get_display_name:
521  * @size: a #GtkPaperSize object
522  * 
523  * Gets the human-readable name of the #GtkPaperSize.
524  * 
525  * Return value: the human-readable name of @size
526  *
527  * Since: 2.10
528  */
529 G_CONST_RETURN gchar *
530 gtk_paper_size_get_display_name (GtkPaperSize *size)
531 {
532   const gchar *display_name;
533
534   if (size->display_name)
535     return size->display_name;
536
537   g_assert (size->info != NULL);
538
539   display_name = paper_names + size->info->display_name;
540   return g_dpgettext2 (GETTEXT_PACKAGE, "paper size", display_name);
541 }
542
543 /**
544  * gtk_paper_size_get_ppd_name:
545  * @size: a #GtkPaperSize object
546  * 
547  * Gets the PPD name of the #GtkPaperSize, which
548  * may be %NULL.
549  * 
550  * Return value: the PPD name of @size
551  *
552  * Since: 2.10
553  */
554 G_CONST_RETURN gchar *
555 gtk_paper_size_get_ppd_name (GtkPaperSize *size)
556 {
557   if (size->ppd_name)
558     return size->ppd_name;
559   if (size->info)
560     return paper_names + size->info->ppd_name;
561   return NULL;
562 }
563
564 /**
565  * gtk_paper_size_get_width:
566  * @size: a #GtkPaperSize object
567  * @unit: the unit for the return value
568  * 
569  * Gets the paper width of the #GtkPaperSize, in 
570  * units of @unit.
571  * 
572  * Return value: the paper width 
573  *
574  * Since: 2.10
575  */
576 gdouble
577 gtk_paper_size_get_width (GtkPaperSize *size, 
578                           GtkUnit       unit)
579 {
580   return _gtk_print_convert_from_mm (size->width, unit);
581 }
582
583 /**
584  * gtk_paper_size_get_height:
585  * @size: a #GtkPaperSize object
586  * @unit: the unit for the return value
587  * 
588  * Gets the paper height of the #GtkPaperSize, in 
589  * units of @unit.
590  * 
591  * Return value: the paper height 
592  *
593  * Since: 2.10
594  */
595 gdouble
596 gtk_paper_size_get_height (GtkPaperSize *size, 
597                            GtkUnit       unit)
598 {
599   return _gtk_print_convert_from_mm (size->height, unit);
600 }
601
602 /**
603  * gtk_paper_size_is_custom:
604  * @size: a #GtkPaperSize object
605  * 
606  * Returns %TRUE if @size is not a standard paper size.
607  * 
608  * Return value: whether @size is a custom paper size.
609  **/
610 gboolean
611 gtk_paper_size_is_custom (GtkPaperSize *size)
612 {
613   return size->is_custom;
614 }
615
616 /**
617  * gtk_paper_size_set_size:
618  * @size: a custom #GtkPaperSize object
619  * @width: the new width in units of @unit
620  * @height: the new height in units of @unit
621  * @unit: the unit for @width and @height
622  * 
623  * Changes the dimensions of a @size to @width x @height.
624  *
625  * Since: 2.10
626  */
627 void
628 gtk_paper_size_set_size (GtkPaperSize *size, 
629                          gdouble       width, 
630                          gdouble       height, 
631                          GtkUnit       unit)
632 {
633   g_return_if_fail (size != NULL);
634   g_return_if_fail (size->is_custom);
635
636   size->width = _gtk_print_convert_to_mm (width, unit);
637   size->height = _gtk_print_convert_to_mm (height, unit);
638 }
639
640 #define NL_PAPER_GET(x)         \
641   ((union { char *string; unsigned int word; })nl_langinfo(x)).word
642
643 /**
644  * gtk_paper_size_get_default:
645  *
646  * Returns the name of the default paper size, which 
647  * depends on the current locale.  
648  * 
649  * Return value: the name of the default paper size. The string
650  * is owned by GTK+ and should not be modified.
651  * 
652  * Since: 2.10
653  */
654 G_CONST_RETURN gchar *
655 gtk_paper_size_get_default (void)
656 {
657   char *locale, *freeme = NULL;
658   const char *paper_size;
659
660 #if defined(HAVE__NL_PAPER_HEIGHT) && defined(HAVE__NL_PAPER_WIDTH)
661   {
662     int width = NL_PAPER_GET (_NL_PAPER_WIDTH);
663     int height = NL_PAPER_GET (_NL_PAPER_HEIGHT);
664     
665     if (width == 210 && height == 297)
666       return GTK_PAPER_NAME_A4;
667     
668     if (width == 216 && height == 279)
669       return GTK_PAPER_NAME_LETTER;
670   }
671 #endif
672
673 #ifdef G_OS_WIN32
674   freeme = locale = g_win32_getlocale ();
675 #elif defined(LC_PAPER)
676   locale = setlocale(LC_PAPER, NULL);
677 #else
678   locale = setlocale(LC_MESSAGES, NULL);
679 #endif
680
681   if (!locale)
682     return GTK_PAPER_NAME_A4;
683
684   /* CLDR 1.8.1
685    * http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/territory_language_information.html
686    */
687   if (g_regex_match_simple("[^_.@]{2,3}_(BZ|CA|CL|CO|CR|GT|MX|NI|PA|PH|PR|SV|US|VE)",
688                            locale, G_REGEX_ANCHORED, G_REGEX_MATCH_ANCHORED))
689     paper_size = GTK_PAPER_NAME_LETTER;
690   else
691     paper_size = GTK_PAPER_NAME_A4;
692
693   g_free (freeme);
694   return paper_size;
695 }
696
697 /* These get the default margins used for the paper size. Its
698  * larger than most printers margins, so that it will be within
699  * the imageble area on any printer.
700  *
701  * I've taken the actual values used from the OSX page setup dialog.
702  * I'm not sure exactly where they got these values for, but might
703  * correspond to this (from ghostscript docs):
704  * 
705  * All DeskJets have 0.5 inches (1.27cm) of unprintable bottom margin,
706  * due to the mechanical arrangement used to grab the paper. Side margins
707  * are approximately 0.25 inches (0.64cm) for U.S. letter paper, and 0.15
708  * inches (0.38cm) for A4.
709  */
710
711 /**
712  * gtk_paper_size_get_default_top_margin:
713  * @size: a #GtkPaperSize object
714  * @unit: the unit for the return value
715  * 
716  * Gets the default top margin for the #GtkPaperSize.
717  * 
718  * Return value: the default top margin
719  *
720  * Since: 2.10
721  */
722 gdouble
723 gtk_paper_size_get_default_top_margin (GtkPaperSize *size, 
724                                        GtkUnit       unit)
725 {
726   gdouble margin;
727
728   margin = _gtk_print_convert_to_mm (0.25, GTK_UNIT_INCH);
729   return _gtk_print_convert_from_mm (margin, unit);
730 }
731
732 /**
733  * gtk_paper_size_get_default_bottom_margin:
734  * @size: a #GtkPaperSize object
735  * @unit: the unit for the return value
736  * 
737  * Gets the default bottom margin for the #GtkPaperSize.
738  * 
739  * Return value: the default bottom margin
740  *
741  * Since: 2.10
742  */
743 gdouble
744 gtk_paper_size_get_default_bottom_margin (GtkPaperSize *size, 
745                                           GtkUnit       unit)
746 {
747   gdouble margin;
748   const gchar *name;
749
750   margin = _gtk_print_convert_to_mm (0.25, GTK_UNIT_INCH);
751
752   name = gtk_paper_size_get_name (size);
753   if (strcmp (name, "na_letter") == 0 ||
754       strcmp (name, "na_legal") == 0 ||
755       strcmp (name, "iso_a4") == 0)
756     margin = _gtk_print_convert_to_mm (0.56, GTK_UNIT_INCH);
757   
758   return _gtk_print_convert_from_mm (margin, unit);
759 }
760
761 /**
762  * gtk_paper_size_get_default_left_margin:
763  * @size: a #GtkPaperSize object
764  * @unit: the unit for the return value
765  * 
766  * Gets the default left margin for the #GtkPaperSize.
767  * 
768  * Return value: the default left margin
769  *
770  * Since: 2.10
771  */
772 gdouble
773 gtk_paper_size_get_default_left_margin (GtkPaperSize *size, 
774                                         GtkUnit       unit)
775 {
776   gdouble margin;
777
778   margin = _gtk_print_convert_to_mm (0.25, GTK_UNIT_INCH);
779   return _gtk_print_convert_from_mm (margin, unit);
780 }
781
782 /**
783  * gtk_paper_size_get_default_right_margin:
784  * @size: a #GtkPaperSize object
785  * @unit: the unit for the return value
786  * 
787  * Gets the default right margin for the #GtkPaperSize.
788  * 
789  * Return value: the default right margin
790  *
791  * Since: 2.10
792  */
793 gdouble
794 gtk_paper_size_get_default_right_margin (GtkPaperSize *size, 
795                                          GtkUnit       unit)
796 {
797   gdouble margin;
798
799   margin = _gtk_print_convert_to_mm (0.25, GTK_UNIT_INCH);
800   return _gtk_print_convert_from_mm (margin, unit);
801 }
802
803 /**
804  * gtk_paper_size_new_from_key_file:
805  * @key_file: the #GKeyFile to retrieve the papersize from
806  * @group_name: the name ofthe group in the key file to read,
807  *     or %NULL to read the first group
808  * @error: (allow-none): return location for an error, or %NULL
809  *
810  * Reads a paper size from the group @group_name in the key file
811  * @key_file. 
812  *
813  * Returns: a new #GtkPaperSize object with the restored
814  *          paper size, or %NULL if an error occurred.
815  *
816  * Since: 2.12
817  */
818 GtkPaperSize *
819 gtk_paper_size_new_from_key_file (GKeyFile    *key_file,
820                                   const gchar *group_name,
821                                   GError     **error)
822 {
823   GtkPaperSize *paper_size = NULL;
824   char *name = NULL, *ppd_name = NULL, *display_name = NULL, *freeme = NULL;
825   gdouble width, height;
826   gboolean retval = TRUE;
827   GError *err = NULL;
828
829   g_return_val_if_fail (key_file != NULL, NULL);
830
831   if (!group_name)
832     group_name = freeme = g_key_file_get_start_group (key_file);
833   if (!group_name || !g_key_file_has_group (key_file, group_name))
834     {
835       g_set_error_literal (error,
836                            GTK_PRINT_ERROR,
837                            GTK_PRINT_ERROR_INVALID_FILE,
838                            _("Not a valid page setup file"));
839       retval = FALSE;
840       goto out;
841     }
842
843 #define GET_DOUBLE(kf, group, name, v) \
844   v = g_key_file_get_double (kf, group, name, &err); \
845   if (err != NULL) \
846     {\
847       g_propagate_error (error, err);\
848       retval = FALSE;\
849       goto out;\
850     }
851
852   GET_DOUBLE (key_file, group_name, "Width", width);
853   GET_DOUBLE (key_file, group_name, "Height", height);
854
855 #undef GET_DOUBLE
856
857   name = g_key_file_get_string (key_file, group_name,
858                                 "Name", NULL);
859   ppd_name = g_key_file_get_string (key_file, group_name,
860                                     "PPDName", NULL);
861   display_name = g_key_file_get_string (key_file, group_name,
862                                         "DisplayName", NULL);
863   /* Fallback for old ~/.gtk-custom-paper entries */
864   if (!display_name)
865     display_name = g_strdup (name);
866
867   if (ppd_name != NULL)
868     paper_size = gtk_paper_size_new_from_ppd (ppd_name,
869                                               display_name,
870                                               _gtk_print_convert_from_mm (width, GTK_UNIT_POINTS),
871                                               _gtk_print_convert_from_mm (height, GTK_UNIT_POINTS));
872   else if (name != NULL)
873     paper_size = gtk_paper_size_new_custom (name, display_name,
874                                             width, height, GTK_UNIT_MM);
875   else
876     {
877       g_set_error_literal (error,
878                            GTK_PRINT_ERROR,
879                            GTK_PRINT_ERROR_INVALID_FILE,
880                            _("Not a valid page setup file"));
881       retval = FALSE;
882       goto out;
883     }
884   g_assert (paper_size != NULL);
885
886 out:
887   g_free (ppd_name);
888   g_free (name);
889   g_free (display_name);
890   g_free (freeme);
891
892   return paper_size;
893 }
894
895 /**
896  * gtk_paper_size_to_key_file:
897  * @size: a #GtkPaperSize
898  * @key_file: the #GKeyFile to save the paper size to
899  * @group_name: the group to add the settings to in @key_file
900  *
901  * This function adds the paper size from @size to @key_file.
902  *
903  * Since: 2.12
904  */
905 void
906 gtk_paper_size_to_key_file (GtkPaperSize *size,
907                             GKeyFile     *key_file,
908                             const gchar  *group_name)
909 {
910   const char *name, *ppd_name, *display_name;
911
912   g_return_if_fail (size != NULL);
913   g_return_if_fail (key_file != NULL);
914
915   name = gtk_paper_size_get_name (size);
916   display_name = gtk_paper_size_get_display_name (size);
917   ppd_name = gtk_paper_size_get_ppd_name (size);
918
919   if (ppd_name != NULL) 
920     g_key_file_set_string (key_file, group_name,
921                            "PPDName", ppd_name);
922   else
923     g_key_file_set_string (key_file, group_name,
924                            "Name", name);
925
926   if (display_name) 
927     g_key_file_set_string (key_file, group_name,
928                            "DisplayName", display_name);
929
930   g_key_file_set_double (key_file, group_name,
931                          "Width", gtk_paper_size_get_width (size, GTK_UNIT_MM));
932   g_key_file_set_double (key_file, group_name,
933                          "Height", gtk_paper_size_get_height (size, GTK_UNIT_MM));
934 }