1 /* GTK - The GTK+ 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, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
26 #if defined(HAVE__NL_PAPER_HEIGHT) && defined(HAVE__NL_PAPER_WIDTH)
30 #include "gtkpapersize.h"
31 #include "gtkprintutils.h"
32 #include "gtkprintoperation.h" /* for GtkPrintError */
36 #include "paper_names_offsets.c"
40 const PaperInfo *info;
42 /* If these are not set we fall back to info */
47 gdouble width, height; /* Stored in mm */
52 gtk_paper_size_get_type (void)
54 static GType our_type = 0;
57 our_type = g_boxed_type_register_static (I_("GtkPaperSize"),
58 (GBoxedCopyFunc)gtk_paper_size_copy,
59 (GBoxedFreeFunc)gtk_paper_size_free);
63 static const PaperInfo *
64 lookup_paper_info (const gchar *name)
67 int upper = G_N_ELEMENTS (standard_names_offsets) - 1;
73 mid = (lower + upper) / 2;
74 cmp = strcmp (name, paper_names + standard_names_offsets[mid].name);
80 return &standard_names_offsets[mid];
82 while (lower <= upper);
88 parse_media_size (const gchar *size,
94 double short_dim, long_dim;
98 short_dim = g_ascii_strtod (p, &e);
100 if (p == e || *e != 'x')
103 p = e + 1; /* Skip x */
105 long_dim = g_ascii_strtod (p, &e);
112 if (strcmp (p, "in") == 0)
114 short_dim = short_dim * MM_PER_INCH;
115 long_dim = long_dim * MM_PER_INCH;
117 else if (strcmp (p, "mm") != 0)
121 *width_mm = short_dim;
123 *height_mm = long_dim;
129 parse_full_media_size_name (const gchar *full_name,
135 const char *end_of_name;
138 media-size-self-describing-name =
139 ( class-in "_" size-name "_" short-dim "x" long-dim "in" ) |
140 ( class-mm "_" size-name "_" short-dim "x" long-dim "mm" )
141 class-in = "custom" | "na" | "asme" | "roc" | "oe"
142 class-mm = "custom" | "iso" | "jis" | "jpn" | "prc" | "om"
143 size-name = ( lowalpha | digit ) *( lowalpha | digit | "-" )
146 dim = integer-part [fraction-part] | "0" fraction-part
147 integer-part = non-zero-digit *digit
148 fraction-part = "." *digit non-zero-digit
149 lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
150 "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
151 "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
152 non-zero-digit = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
153 digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
156 p = strchr (full_name, '_');
170 if (!parse_media_size (p, width_mm, height_mm))
174 *name = g_strndup (full_name, end_of_name - full_name);
179 static GtkPaperSize *
180 gtk_paper_size_new_from_info (const PaperInfo *info)
184 size = g_slice_new0 (GtkPaperSize);
186 size->width = info->width;
187 size->height = info->height;
193 * gtk_paper_size_new:
194 * @name: a paper size name, or %NULL
196 * Creates a new #GtkPaperSize object by parsing a
197 * <ulink url="ftp://ftp.pwg.org/pub/pwg/candidates/cs-pwgmsn10-20020226-5101.1.pdf">PWG 5101.1-2002</ulink>
200 * If @name is %NULL, the default paper size is returned,
201 * see gtk_paper_size_get_default().
203 * Return value: a new #GtkPaperSize, use gtk_paper_size_free()
209 gtk_paper_size_new (const gchar *name)
213 double width, height;
214 const PaperInfo *info;
217 name = gtk_paper_size_get_default ();
219 if (parse_full_media_size_name (name, &short_name, &width, &height))
221 size = g_slice_new0 (GtkPaperSize);
224 size->height = height;
225 size->name = short_name;
226 size->display_name = g_strdup (short_name);
227 if (strncmp (short_name, "custom", 6) == 0)
228 size->is_custom = TRUE;
232 info = lookup_paper_info (name);
234 size = gtk_paper_size_new_from_info (info);
237 g_warning ("Unknown paper size %s\n", name);
238 size = g_slice_new0 (GtkPaperSize);
239 size->name = g_strdup (name);
240 size->display_name = g_strdup (name);
241 /* Default to A4 size */
251 * gtk_paper_size_new_from_ppd:
252 * @ppd_name: a PPD paper name
253 * @ppd_display_name: the corresponding human-readable name
254 * @width: the paper width, in points
255 * @height: the paper height in points
257 * Creates a new #GtkPaperSize object by using
260 * If @ppd_name is not a recognized PPD paper name,
261 * @ppd_display_name, @width and @height are used to
262 * construct a custom #GtkPaperSize object.
264 * Return value: a new #GtkPaperSize, use gtk_paper_size_free()
270 gtk_paper_size_new_from_ppd (const gchar *ppd_name,
271 const gchar *ppd_display_name,
276 const char *lookup_ppd_name;
281 lookup_ppd_name = ppd_name;
284 /* Strip out Traverse suffix in matching. */
285 if (g_str_has_suffix (ppd_name, ".Transverse"))
287 lookup_ppd_name = freeme =
288 g_strndup (ppd_name, strlen (ppd_name) - strlen (".Transverse"));
291 for (i = 0; i < G_N_ELEMENTS(standard_names_offsets); i++)
293 if (standard_names_offsets[i].ppd_name != -1 &&
294 strcmp (paper_names + standard_names_offsets[i].ppd_name, lookup_ppd_name) == 0)
296 size = gtk_paper_size_new_from_info (&standard_names_offsets[i]);
301 for (i = 0; i < G_N_ELEMENTS(extra_ppd_names_offsets); i++)
303 if (strcmp (paper_names + extra_ppd_names_offsets[i].ppd_name, lookup_ppd_name) == 0)
305 size = gtk_paper_size_new (paper_names + extra_ppd_names_offsets[i].standard_name);
310 name = g_strconcat ("ppd_", ppd_name, NULL);
311 size = gtk_paper_size_new_custom (name, ppd_display_name, width, height, GTK_UNIT_POINTS);
316 if (size->info == NULL ||
317 size->info->ppd_name == -1 ||
318 strcmp (paper_names + size->info->ppd_name, ppd_name) != 0)
319 size->ppd_name = g_strdup (ppd_name);
327 * gtk_paper_size_new_custom:
328 * @name: the paper name
329 * @display_name: the human-readable name
330 * @width: the paper width, in units of @unit
331 * @height: the paper height, in units of @unit
332 * @unit: the unit for @width and @height
334 * Creates a new #GtkPaperSize object with the
337 * Return value: a new #GtkPaperSize object, use gtk_paper_size_free()
343 gtk_paper_size_new_custom (const gchar *name,
344 const gchar *display_name,
350 g_return_val_if_fail (name != NULL, NULL);
351 g_return_val_if_fail (unit != GTK_UNIT_PIXEL, NULL);
353 size = g_slice_new0 (GtkPaperSize);
355 size->name = g_strdup (name);
356 size->display_name = g_strdup (display_name);
357 size->is_custom = TRUE;
359 size->width = _gtk_print_convert_to_mm (width, unit);
360 size->height = _gtk_print_convert_to_mm (height, unit);
366 * gtk_paper_size_copy:
367 * @other: a #GtkPaperSize
369 * Copies an existing #GtkPaperSize.
371 * Return value: a copy of @other
376 gtk_paper_size_copy (GtkPaperSize *other)
380 size = g_slice_new0 (GtkPaperSize);
382 size->info = other->info;
384 size->name = g_strdup (other->name);
385 if (other->display_name)
386 size->display_name = g_strdup (other->display_name);
388 size->ppd_name = g_strdup (other->ppd_name);
390 size->width = other->width;
391 size->height = other->height;
392 size->is_custom = other->is_custom;
398 * gtk_paper_size_free:
399 * @size: a #GtkPaperSize
401 * Free the given #GtkPaperSize object.
406 gtk_paper_size_free (GtkPaperSize *size)
409 g_free (size->display_name);
410 g_free (size->ppd_name);
412 g_slice_free (GtkPaperSize, size);
416 * gtk_paper_size_is_equal:
417 * @size1: a #GtkPaperSize object
418 * @size2: another #GtkPaperSize object
420 * Compares two #GtkPaperSize objects.
422 * Return value: %TRUE, if @size1 and @size2
423 * represent the same paper size
428 gtk_paper_size_is_equal (GtkPaperSize *size1,
431 if (size1->info != NULL && size2->info != NULL)
432 return size1->info == size2->info;
434 return strcmp (gtk_paper_size_get_name (size1),
435 gtk_paper_size_get_name (size2)) == 0;
438 GList * _gtk_load_custom_papers (void);
441 * gtk_paper_size_get_paper_sizes:
442 * @include_custom: whether to include custom paper sizes
443 * as defined in the page setup dialog
445 * Creates a list of known paper sizes.
447 * Return value: a newly allocated list of newly
448 * allocated #GtkPaperSize objects
453 gtk_paper_size_get_paper_sizes (gboolean include_custom)
457 #ifdef G_OS_UNIX /* _gtk_load_custom_papers() only on Unix so far */
460 GList *page_setups, *l;
462 page_setups = _gtk_load_custom_papers ();
463 for (l = page_setups; l != NULL; l = l->next)
465 GtkPageSetup *setup = (GtkPageSetup *) l->data;
468 size = gtk_page_setup_get_paper_size (setup);
469 list = g_list_prepend (list, gtk_paper_size_copy (size));
472 g_list_foreach (page_setups, (GFunc) g_object_unref, NULL);
473 g_list_free (page_setups);
476 for (i = 0; i < G_N_ELEMENTS (standard_names_offsets); ++i)
480 size = gtk_paper_size_new_from_info (&standard_names_offsets[i]);
481 list = g_list_prepend (list, size);
484 return g_list_reverse (list);
489 * gtk_paper_size_get_name:
490 * @size: a #GtkPaperSize object
492 * Gets the name of the #GtkPaperSize.
494 * Return value: the name of @size
498 G_CONST_RETURN gchar *
499 gtk_paper_size_get_name (GtkPaperSize *size)
503 g_assert (size->info != NULL);
504 return paper_names + size->info->name;
508 * gtk_paper_size_get_display_name:
509 * @size: a #GtkPaperSize object
511 * Gets the human-readable name of the #GtkPaperSize.
513 * Return value: the human-readable name of @size
517 G_CONST_RETURN gchar *
518 gtk_paper_size_get_display_name (GtkPaperSize *size)
520 const gchar *display_name;
522 if (size->display_name)
523 return size->display_name;
525 g_assert (size->info != NULL);
527 display_name = paper_names + size->info->display_name;
528 return g_strip_context (display_name, _(display_name));
532 * gtk_paper_size_get_ppd_name:
533 * @size: a #GtkPaperSize object
535 * Gets the PPD name of the #GtkPaperSize, which
538 * Return value: the PPD name of @size
542 G_CONST_RETURN gchar *
543 gtk_paper_size_get_ppd_name (GtkPaperSize *size)
546 return size->ppd_name;
548 return paper_names + size->info->ppd_name;
553 * gtk_paper_size_get_width:
554 * @size: a #GtkPaperSize object
555 * @unit: the unit for the return value
557 * Gets the paper width of the #GtkPaperSize, in
560 * Return value: the paper width
565 gtk_paper_size_get_width (GtkPaperSize *size,
568 return _gtk_print_convert_from_mm (size->width, unit);
572 * gtk_paper_size_get_height:
573 * @size: a #GtkPaperSize object
574 * @unit: the unit for the return value
576 * Gets the paper height of the #GtkPaperSize, in
579 * Return value: the paper height
584 gtk_paper_size_get_height (GtkPaperSize *size,
587 return _gtk_print_convert_from_mm (size->height, unit);
591 * gtk_paper_size_is_custom:
592 * @size: a #GtkPaperSize object
594 * Returns %TRUE if @size is not a standard paper size.
596 * Return value: whether @size is a custom paper size.
599 gtk_paper_size_is_custom (GtkPaperSize *size)
601 return size->is_custom;
605 * gtk_paper_size_set_size:
606 * @size: a custom #GtkPaperSize object
607 * @width: the new width in units of @unit
608 * @height: the new height in units of @unit
609 * @unit: the unit for @width and @height
611 * Changes the dimensions of a @size to @width x @height.
616 gtk_paper_size_set_size (GtkPaperSize *size,
621 g_return_if_fail (size != NULL);
622 g_return_if_fail (size->is_custom);
624 size->width = _gtk_print_convert_to_mm (width, unit);
625 size->height = _gtk_print_convert_to_mm (height, unit);
628 #define NL_PAPER_GET(x) \
629 ((union { char *string; unsigned int word; })nl_langinfo(x)).word
632 * gtk_paper_size_get_default:
634 * Returns the name of the default paper size, which
635 * depends on the current locale.
637 * Return value: the name of the default paper size. The string
638 * is owned by GTK+ and should not be modified.
642 G_CONST_RETURN gchar *
643 gtk_paper_size_get_default (void)
645 char *locale, *freeme = NULL;
646 const char *paper_size;
648 #if defined(HAVE__NL_PAPER_HEIGHT) && defined(HAVE__NL_PAPER_WIDTH)
650 int width = NL_PAPER_GET (_NL_PAPER_WIDTH);
651 int height = NL_PAPER_GET (_NL_PAPER_HEIGHT);
653 if (width == 210 && height == 297)
654 return GTK_PAPER_NAME_A4;
656 if (width == 216 && height == 279)
657 return GTK_PAPER_NAME_LETTER;
662 freeme = locale = g_win32_getlocale ();
663 #elif defined(LC_PAPER)
664 locale = setlocale(LC_PAPER, NULL);
666 locale = setlocale(LC_MESSAGES, NULL);
670 return GTK_PAPER_NAME_A4;
672 if (g_str_has_prefix (locale, "en_CA") ||
673 g_str_has_prefix (locale, "en_US") ||
674 g_str_has_prefix (locale, "es_PR") ||
675 g_str_has_prefix (locale, "es_US"))
676 paper_size = GTK_PAPER_NAME_LETTER;
678 paper_size = GTK_PAPER_NAME_A4;
684 /* These get the default margins used for the paper size. Its
685 * larger than most printers margins, so that it will be within
686 * the imageble area on any printer.
688 * I've taken the actual values used from the OSX page setup dialog.
689 * I'm not sure exactly where they got these values for, but might
690 * correspond to this (from ghostscript docs):
692 * All DeskJets have 0.5 inches (1.27cm) of unprintable bottom margin,
693 * due to the mechanical arrangement used to grab the paper. Side margins
694 * are approximately 0.25 inches (0.64cm) for U.S. letter paper, and 0.15
695 * inches (0.38cm) for A4.
699 * gtk_paper_size_get_default_top_margin:
700 * @size: a #GtkPaperSize object
701 * @unit: the unit for the return value
703 * Gets the default top margin for the #GtkPaperSize.
705 * Return value: the default top margin
710 gtk_paper_size_get_default_top_margin (GtkPaperSize *size,
715 margin = _gtk_print_convert_to_mm (0.25, GTK_UNIT_INCH);
716 return _gtk_print_convert_from_mm (margin, unit);
720 * gtk_paper_size_get_default_bottom_margin:
721 * @size: a #GtkPaperSize object
722 * @unit: the unit for the return value
724 * Gets the default bottom margin for the #GtkPaperSize.
726 * Return value: the default bottom margin
731 gtk_paper_size_get_default_bottom_margin (GtkPaperSize *size,
737 margin = _gtk_print_convert_to_mm (0.25, GTK_UNIT_INCH);
739 name = gtk_paper_size_get_name (size);
740 if (strcmp (name, "na_letter") == 0 ||
741 strcmp (name, "na_legal") == 0 ||
742 strcmp (name, "iso_a4") == 0)
743 margin = _gtk_print_convert_to_mm (0.56, GTK_UNIT_INCH);
745 return _gtk_print_convert_from_mm (margin, unit);
749 * gtk_paper_size_get_default_left_margin:
750 * @size: a #GtkPaperSize object
751 * @unit: the unit for the return value
753 * Gets the default left margin for the #GtkPaperSize.
755 * Return value: the default left margin
760 gtk_paper_size_get_default_left_margin (GtkPaperSize *size,
765 margin = _gtk_print_convert_to_mm (0.25, GTK_UNIT_INCH);
766 return _gtk_print_convert_from_mm (margin, unit);
770 * gtk_paper_size_get_default_right_margin:
771 * @size: a #GtkPaperSize object
772 * @unit: the unit for the return value
774 * Gets the default right margin for the #GtkPaperSize.
776 * Return value: the default right margin
781 gtk_paper_size_get_default_right_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_new_from_key_file:
792 * @key_file: the #GKeyFile to retrieve the papersize from
793 * @group_name: the name ofthe group in the key file to read,
794 * or %NULL to read the first group
795 * @error: return location for an error, or %NULL
797 * Reads a paper size from the group @group_name in the key file
800 * Returns: a new #GtkPaperSize object with the restored
801 * paper size, or %NULL if an error occurred.
806 gtk_paper_size_new_from_key_file (GKeyFile *key_file,
807 const gchar *group_name,
810 GtkPaperSize *paper_size = NULL;
811 char *name = NULL, *ppd_name = NULL, *display_name = NULL, *freeme = NULL;
812 gdouble width, height;
813 gboolean retval = TRUE;
816 g_return_val_if_fail (key_file != NULL, NULL);
819 group_name = freeme = g_key_file_get_start_group (key_file);
820 if (!group_name || !g_key_file_has_group (key_file, group_name))
822 g_set_error_literal (error,
824 GTK_PRINT_ERROR_INVALID_FILE,
825 _("Not a valid page setup file"));
830 #define GET_DOUBLE(kf, group, name, v) \
831 v = g_key_file_get_double (kf, group, name, &err); \
834 g_propagate_error (error, err);\
839 GET_DOUBLE (key_file, group_name, "Width", width);
840 GET_DOUBLE (key_file, group_name, "Height", height);
844 name = g_key_file_get_string (key_file, group_name,
846 ppd_name = g_key_file_get_string (key_file, group_name,
848 display_name = g_key_file_get_string (key_file, group_name,
849 "DisplayName", NULL);
850 /* Fallback for old ~/.gtk-custom-paper entries */
852 display_name = g_strdup (name);
854 if (ppd_name != NULL)
855 paper_size = gtk_paper_size_new_from_ppd (ppd_name, display_name,
857 else if (name != NULL)
858 paper_size = gtk_paper_size_new_custom (name, display_name,
859 width, height, GTK_UNIT_MM);
862 g_set_error_literal (error,
864 GTK_PRINT_ERROR_INVALID_FILE,
865 _("Not a valid page setup file"));
869 g_assert (paper_size != NULL);
874 g_free (display_name);
881 * gtk_paper_size_to_key_file:
882 * @size: a #GtkPaperSize
883 * @key_file: the #GKeyFile to save the paper size to
884 * @group_name: the group to add the settings to in @key_file
886 * This function adds the paper size from @size to @key_file.
891 gtk_paper_size_to_key_file (GtkPaperSize *size,
893 const gchar *group_name)
895 const char *name, *ppd_name, *display_name;
897 g_return_if_fail (size != NULL);
898 g_return_if_fail (key_file != NULL);
900 name = gtk_paper_size_get_name (size);
901 display_name = gtk_paper_size_get_display_name (size);
902 ppd_name = gtk_paper_size_get_ppd_name (size);
904 if (ppd_name != NULL)
905 g_key_file_set_string (key_file, group_name,
906 "PPDName", ppd_name);
908 g_key_file_set_string (key_file, group_name,
912 g_key_file_set_string (key_file, group_name,
913 "DisplayName", display_name);
915 g_key_file_set_double (key_file, group_name,
916 "Width", gtk_paper_size_get_width (size, GTK_UNIT_MM));
917 g_key_file_set_double (key_file, group_name,
918 "Height", gtk_paper_size_get_height (size, GTK_UNIT_MM));
922 #define __GTK_PAPER_SIZE_C__
923 #include "gtkaliasdef.c"