1 /* GTK - The GIMP Toolkit
2 * gtkpapersize.c: Paper Size
3 * Copyright (C) 2006, Red Hat, Inc.
4 * Copyright © 2006, 2007 Christian Persch
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.
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.
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/>.
24 #if defined(HAVE__NL_PAPER_HEIGHT) && defined(HAVE__NL_PAPER_WIDTH)
28 #include "gtkpapersize.h"
29 #include "gtkprintutils.h"
30 #include "gtkprintoperation.h" /* for GtkPrintError */
33 #ifdef G_OS_UNIX /* _gtk_load_custom_papers() only on Unix so far */
34 #include "gtkcustompaperunixdialog.h"
37 #include "paper_names_offsets.c"
41 * SECTION:gtkpapersize
42 * @Short_description: Support for named paper sizes
43 * @Title: GtkPaperSize
44 * @See_also:#GtkPageSetup
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.
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>.
56 * Printing support has been added in GTK+ 2.10.
62 const PaperInfo *info;
64 /* If these are not set we fall back to info */
69 gdouble width, height; /* Stored in mm */
73 G_DEFINE_BOXED_TYPE (GtkPaperSize, gtk_paper_size,
77 static const PaperInfo *
78 lookup_paper_info (const gchar *name)
81 int upper = G_N_ELEMENTS (standard_names_offsets) - 1;
87 mid = (lower + upper) / 2;
88 cmp = strcmp (name, paper_names + standard_names_offsets[mid].name);
94 return &standard_names_offsets[mid];
96 while (lower <= upper);
102 parse_media_size (const gchar *size,
108 double short_dim, long_dim;
112 short_dim = g_ascii_strtod (p, &e);
114 if (p == e || *e != 'x')
117 p = e + 1; /* Skip x */
119 long_dim = g_ascii_strtod (p, &e);
126 if (strcmp (p, "in") == 0)
128 short_dim = short_dim * MM_PER_INCH;
129 long_dim = long_dim * MM_PER_INCH;
131 else if (strcmp (p, "mm") != 0)
135 *width_mm = short_dim;
137 *height_mm = long_dim;
143 parse_full_media_size_name (const gchar *full_name,
149 const char *end_of_name;
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 | "-" )
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"
170 p = strchr (full_name, '_');
184 if (!parse_media_size (p, width_mm, height_mm))
188 *name = g_strndup (full_name, end_of_name - full_name);
193 static GtkPaperSize *
194 gtk_paper_size_new_from_info (const PaperInfo *info)
198 size = g_slice_new0 (GtkPaperSize);
200 size->width = info->width;
201 size->height = info->height;
207 * gtk_paper_size_new:
208 * @name: (allow-none): a paper size name, or %NULL
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>
214 * If @name is %NULL, the default paper size is returned,
215 * see gtk_paper_size_get_default().
217 * Return value: a new #GtkPaperSize, use gtk_paper_size_free()
223 gtk_paper_size_new (const gchar *name)
227 double width, height;
228 const PaperInfo *info;
231 name = gtk_paper_size_get_default ();
233 if (parse_full_media_size_name (name, &short_name, &width, &height))
235 info = lookup_paper_info (short_name);
236 if (info != NULL && info->width == width && info->height == height)
238 size = gtk_paper_size_new_from_info (info);
243 size = g_slice_new0 (GtkPaperSize);
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;
255 info = lookup_paper_info (name);
257 size = gtk_paper_size_new_from_info (info);
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 */
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
280 * Creates a new #GtkPaperSize object by using
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.
287 * Return value: a new #GtkPaperSize, use gtk_paper_size_free()
293 gtk_paper_size_new_from_ppd (const gchar *ppd_name,
294 const gchar *ppd_display_name,
299 const char *lookup_ppd_name;
304 lookup_ppd_name = ppd_name;
307 /* Strip out Traverse suffix in matching. */
308 if (g_str_has_suffix (ppd_name, ".Transverse"))
310 lookup_ppd_name = freeme =
311 g_strndup (ppd_name, strlen (ppd_name) - strlen (".Transverse"));
314 for (i = 0; i < G_N_ELEMENTS(standard_names_offsets); i++)
316 if (standard_names_offsets[i].ppd_name != -1 &&
317 strcmp (paper_names + standard_names_offsets[i].ppd_name, lookup_ppd_name) == 0)
319 size = gtk_paper_size_new_from_info (&standard_names_offsets[i]);
324 for (i = 0; i < G_N_ELEMENTS(extra_ppd_names_offsets); i++)
326 if (strcmp (paper_names + extra_ppd_names_offsets[i].ppd_name, lookup_ppd_name) == 0)
328 size = gtk_paper_size_new (paper_names + extra_ppd_names_offsets[i].standard_name);
333 name = g_strconcat ("ppd_", ppd_name, NULL);
334 size = gtk_paper_size_new_custom (name, ppd_display_name, width, height, GTK_UNIT_POINTS);
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);
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.
357 * Creates a new #GtkPaperSize object with the
360 * Return value: a new #GtkPaperSize object, use gtk_paper_size_free()
366 gtk_paper_size_new_custom (const gchar *name,
367 const gchar *display_name,
373 g_return_val_if_fail (name != NULL, NULL);
374 g_return_val_if_fail (unit != GTK_UNIT_NONE, NULL);
376 size = g_slice_new0 (GtkPaperSize);
378 size->name = g_strdup (name);
379 size->display_name = g_strdup (display_name);
380 size->is_custom = TRUE;
382 size->width = _gtk_print_convert_to_mm (width, unit);
383 size->height = _gtk_print_convert_to_mm (height, unit);
389 * gtk_paper_size_copy:
390 * @other: a #GtkPaperSize
392 * Copies an existing #GtkPaperSize.
394 * Return value: a copy of @other
399 gtk_paper_size_copy (GtkPaperSize *other)
403 size = g_slice_new0 (GtkPaperSize);
405 size->info = other->info;
407 size->name = g_strdup (other->name);
408 if (other->display_name)
409 size->display_name = g_strdup (other->display_name);
411 size->ppd_name = g_strdup (other->ppd_name);
413 size->width = other->width;
414 size->height = other->height;
415 size->is_custom = other->is_custom;
421 * gtk_paper_size_free:
422 * @size: a #GtkPaperSize
424 * Free the given #GtkPaperSize object.
429 gtk_paper_size_free (GtkPaperSize *size)
432 g_free (size->display_name);
433 g_free (size->ppd_name);
435 g_slice_free (GtkPaperSize, size);
439 * gtk_paper_size_is_equal:
440 * @size1: a #GtkPaperSize object
441 * @size2: another #GtkPaperSize object
443 * Compares two #GtkPaperSize objects.
445 * Return value: %TRUE, if @size1 and @size2
446 * represent the same paper size
451 gtk_paper_size_is_equal (GtkPaperSize *size1,
454 if (size1->info != NULL && size2->info != NULL)
455 return size1->info == size2->info;
457 return strcmp (gtk_paper_size_get_name (size1),
458 gtk_paper_size_get_name (size2)) == 0;
462 * gtk_paper_size_get_paper_sizes:
463 * @include_custom: whether to include custom paper sizes
464 * as defined in the page setup dialog
466 * Creates a list of known paper sizes.
468 * Return value: (element-type GtkPaperSize) (transfer full): a newly allocated list of newly
469 * allocated #GtkPaperSize objects
474 gtk_paper_size_get_paper_sizes (gboolean include_custom)
478 #ifdef G_OS_UNIX /* _gtk_load_custom_papers() only on Unix so far */
481 GList *page_setups, *l;
483 page_setups = _gtk_load_custom_papers ();
484 for (l = page_setups; l != NULL; l = l->next)
486 GtkPageSetup *setup = (GtkPageSetup *) l->data;
489 size = gtk_page_setup_get_paper_size (setup);
490 list = g_list_prepend (list, gtk_paper_size_copy (size));
493 g_list_free_full (page_setups, g_object_unref);
496 for (i = 0; i < G_N_ELEMENTS (standard_names_offsets); ++i)
500 size = gtk_paper_size_new_from_info (&standard_names_offsets[i]);
501 list = g_list_prepend (list, size);
504 return g_list_reverse (list);
509 * gtk_paper_size_get_name:
510 * @size: a #GtkPaperSize object
512 * Gets the name of the #GtkPaperSize.
514 * Return value: the name of @size
519 gtk_paper_size_get_name (GtkPaperSize *size)
523 g_assert (size->info != NULL);
524 return paper_names + size->info->name;
528 * gtk_paper_size_get_display_name:
529 * @size: a #GtkPaperSize object
531 * Gets the human-readable name of the #GtkPaperSize.
533 * Return value: the human-readable name of @size
538 gtk_paper_size_get_display_name (GtkPaperSize *size)
540 const gchar *display_name;
542 if (size->display_name)
543 return size->display_name;
545 g_assert (size->info != NULL);
547 display_name = paper_names + size->info->display_name;
548 return g_dpgettext2 (GETTEXT_PACKAGE, "paper size", display_name);
552 * gtk_paper_size_get_ppd_name:
553 * @size: a #GtkPaperSize object
555 * Gets the PPD name of the #GtkPaperSize, which
558 * Return value: the PPD name of @size
563 gtk_paper_size_get_ppd_name (GtkPaperSize *size)
566 return size->ppd_name;
568 return paper_names + size->info->ppd_name;
573 * gtk_paper_size_get_width:
574 * @size: a #GtkPaperSize object
575 * @unit: the unit for the return value, not %GTK_UNIT_NONE
577 * Gets the paper width of the #GtkPaperSize, in
580 * Return value: the paper width
585 gtk_paper_size_get_width (GtkPaperSize *size,
588 return _gtk_print_convert_from_mm (size->width, unit);
592 * gtk_paper_size_get_height:
593 * @size: a #GtkPaperSize object
594 * @unit: the unit for the return value, not %GTK_UNIT_NONE
596 * Gets the paper height of the #GtkPaperSize, in
599 * Return value: the paper height
604 gtk_paper_size_get_height (GtkPaperSize *size,
607 return _gtk_print_convert_from_mm (size->height, unit);
611 * gtk_paper_size_is_custom:
612 * @size: a #GtkPaperSize object
614 * Returns %TRUE if @size is not a standard paper size.
616 * Return value: whether @size is a custom paper size.
619 gtk_paper_size_is_custom (GtkPaperSize *size)
621 return size->is_custom;
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
631 * Changes the dimensions of a @size to @width x @height.
636 gtk_paper_size_set_size (GtkPaperSize *size,
641 g_return_if_fail (size != NULL);
642 g_return_if_fail (size->is_custom);
644 size->width = _gtk_print_convert_to_mm (width, unit);
645 size->height = _gtk_print_convert_to_mm (height, unit);
648 #define NL_PAPER_GET(x) \
649 ((union { char *string; unsigned int word; })nl_langinfo(x)).word
652 * gtk_paper_size_get_default:
654 * Returns the name of the default paper size, which
655 * depends on the current locale.
657 * Return value: the name of the default paper size. The string
658 * is owned by GTK+ and should not be modified.
663 gtk_paper_size_get_default (void)
665 char *locale, *freeme = NULL;
666 const char *paper_size;
668 #if defined(HAVE__NL_PAPER_HEIGHT) && defined(HAVE__NL_PAPER_WIDTH)
670 int width = NL_PAPER_GET (_NL_PAPER_WIDTH);
671 int height = NL_PAPER_GET (_NL_PAPER_HEIGHT);
673 if (width == 210 && height == 297)
674 return GTK_PAPER_NAME_A4;
676 if (width == 216 && height == 279)
677 return GTK_PAPER_NAME_LETTER;
682 freeme = locale = g_win32_getlocale ();
683 #elif defined(LC_PAPER)
684 locale = setlocale(LC_PAPER, NULL);
686 locale = setlocale(LC_MESSAGES, NULL);
690 return GTK_PAPER_NAME_A4;
693 * http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/territory_language_information.html
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;
699 paper_size = GTK_PAPER_NAME_A4;
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.
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):
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.
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
724 * Gets the default top margin for the #GtkPaperSize.
726 * Return value: the default top margin
731 gtk_paper_size_get_default_top_margin (GtkPaperSize *size,
736 margin = _gtk_print_convert_to_mm (0.25, GTK_UNIT_INCH);
737 return _gtk_print_convert_from_mm (margin, unit);
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
745 * Gets the default bottom margin for the #GtkPaperSize.
747 * Return value: the default bottom margin
752 gtk_paper_size_get_default_bottom_margin (GtkPaperSize *size,
758 margin = _gtk_print_convert_to_mm (0.25, GTK_UNIT_INCH);
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);
766 return _gtk_print_convert_from_mm (margin, unit);
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
774 * Gets the default left margin for the #GtkPaperSize.
776 * Return value: the default left margin
781 gtk_paper_size_get_default_left_margin (GtkPaperSize *size,
786 margin = _gtk_print_convert_to_mm (0.25, GTK_UNIT_INCH);
787 return _gtk_print_convert_from_mm (margin, unit);
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
795 * Gets the default right margin for the #GtkPaperSize.
797 * Return value: the default right margin
802 gtk_paper_size_get_default_right_margin (GtkPaperSize *size,
807 margin = _gtk_print_convert_to_mm (0.25, GTK_UNIT_INCH);
808 return _gtk_print_convert_from_mm (margin, unit);
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
818 * Reads a paper size from the group @group_name in the key file
821 * Returns: a new #GtkPaperSize object with the restored
822 * paper size, or %NULL if an error occurred
827 gtk_paper_size_new_from_key_file (GKeyFile *key_file,
828 const gchar *group_name,
831 GtkPaperSize *paper_size = NULL;
833 gchar *ppd_name = NULL;
834 gchar *display_name = NULL;
835 gchar *freeme = NULL;
836 gdouble width, height;
839 g_return_val_if_fail (key_file != NULL, NULL);
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))
845 g_set_error_literal (error,
847 GTK_PRINT_ERROR_INVALID_FILE,
848 _("Not a valid page setup file"));
852 #define GET_DOUBLE(kf, group, name, v) \
853 v = g_key_file_get_double (kf, group, name, &err); \
856 g_propagate_error (error, err);\
860 GET_DOUBLE (key_file, group_name, "Width", width);
861 GET_DOUBLE (key_file, group_name, "Height", height);
865 name = g_key_file_get_string (key_file, group_name,
867 ppd_name = g_key_file_get_string (key_file, group_name,
869 display_name = g_key_file_get_string (key_file, group_name,
870 "DisplayName", NULL);
871 /* Fallback for old ~/.gtk-custom-paper entries */
873 display_name = g_strdup (name);
875 if (ppd_name != NULL)
876 paper_size = gtk_paper_size_new_from_ppd (ppd_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);
885 g_set_error_literal (error,
887 GTK_PRINT_ERROR_INVALID_FILE,
888 _("Not a valid page setup file"));
892 g_assert (paper_size != NULL);
897 g_free (display_name);
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
909 * This function adds the paper size from @size to @key_file.
914 gtk_paper_size_to_key_file (GtkPaperSize *size,
916 const gchar *group_name)
918 const char *name, *ppd_name, *display_name;
920 g_return_if_fail (size != NULL);
921 g_return_if_fail (key_file != NULL);
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);
927 if (ppd_name != NULL)
928 g_key_file_set_string (key_file, group_name,
929 "PPDName", ppd_name);
931 g_key_file_set_string (key_file, group_name,
935 g_key_file_set_string (key_file, group_name,
936 "DisplayName", display_name);
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));