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