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